Разница между char ** p, char * p [], char p [] []
char *p = "some string"
создает указатель p, указывающий на блок, содержащий строку.
char p[] = "some string"
создает массив символов и с литералами в нем.
И первый из них является объявлением константы. Это же относится к двумерным массивам?
какая разница между
char **p,char *p[],char p[][].
Я немного читал об этом, что char ** p создает массив указателей, поэтому он имеет накладные расходы по сравнению с char p[][]
для хранения значений указателя.
первые два объявления создают константу arrays.i, не получая ошибки во время выполнения, когда я пытался изменить содержимое argv
в main(int argc,char **argv)
. Это потому, что они объявлены в прототипе функции?
Ответы
Ответ 1
Нормальные объявления (не функциональные параметры)
char **p;
объявляет указатель на указатель на char
. Он резервирует место для указателя. Он не оставляет места для указательных указателей или любого char
.
char *p[N];
объявляет массив из N указателей на char
. Он резервирует пространство для N указателей. Он не оставляет места для любого char
. N
должен быть указан явно или в определении с инициализаторами неявно, позволяя компилятору подсчитать инициализаторы.
char p[M][N];
объявляет массив массивов M из N char
. Он резервирует пространство для M • N char
. Нет никаких указателей. M
и N
должны быть указаны явно или, в определении с инициализаторами, неявно, позволяя компилятору подсчитать инициализаторы.
Объявления в функциональных параметрах
char **p
объявляет указатель на указатель на char
. Когда функция вызывается, для этого указателя предоставляется пространство (обычно в стеке или в регистре процессора). Для указателей с указателем или любого char
не зарезервировано места.
char *p[N]
настраивается как char **p
, так что это то же самое, что и выше. N
игнорируется и может отсутствовать.
char p[M][N]
настраивается как char (*p)[N]
, поэтому он является указателем на массив из N char
. M
игнорируется и может отсутствовать. N
. Когда функция вызывается, для указателя предоставляется пространство (обычно в стеке или в регистре процессора). Для массива N char
не зарезервировано места.
ARGV
argv
создается специальным программным обеспечением, которое вызывает main
. Он заполнен данными, которые программное обеспечение получает из "среды". Вам разрешено изменять данные char
.
В вашем определении char *p = "some string";
вам не разрешено изменять данные, на которые указывает p
, потому что в стандарте C указано, что символы в строковом литерале не могут быть изменены. (Технически, он говорит, что он не определяет поведение, если вы пытаетесь.) В этом определении p
не является массивом; это указатель на первый char
в массиве, а те char
находятся внутри строкового литерала, и вам не разрешается изменять содержимое строкового литерала.
В вашем определении char p[] = "some string";
вы можете изменить содержимое p
. Они не являются строковым литералом. В этом случае строковый литерал фактически не существует во время выполнения; это только то, что используется для указания того, как инициализируется массив p
. После инициализации p
вы можете изменить его.
Настройка данных для argv
настроена таким образом, чтобы вы могли ее модифицировать (поскольку это указывает стандарт C).
Ответ 2
Некоторые описания отличий выглядят следующим образом:
я. char **p;
p
- двойной указатель типа char
Декларация:
char a = 'g';
char *b = &a;
char **p = &b;
p b a
+------+ +------+ +------+
| | | | | |
|0x2000|------------>|0x1000|------------>| g |
| | | | | |
+------+ +------+ +------+
0x3000 0x2000 0x1000
Figure 1: Typical memory layout assumption
В приведенном выше объявлении a
есть тип char
, содержащий символ g
. Указатель b
содержит адрес существующей символьной переменной a
. Теперь b
- адрес 0x1000
, а *b
- символ g
. Наконец, адрес b
присваивается p
, поэтому a
является символьной переменной, b
является указателем, а p
- указателем на указатель. Из чего следует a
содержит значение, b
содержит адрес и p
содержит адрес адреса, как показано ниже на диаграмме.
Здесь sizeof(p) = sizeof(char *)
в соответствующей системе;
II. char *p[M];
p
- это массив строк
Декларация:
char *p[] = {"Monday", "Tuesday", "Wednesday"};
p
+------+
| p[0] | +----------+
0 | 0x100|------>| Monday\0 |
| | +----------+
|------| 0x100
| p[1] | +-----------+
1 | 0x200|------>| Tuesday\0 |
| | +-----------+
|------| 0x200
| p[2] | +-------------+
2 | 0x300|------>| Wednesday\0 |
| | +-------------+
+------+ 0x300
Figure 2: Typical memory layout assumption
В этом объявлении p
находится массив из 3 указателей типа char
. Implies array p
может содержать 3 строки. Каждая строка (Monday, Tuesday & Wednesday)
находится там, где в памяти (0x100, 0x200 & 0x300)
, адреса находятся в массиве p
как (p[0], p[1] & p[2])
соответственно. Следовательно, это массив указателей.
Примечания: char *p[3];
1. p[0], p[1] & p[2] are addresses of strings of type `char *`.
2. p, p+1 & p+2 are address of address with type being `char **`.
3. Accessing elements is through, p[i][j] is char; p[i] is char *; & p is char **
Здесь sizeof(p) = Number of char array * sizeof(char *)
III. char p[M][N];
p
- это массив строк фиксированной длины с размерами как M x N
Декларация:
char p[][10] = {Monday, Tuesday, Wednesday};
p 0x1 2 3 4 5 6 7 8 9 10
+-------------------------+
0 | M o n d a y \0 \0 \0 \0|
1 | T u e s d a y \0 \0 \0|
2 | W e d n e s d a y \0|
+-------------------------+
Figure 3: Typical memory layout assumption
В этом случае массив p
содержит 3 строки, каждая из которых содержит 10 символов. Создайте макет памяти, который мы можем сказать p
- это двумерный массив символов с размером MxN
, который 3x10
в нашем примере. Это полезно для представления строк равной длины, поскольку существует вероятность потери памяти, когда строки содержат менее 10 символов по сравнению с объявлением char *p[]
, который не имеет потери памяти, поскольку длина строки не указана, и она полезна для представления строк неравная длина.
Доступ к элементам аналогичен приведенному выше случаю, p[M]
- это строка M'th, а p [M] [N] - N-й символ строки M'th.
Здесь sizeof(p) = (M rows * N columns) * sizeof(char)
двумерного массива;
Ответ 3
-
a
in char* a
- указатель на массив символов, a
может быть изменен.
-
b
in char b[]
- это массив символов. b
не может быть изменен.
Они являются совместимыми - b
может автоматически распадаться на a
в назначениях и выражениях, но не наоборот.
Когда вы используете char** p
, char* p[]
и char p[][]
, это очень похожая ситуация, просто больше уровней косвенности.