Cuando se aplica ‘sizeof’ en una cadena, ¿por qué devuelve su tamaño (como strlen)?

Si tengo una cadena:

char s1[]="hello, how are you?"; printf("%d\n",sizeof(s1)); 

imprime el número exacto de caracteres correctos, 20. Pero si tengo una cadena inicializada por un puntero:

 char *s2; s2=(char*)malloc(sizeof(char)); strcpy(s2,s1); printf("%d\n",sizeof(s2)); 

imprime el tamaño de un puntero, que depende de la máquina (en la mía, 8). Entonces, ¿por qué son 8 bytes para s2 y 20 bytes para s1, ya que son la misma cadena?

No son la misma cadena, ni siquiera el mismo tipo. char s2[] es una matriz , tiene el tamaño de la sum del tamaño de sus elementos. char *s2 es un puntero , tiene el tamaño de un puntero.

sizeof() es (en C89) un operador en tiempo de comstackción que debe conocer el tamaño de su argumento en el momento de la comstackción. Dado que un puntero puede venir de cualquier parte, sizeof() no puede saber el tamaño de la memoria asignada, pero a una matriz siempre se le asigna un tamaño en el momento de la comstackción (excepto los VLA de C99), y sizeof() puede devolver el tamaño de esa memoria

char s2[] es una matriz asignada estáticamente, está todo en la stack, y el operador sizeof tiene una versión sobrecargada que puede medir el tamaño de una matriz asignada estáticamente, como comentó delnan.

char* s2 es un puntero y la cadena asignada (con malloc ) está en el montón.

Recuerda que las matrices no son punteros; en un caso, obtienes el tamaño de una matriz y en el otro el tamaño del puntero.

El operador sizeof aplicado a una cadena produce el número de caracteres de la cadena, incluido el carácter nulo final.

En el segundo caso, no está calculando el tamaño de una cadena, sino el tamaño de un puntero a una cadena, por lo que produce el tamaño del tipo de puntero.

 char *s2; s2=(char*)malloc(sizeof(char)); strcpy(s2,s1); 

Este código es incorrecto; está asignando espacio para un solo personaje. Necesitas asignar espacio para toda la cadena:

 char *s2; s2 = malloc(sizeof s1); strcpy(s2, s1); 

Finalmente, con respecto a la función strlen (como lo mencionó): la longitud de una cadena no es el mismo valor que el tamaño de una cadena. La longitud de una cadena es el número de caracteres que preceden al final, terminando el carácter nulo, mientras que el tamaño de una cadena es el número de caracteres de la cadena, incluido el carácter nulo.

sizeof devuelve el tamaño del tipo de datos que se pasa. Cuando se pasa en char[20] ese tipo de datos ocupa 20 bytes, pero cuando se pasa en char* que toma una palabra de máquina.

Sin tener en cuenta el hecho de que no asignó suficiente memoria en el segundo caso (debería haber sido malloc(+1) ), los dos s2 no son lo mismo.

En el primer caso, tienes una matriz ; está utilizando la syntax especial de inicialización de cadena que da como resultado una matriz del tamaño correcto que ya se ha inicializado en esa cadena. sizeof en una matriz resulta correctamente en su tamaño (en unidades de char ).

En el segundo caso, tiene un puntero , que no sabe nada acerca de qué tan grande es lo que está señalando. sizeof en un puntero devuelve el tamaño del puntero, que, en máquinas de 32 bits, es de 4 bytes = 32 bits, porque 32 bits son todo el espacio necesario para almacenar un puntero a cada ubicación de memoria posible en un espacio de direcciones de 32 bits.

Esto es por definición. Cuando el operador sizeof se aplica a los arreglos, el comstackdor lo reemplazará con la longitud del arreglo (en la etapa de comstackción). Cuando se aplica a un puntero, el comstackdor lo reemplaza con el tamaño del puntero.