2010-12-07 20 views
5

Duplicar posible:
What is the difference between char s[] and char *s in C?
Difference between char *str = “…” and char str[N] = “…”?Pregunta sobre punteros y cadenas en C

que tiene un código que me ha tenido perplejo.

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char *argv[]) 
{ 
    char* string1 = "this is a test"; 
    char string2[] = "this is a test"; 
    printf("%i, %i\n", sizeof(string1), sizeof(string2)); 
    system("PAUSE"); 
    return 0; 
} 

Cuando se emite el tamaño de cadena1, imprime 4, que es de esperarse debido a que el tamaño de un puntero es de 4 bytes. Pero cuando imprime string2, emite 15. Pensé que una matriz era un puntero, por lo que el tamaño de string2 debería ser igual que string1 ¿no? Entonces, ¿por qué imprime dos tamaños diferentes para el mismo tipo de datos (puntero)?

+4

Además, 'sizeof' devuelve' size_t', que, a diferencia del 'int' esperado por'% i', no está firmado. El formato correcto para las variables 'size_t' es'% zu'. –

+0

¡La matriz no es un pinter! ¡Recuerda eso! – Hauleth

Respuesta

5

Las matrices y los punteros son animales completamente diferentes. En la mayoría de los contextos, una expresión que designa una matriz se trata como un puntero.

En primer lugar, un poco de lenguaje estándar (n1256):

6.3.2.1 Lvalues, matrices y designadores de función
...
3, excepto cuando es el operando del operador sizeof o la unario & operador, o es una cadena literal utilizado para inicializar una matriz, una expresión que tiene el tipo " matriz de tipo "se convierte en una expresión con tipo" puntero a tipo "que apunta al elemento inicial del objeto de matriz y no es un valor l. Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento no está definido.

La cadena literal "esta es una prueba" es una matriz de 15 elementos de char. En la declaración


    char *string1 = "this is a test"; 

string1 se declara como un puntero a char. Según el idioma anterior, el tipo de la expresión "esto es una prueba" se convierte de char [15] a char *, y el valor del puntero resultante se asigna a string1.


En la declaración


    char string2[] = "this is a test"; 


sucede algo diferente. Más lenguaje estándar:

6.7.8 Inicialización
...
14 Matriz de tipo carácter puede ser inicializado por una cadena de caracteres literales, opcionalmente entre llaves. Los caracteres sucesivos del literal de cadena de caracteres (incluido el carácter nulo de terminación si hay espacio o si el conjunto es de tamaño desconocido) inicializan los elementos del conjunto.
...
22 Si se inicializa una matriz de tamaño desconocido, su tamaño está determinado por el elemento indexado más grande con un inicializador explícito. Al final de su lista de inicializadores, la matriz ya no tiene un tipo incompleto.

En este caso, string2 se declara como una matriz de char, su tamaño se calcula a partir de la longitud del inicializador, y los contenido de la cadena literal se copian a la matriz.

Aquí está un mapa de memoria hipotética para ilustrar lo que está sucediendo:

 
Item   Address  0x00 0x01 0x02 0x03 
----   -------  ---- ---- ---- ---- 
no name  0x080't' 'h' 'i' 's' 
       0x080' ' 'i' 's' ' ' 
       0x080'a' ' ' 't' 'e' 
       0x0800123C 's' 't' 0 
       ... 
string1  0x12340000 0x08 0x00 0x12 0x30 
string2  0x12340004 't' 'h' 'i' 's' 
       0x12340008 ' ' 'i' 's' ' ' 
       0x1234000C 'a' ' ' 't' 'e' 
       0x1234000F 's' 't' 0 

literales de cadena tienen medida estática; es decir, la memoria para ellos se reserva al inicio del programa y se mantiene hasta que finaliza el programa. Intentar modificar el contenido de un literal de cadena invoca un comportamiento indefinido; la plataforma subyacente puede o no permitirlo, y la norma no impone restricciones al compilador. Lo mejor es actuar como si los literales fueran siempre no escribibles.

En mi mapa de memoria de arriba, la dirección del literal de cadena se establece un poco desde las direcciones de string1 y string2 para ilustrar esto.

De todos modos, puede ver que string1, que tiene un tipo de puntero, contiene la dirección de la cadena literal. string2, al ser un tipo de matriz, contiene una copia del contenido de la cadena literal.

Como se conoce el tamaño de string2 en tiempo de compilación, sizeof devuelve el tamaño (número de bytes) en la matriz.

El especificador de conversión %i no es el correcto para las expresiones del tipo size_t. Si está trabajando en C99, use %zu. En C89, utilizaría %lu y echó la expresión de unsigned long:


C89: printf("%lu, %lu\n", (unsigned long) sizeof string1, (unsigned long) sizeof string2); 
C99: printf("%zu, %zu\n", sizeof string1, sizeof string2); 

Tenga en cuenta que es un operador sizeof, no es una llamada a la función; cuando el operando es una expresión que denota un objeto , los paréntesis no son necesarios (aunque no duelen).

+0

¡Guau! ¡Gracias por la respuesta detallada! Esto realmente me ayudó. –

13

Las matrices no son punteros. Los nombres de matriz decay en punteros al primer elemento de la matriz en ciertas situaciones: cuando lo pasa a una función, cuando lo asigna a un puntero, etc. Pero las matrices son matrices, existen en la pila, tienen compilación -tipos de tiempo que se pueden determinar con sizeof, y todas esas otras cosas buenas.

4

string1 es un puntero, pero string2 es una matriz.

La segunda línea es algo así como int a[] = { 1, 2, 3}; que define a como una matriz de longitud 3 (a través del inicializador).

El tamaño de string2 es 15 porque el inicializador tiene terminación nula (por lo que 15 es la longitud de la cadena + 1).

2

El compilador sabe que test2 es una matriz, por lo que imprime el número de bytes asignados (14 letras más terminador nulo). Recuerde que sizeof es una función de compilación, por lo que puede conocer el tamaño de una variable de pila.

4

Una matriz de tamaño desconocido es equivalente a un puntero para el tamaño de los propósitos. Una matriz de tamaño estático cuenta como su propio tipo para el tamaño de los propósitos, y sizeof informa el tamaño del almacenamiento requerido para la matriz. Aunque string2 se asigna sin un tamaño explícito, el compilador de C lo trata mágicamente debido a la inicialización directa por una cadena entrecomillada y lo convierte en una matriz con tamaño estático. (Dado que la memoria no está asignada de ninguna otra manera, no hay nada más que pueda hacer, después de todo.) ¡Las matrices de tamaño estático son tipos diferentes de punteros (o matrices dinámicas!) Para el comportamiento sizeof, porque así es como C es.

This parece ser una referencia decente sobre los comportamientos de sizeof.

1

matriz no es puntero. El puntero es una variable que apunta a una ubicación de memoria mientras que la matriz es el punto de inicio de la memoria secuencial asignada

1

Su porque

  1. cadena1 mantiene puntero, donde puntero tiene caracteres contiguos & su inmutable.
  2. string2 es la ubicación donde se sientan sus personajes.

básicamente compilador C iterprets estos 2 de forma diferente. bellamente explicado aquí http://c-faq.com/aryptr/aryptr2.html.