2011-10-02 9 views
21

En C por qué es legal hacerlopuntero en C

char * str = "Hello"; 

pero ilegal hacer

int * arr = {0,1,2,3}; 
+0

Causa, que no es una matriz. (La norma no especifica que funcione). –

+0

Porque normalmente esperamos 'printf (" ¡Hola, mundo! \ N ");' funcione sin ninguna variable, pero nadie quiere usar 'memcpy (arr, {0 , 1,2,3}, sizeof arr); ' –

+2

@ChrisLutz: ¿Quién dice que nadie quiere? No lo usamos porque el idioma no lo admite; la pregunta (razonable en mi humilde opinión) es * por qué *. –

Respuesta

12

supongo que así es como inicializadores trabajan en C. Sin embargo, se puede hacer:

int *v = (int[]){1, 2, 3}; /* C99. */ 
+2

Puede hacer la misma sintaxis para cadenas para obtener una cadena modificable "literal". –

3

Debido a que no hay punto de declarar e inicializar un puntero a un array int, cuando el nombre gama se puede utilizar como un puntero al primer elemento. Después

int arr[] = { 0, 1, 2, 3 }; 

puede utilizar como un arrint * en casi todos los contextos (con la excepción de que el operando a sizeof).

+6

La otra excepción es como el operando del operador de dirección '&' unario; '& arr' proporciona la dirección de la matriz, no de su primer elemento (la misma ubicación de memoria, tipo diferente). –

8

cuanto a C89:

"A string", cuando se utiliza fuera char matriz de inicialización, es una cadena literal; el estándar dice que cuando usas un literal de cadena es como si creaste una matriz global char inicializada a ese valor y escribes su nombre en lugar del literal (también existe la restricción adicional de que cualquier intento de modificar una cadena literal da como resultado un comportamiento indefinido) . En su código está inicializando un char * con un literal de cadena, que se desintegra a un puntero char y todo funciona bien.

Sin embargo, si utiliza una cadena literal para inicializar una matriz char, varias reglas mágicas entran en acción, por lo que ya no es "como una matriz ... etc" (que no funcionaría en la inicialización de la matriz), pero es solo una buena manera de decirle al compilador cómo debe inicializarse la matriz.

La forma de inicializar matrices {1, 2, 3} mantiene esta semántica: es solo para la inicialización de la matriz, no es una "matriz literal".

5

En el caso de:

char * str = "Hello"; 

"Hello" es una cadena literal. Se carga en la memoria (pero a menudo solo lectura) cuando se ejecuta el programa, y ​​tiene una dirección de memoria que se puede asignar a un puntero como char *str. Sin embargo, los literales de cadena como este son una excepción.

Con:

int * arr = {0,1,2,3}; 

..you're efectivamente tratando de apuntar a una matriz que no ha sido puesto en cualquier lugar, en particular en la memoria. arr es un puntero, no una matriz; contiene una dirección de memoria, pero no tiene almacenamiento para los datos de la matriz. Si usa int arr[] en lugar de int *arr, entonces funciona, porque una matriz como esa está asociada con el almacenamiento de su contenido. Aunque la matriz se desintegra a un puntero a sus datos en muchos contextos, no es lo mismo.

Incluso con literales de cadena, char *str = "Hello"; y char str[] = "Hello"; hacen cosas diferentes. El primero establece el puntero str para apuntar a la cadena literal, y el segundo inicializa la matriz str con los valores de "Hello".La matriz tiene almacenamiento para sus datos asociados a ella, pero el puntero simplemente apunta a los datos que ya están cargados en la memoria en algún lugar.

2

... o puede abusar de los literales de cadena y almacenar los números como una cadena literal, lo que para una pequeña máquina endian se verá de la siguiente manera:

int * arr = (int *)"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0"; 
+0

Una pequeña máquina endian, donde 'sizeof int' es 4, para ser precisos. – Jens