¿Qué significa el ‘nombre de la matriz’ en el caso de la matriz de punteros de char?

En mi código:

char *str[] = {"forgs", "do", "not", "die"}; printf("%d %d", sizeof(str), sizeof(str[0])); 

Obtengo la salida como 12 2 , así que mis dudas son:

  1. ¿Por qué hay una diferencia?
  2. Tanto str como str[0] son punteros de char, ¿verdad?

En la mayoría de los casos, un nombre de matriz decaerá al valor de la dirección de su primer elemento, y con el tipo que es lo mismo que un puntero al tipo de elemento. Por lo tanto, esperaría que un str desnudo tenga un valor igual a &str[0] con un puntero tipo a puntero a char .

Sin embargo, este no es el caso para sizeof . En este caso, el nombre de la matriz mantiene su tipo para sizeof , que sería una matriz de 4 punteros a char .

El tipo de devolución de sizeof es un size_t . Si tiene un comstackdor C99, puede usar %zu en la cadena de formato para imprimir el valor devuelto por sizeof .

A través de la pregunta ya está respondida y aceptada, pero estoy agregando más descripción (que también responde a la pregunta original) que creo que será útil para los nuevos usuarios. (como busqué, esta descripción no se explica en ningún otro lugar (al menos en stackoverflow) por lo tanto, ahora estoy agregando.

Primera lectura: operador de sizeof

6.5.3.4 El operador de tamaño, 1125:
Cuando aplica el operador sizeof a un tipo de matriz, el resultado es la cantidad total de bytes en la matriz.

De acuerdo con esto, cuando sizeof se aplica al nombre de un identificador de matriz estática ( no asignado a través de malloc), el resultado es el tamaño en bytes de toda la matriz en lugar de solo la dirección. Esta es una de las pocas excepciones a la regla de que el nombre de una matriz se convierte / decae a un puntero al primer elemento de la matriz , y es posible simplemente porque el tamaño real de la matriz es fijo y conocido en tiempo de comstackción, cuando sizeof operador sizeof evalúa.

Para entenderlo mejor, considere el siguiente código:

 #include int main(){ char a1[6], // One dimensional a2[7][6], // Two dimensional a3[5][7][6]; // Three dimensional printf(" sizeof(a1) : %lu \n", sizeof(a1)); printf(" sizeof(a2) : %lu \n", sizeof(a2)); printf(" sizeof(a3) : %lu \n", sizeof(a3)); printf(" Char : %lu \n", sizeof(char)); printf(" Char[6] : %lu \n", sizeof(char[6])); printf(" Char[5][7] : %lu \n", sizeof(char[7][6])); printf(" Char[5][7][6]: %lu \n", sizeof(char[5][7][6])); return 1; } 

Su salida:

  sizeof(a1) : 6 sizeof(a2) : 42 sizeof(a3) : 210 Char : 1 Char[5] : 6 Char[5][7] : 42 Char[5][7][6]: 210 

Verifique arriba, trabajando en @ codepad , observe que el tamaño de char es de un byte, si reemplaza char con int en el progtwig anterior, entonces cada salida se multiplicará por sizeof(int) en su máquina.

Diferencia entre char* str[] y char str[][] y cómo se almacenan ambos en la memoria

Declaración-1: char *str[] = {"forgs", "do", "not", "die"};

En esta statement str[] es una matriz de punteros a char. Cada índice str[i] apunta al primer carácter de las cadenas en {"forgs", "do", "not", "die"}; .
Lógicamente str debe organizarse en la memoria de la siguiente manera:

 Array Variable: Constant Strings: --------------- ----------------- str: 201 202 203 204 205 206 +--------+ +-----+-----+-----+-----+-----+-----+ 343 | |= *(str + 0) | 'f' | 'o' | 'r' | 'g' | 's' | '\0'| | str[0] |-------| +-----+-----+-----+-----+-----+-----+ | 201 | +-----------▲ +--------+ 502 503 504 | | +-----+-----+-----+ 347 | str[1] |= *(str + 1) | 'd' | 'o' | '\0'| | 502 |-------| +-----+-----+-----+ +--------+ +-----------▲ | | 43 44 45 46 351 | 43 | +-----+-----+-----+-----+ | str[2] |= *(str + 2) | 'n' | 'o' | 't' | '\0'| | |-------| +-----+-----+-----+-----+ +--------+ +-----------▲ 355 | | | 9002 | 9002 9003 9004 9005 | str[3] | +-----+-----+-----+-----+ | |= *(str + 3) | 'd' | 'i' | 'e' | '\0'| +--------+ | +-----+-----+-----+-----+ +-----------▲ Diagram: shows that str[i] Points to first char of each constant string literal. Memory address values are assumption. 

Nota: str[] se almacena en las asignaciones de memoria continua y cada cadena se almacena en la memoria en una dirección aleatoria (no en el espacio continuo).

[RESPONDER]

De acuerdo con el código de Codepad siguiente:

 int main(int argc, char **argv){ char *str[] = {"forgs", "do", "not", "die"}; printf("sizeof(str): %lu, sizeof(str[0]): %lu\n", sizeof(str), sizeof(str[0]) ); return 0; } 

Salida:

 sizeof(str): 16, sizeof(str[0]): 4 
  • En este código, str es una matriz para 4 direcciones de caracteres, donde cada char* tiene un tamaño de 4 bytes, por lo que, de acuerdo con la cita anterior, el tamaño total de la matriz es 4 * sizeof(char*) = 16 bytes.

  • El tipo de datos de str es char*[4] .

  • str[0] no es más que puntero a char, por lo que sus cuatro bytes. El tipo de fecha de str[i] es char* .

(nota: en alguna dirección del sistema puede ser de 2 bytes o 8 bytes)

En cuanto a la producción, también se debe leer el comentario de glglgl a la pregunta:

En cualquier architecture que seas, el primer valor debe ser 4 veces el segundo. En una máquina de 32 bits, debería obtener 16 4, en una de 64 bits, una 32 8. En una muy antigua o en un sistema integrado, incluso podría obtener 8 2, pero nunca 12 2, ya que la matriz contiene 4 elementos del mismo tamaño

Puntos adicionales:

  • Como cada str[i] apunta a un char* (y string) es variable, a str[i] se le puede asignar una nueva dirección de cadena, por ejemplo: str[i] = "yournewname"; es válido para i = 0 to < 4 .

Un punto más importante para notar:

  • En nuestro ejemplo anterior, str[i] apunta a un literal de cadena constante que no se puede modificar; por lo tanto str[i][j] = 'A' no es válido (no podemos escribir en la memoria de solo lectura) y hacer esto será un error de tiempo de ejecución.
    Pero supongamos que si str[i] apunta a una matriz de caracteres simple, entonces str[i][j] = 'A' puede ser una expresión válida.
    Considera seguir el código:

      char a[] = "Hello"; // a[] is simple array char *str[] = {"forgs", "do", "not", "die"}; //str[0][4] = 'A'; // is error because writing on read only memory str[0] = a; str[0][5] = 'A'; // is perfectly valid because str[0] // points to an array (that is not constant) 

Compruebe aquí el código de trabajo: Codepad

Declaración-2: char str[][6] = {"forgs", "do", "not", "die"}; :

Aquí str es una matriz bidimensional de caracteres (donde cada fila es igual en tamaño) de tamaño 4 * 6. (recuerde que debe dar el valor de la columna en la statement de str explícitamente, pero la fila es 4 porque el número de cadenas es 4)
En la memoria str[][] será algo así como debajo en el diagtwig:

  str +---201---202---203---204---205---206--+ 201 | +-----+-----+-----+-----+-----+-----+| str[0] = *(str + 0)--►| 'f' | 'o' | 'r' | 'g' | 's' | '\0'|| 207 | +-----+-----+-----+-----+-----+-----+| str[1] = *(str + 1)--►| 'd' | 'o' | '\0'| '\0'| '\0'| '\0'|| 213 | +-----+-----+-----+-----+-----+-----+| str[2] = *(str + 2)--►| 'n' | 'o' | 't' | '\0'| '\0'| '\0'|| 219 | +-----+-----+-----+-----+-----+-----+| str[3] = *(str + 3)--►| 'd' | 'i' | 'e' | '\0'| '\0'| '\0'|| | +-----+-----+-----+-----+-----+-----+| +--------------------------------------+ In Diagram: str[i] = *(str + i) = points to a complete i-row of size = 6 chars. str[i] is an array of 6 chars. 

Esta disposición de la matriz 2D en la memoria se denomina Fila principal : una matriz multidimensional en la memoria lineal está organizada de manera que las filas se almacenan una después de la otra. Es el enfoque utilizado por el lenguaje de progtwigción C.

Observe las diferencias en ambos diagtwigs.

  • En el segundo caso, se asigna una matriz de caracteres bidimensional completa en la memoria continua.
  • Para cualquier i = 0 to 2 , el valor de str[i] y str[i + 1] es diferente en 6 bytes (esto es igual a la longitud de una fila).
  • La doble línea de límite en este diagtwig significa que str representa 6 * 4 = 24 caracteres completos.

Ahora considere el código similar que publicó en su pregunta para una matriz de caracteres bidimensionales, verifique en Codepad :

 int main(int argc, char **argv){ char str[][6] = {"forgs", "do", "not", "die"}; printf("sizeof(str): %lu, sizeof(str[0]): %lu\n", sizeof(str), sizeof(str[0]) ); return 0; } 

Salida:

 sizeof(str): 24, sizeof(str[0]): 6 

De acuerdo con el tamaño del tratamiento del operador con matriz, en la aplicación de 2-d tamaño de matriz debería devolver el tamaño completo de la matriz que es de 24 bytes.

  • Como sabemos, el operador sizeof devuelve el tamaño de toda la matriz al aplicar el nombre de la matriz. Entonces, para sizeof(str) , devuelve = 24, que es el tamaño de una matriz 2D completa, consta de 24 caracteres (6 columnas * 4 filas).

  • En esta statement, el tipo de str es char[4][6] .

  • Un punto más interesante es que str[i] representa un conjunto de chats y su tipo es char[6] . Y sizeof(str[0]) es el tamaño completo de la matriz = 6 (longitud de fila).

Puntos adicionales:

  • En la segunda statement str[i][j] no es constante, y su contenido puede ser cambios, por ejemplo, str[i][j] = 'A' es una operación válida.

  • str[i] es el nombre de la matriz char del tipo char[6] es una constante y la asignación a str[i] por ejemplo str[i] = "newstring" es una operación ilegal (infectarlo será un error de tiempo de comstackción).

Una diferencia más importante entre dos declaraciones:

En Declaration-1 : char *str[] = {"forgs", "do", "not", "die"}; , el tipo de &str es char*(*)[4] , su dirección de una matriz de punteros char.

En Declaration-2 : char str[][6] = {"forgs", "do", "not", "die"}; , el tipo de &str es char(*)[4][6] , su dirección de 2-D char array de 4 filas y 6 cols.

Si uno quiere leer una descripción similar para una matriz 1-D: ¿Qué devuelve sizeof(&array) ?

Es 16 4 en mi computadora, y puedo explicar esto: str es una matriz de char* , así sizeof(str)==sizeof(char*)*4

Sin embargo, no sé por qué tienes 12 2 .

Los dos punteros son diferentes. str es una array of char pointers , en su ejemplo es a ( char*[4] ), y str[0] es un char pointer .

El primer tamaño devuelve el tamaño de los cuatro punteros que contiene, y el segundo devuelve el tamaño del char* .
En mis pruebas, los resultados son:

 sizeof(str[0]) = 4 // = sizeof(char*) sizeof(str) = 16 = sizeof(str[0]) + sizeof(str[1]) + sizeof(str[2]) + sizeof(str[3]) = 4 * sizeof(char*) = 4 * 4 = 16