2011-01-28 7 views
22

Siempre pensé que la declaración deC declaración de puntero doble carácter y la inicialización

char *c = "line"; 

fue el mismo que

char c[] = "line"; 

y así lo hice

char **choices = { "New Game", "Continue Game", "Exit" }; 

Lo que me da un puntero incompatibles tipo, donde

char *choices[] = { "New Game", "Continue Game", "Exit" }; 

no. ¿Alguna ayuda para entender esto?

+6

C arrays! = Punteros en C. – nmichaels

+2

En el ejemplo 1, c es un puntero a un char. En el ejemplo 2, c es una matriz de caracteres. En el Ejemplo 3, las opciones son un puntero a un puntero a A char (y se le asigna incorrectamente una matriz de caracteres). En el Ejemplo 4, las opciones son una matriz de punteros a caracteres (y se le asigna correctamente una matriz de caracteres) – oosterwal

+0

@oosterwal: para ** ex3 ** y ** ex4 ** dijiste "... asignó una matriz de caracteres", pero es correcto "... asignó una matriz de punteros a los caracteres". Para ** ex3 ** - hay [una posibilidad] (http://stackoverflow.com/questions/4832082/c-double-character-pointer-declaration-and-initialization/4832167#4832167) para asignar un _array de punteros a chars_ usando _compound literals_. –

Respuesta

12

Bueno, no son lo mismo. Simplemente es más fácil para la mayoría de las personas pensar que son iguales para que todos comiencen a pensar de esa manera hasta que encuentren un problema como el anterior :-)

Iba a escribir algo largo y sin aliento, pero luego figurado ... Alguien más debe haber hecho esto ya. Y tienen. Esta es una muy buena explicación:

http://www.lysator.liu.se/c/c-faq/c-2.html

La manera más fácil de pensar en ello es que cuando haces algo como:

 
    char *foo = "something"; 

Realmente estás haciendo algo como:

 
    char randomblob[] = "something"; 
    char *foo = randomblob; 

Ahora ... eso no es realmente una imagen precisa (aunque no soy un experto compilador). Al menos, te permite pensar sobre las cosas de una manera un poco más correcta.

tanto, de vuelta a su problema, si me entiendo las cosas bien (que nunca está garantizado), no puede hacer su ejemplo la línea # 3 en C. Tiene razón de que alguien podría escribir un compilador que lo haría haz lo correcto aquí, pero gcc no. El 4to ejemplo, sin embargo, hace lo "correcto" y le da "una matriz de indicadores que apuntan hacia una matriz de const ellos mismos".

vez me encontré con una página web que se traduciría un tipo C complejo en Inglés. Sin embargo, eso fue probablemente a principios de los 90, pero apuesto a que si buscas lo suficiente en Google obtendrás una descripción de la frase más precisa que la que acabo de actualizar.

+2

+1 para enlace a C Preguntas frecuentes. – zwol

+0

Muchas gracias por el enlace, siempre pensé que las matrices hacían lo mismo que los punteros. Creo que nunca leí demasiado sobre las matrices. Para mí siempre fue algo que apuntaba a la primera pequeña caja de memoria y fue de allí hasta que obtuvo un '\ 0' por lo que tener una declaración o la otra parecía lo mismo. Las otras respuestas también fueron buenas, pero tu enlace borró las cosas para mí. – vascop

+0

por este y otros errores como este C es un cuchillo afilado – Mandrake

3

Está bien, acaba de escribir

char **choices = (char *[]){ "New Game", "Continue Game", "Exit" };

Sin embargo, choices sólo se puede utilizar para hacer frente a lineal. Por ejemplo:

printf ("%s", &(*choices)[0]); salidas: New Game
printf ("%s", &(*choices)[1]); salidas: ew Game
printf ("%s", &(*choices)[9]); salidas: Continue Game

Así que no es una broma, es una inicialización válida. Solo otro tipo de uso.


También se puede encontrar un ejemplo muy cerca here, explicando literales compuestos noción.

+0

Estoy a favor de * literales compuestos *, pero esta respuesta es una broma o me falta completamente por qué harías tal cosa. – SiegeX

+0

Esta expresión se compila sin errores ni advertencias bajo GCC4.2. Esta pregunta se trata de compilar el problema, no el uso –

+1

@SiegeX: He actualizado mi respuesta con ejemplos de cómo se puede usar esto –

14
char *c = "line"; 

es no lo mismo que

char c[] = "line"; 

que es realmente lo mismo que

static char hidden_C0[] = "line"; 
char *c = hidden_C0; 

excepto que la variable hidden_C0 no es directamente accesible. Pero lo verás si eliminas el lenguaje ensamblador generado (generalmente tendrá un nombre que no sea un identificador de C válido, como .LC0). Y en su ejemplo gama de cuerdas-constantes, lo mismo está sucediendo:

char *choices[] = { "New Game", "Continue Game", "Exit" }; 

convierte

char hidden_C0[] = "New Game"; 
char hidden_C1[] = "Continue Game"; 
char hidden_C2[] = "Exit"; 

char *choices[] = { hidden_C0, hidden_C1, hidden_C2 }; 

Ahora bien, esta es una conducta caso especial que está disponible única de cadena constantes.No se puede escribir

int *numbers = { 1, 2, 3 }; 

debe escribir

int numbers[] = { 1, 2, 3 }; 

y por eso no se puede escribir

char **choices = { "a", "b", "c" }; 

tampoco.

(Su confusión es un caso especial de la idea errónea de que las matrices son "lo mismo que" punteros en C. Ellos no lo son. Las matrices son matrices. Las variables con tipos de matriz sufren tipo de descomposición a un tipo de puntero cuando son usado (en casi todos los contextos), pero no cuando están definidos.)

2

línea C estándar (proyecto n1256):

6.7.8 Inicialización
...
11 El inicializador para una escalar será una sola expresión , opcionalmente entre llaves . El valor inicial del objeto es el de la expresión (después de la conversión); se aplican las mismas restricciones de tipo y conversiones que para la asignación simple, tomando el tipo de escalar para ser la versión no calificada de su tipo declarado.
...
16 De lo contrario, el inicializador para un objeto que tenga agregado o tipo de unión será una lista de llaves incluidas de inicializadores para los elementos o miembros nombrados.

Énfasis añadido.

char ** es un tipo escalar, no un agregado, por lo que no es compatible con el inicializador {"New Game", "Continue Game", "Exit"}. Por el contrario, char *[] es un tipo de agregado (matriz).

Del mismo modo, no se puede escribir algo como

int *foo = {1, 2, 3}; 

porque int * no es un tipo de matriz.

Su comprensión de

char *c = "line"; 

y

char c[] = "line"; 

es ligeramente fuera; son no lo mismo. El primer formulario copia la dirección de la cadena literal al valor del puntero c. El segundo formulario copia el contenido de la expresión de matriz "line" en el almacenamiento intermedio designado por c.

+0

las personas solo pueden considerarse verdaderos desarrolladores C después de leer todo el estándar C – Mandrake

Cuestiones relacionadas