Разница между 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[][], это очень похожая ситуация, просто больше уровней косвенности.