2011-06-24 9 views
9

personas.¿Cuál es el significado de 'char (* p) [5];'?

Estoy tratando de comprender las diferencias entre estas tres declaraciones:

char p[5]; 
char *p[5]; 
char (*p)[5]; 

que estoy tratando de averiguar esto haciendo algunas pruebas, ya que cada guía de lectura declaraciones y cosas por el estilo no ha ayudado yo hasta ahora. Escribí este pequeño programa y no está funcionando (He probado otros tipos de uso de la tercera declaración y me he quedado sin opciones):

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

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p3[0], "char");             

     printf("p1 = %s\np2[0] = %s\np3[0] = %s\n", p1, p2[0], p3[0]);   

     return 0;                
} 

El primer y el segundo funciona bien, y no tengo Entendido lo que hacen. ¿Cuál es el significado de la tercera declaración y la forma correcta de usarla?

¡Gracias!

+0

Declaraciones de descodificación es mi parte menos favorita de C y C++. –

Respuesta

12

El tercero es un puntero a una matriz de 5 caracteres, mientras que el segundo es un array de 5 punteros a char.

imaginarlo así:

________   _____________________ 
|0x7777| -------> | H | e | l | l | o | 
|______|   |_0_|_1_|_2_|_3_|_4_| 
    p   ^
        | 
        0x7777 

mientras que el segundo se parece a lo siguiente:

"abc" "def" "ghi" "jkl" "mno" 
    ^ ^ ^ ^ ^
    |  |  |  |  | 
____________________________________ 
|0x9999|0x7777|0x3333|0x2222|0x6666| 
|___0__|___1__|___2__|___3__|___4__| 
        p 

Este es uno de los casos en que la comprensión de la diferencia entre apuntadores y arreglos es crucial. Una matriz es un objeto cuyo tamaño es el tamaño de cada uno de sus elementos multiplicado por el recuento, mientras que un puntero es simplemente una dirección. En el segundo caso, sizeof(p) dará 5 * the_size_of_a_pointer.

En el tercer caso, sizeof(p) rendirá the_size_of_a_pointer, que normalmente es 4 o 8, dependiendo de la máquina de destino.

+9

La [regla espiral en el sentido de las agujas del reloj] (http://c-faq.com/decl/spiral.anderson.html) es útil para saber cuándo estás jugando con 'C'. –

+0

Intenté usar p3 asignando 5 caracteres y apuntando a p3 y no funcionó. No funciona como dijiste ... ¿Te importaría publicar algún código de ejemplo o algo más claro? – jpmelos

+0

En el tercer caso, sizeof (p3) no está dando lo que usted dijo, está produciendo 8, que es el tamaño de un puntero en mi máquina. – jpmelos

4

Es un puntero a una matriz de caracteres. Se explica en el C FAQ. En el futuro, cuando no comprenda una declaración, use cdecl o cdecl(1).

+0

Muchas gracias, su enlace a las preguntas frecuentes de C me ayudó a comprender mucho este tema. – jpmelos

3
char (*p3)[5]; 

realidad declara un puntero a un array de 5 char. Significa que debe apuntar a un puntero que apunta a una matriz de 5 char. No asigna 5 de nada, solo un puntero, y debe apuntar a algo que apunta a 5 char.

Por lo tanto, el uso correcto es:

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

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3 = &p1;                

     printf("p1 = %s\np2[0] = %s\np3 = %s\n", p1, p2[0], *p3);    

     return 0;                
} 

Si desea acceder a una sola posición de esa cadena p1 p3 usando para acceder a ella, debe hacer (*p3)[2], por ejemplo. Accederá a la tercera posición. Esto se debe a que primero debe transformar p3 en p1 (las desreferencias (*p3) antes de realizar la aritmética de posición) y luego acceder a la tercera posición de esa dirección (apuntada por el puntero desreferenciado).

+0

Genial, usted resumió mi respuesta mejor :-) –

4
char p[5];  // p is a 5-element array of char 
char *p[5];  // p is a 5-element array of pointer to char 
char (*p)[5]; // p is a pointer to a 5-element array of char 

sintaxis de declaración de C se basa en los tipos de expresiones , no objetos.La idea es que la forma de la declaración coincida con la forma de la expresión tal como aparecería en el código.

En los casos anteriores, estamos tratando con arreglos. En el primer caso, p es una matriz de char; acceder a un valor de carácter particular, queremos simplemente índice en la matriz:

val = p[i]; 

El tipo de la expresión p[i] es char, por tanto, la declaración de p es char p[5].

En el siguiente caso, p es una matriz de punteros a char; para acceder al valor, índice en la matriz y eliminar la referencia al resultado:

val = *p[i]; 

operadores de sufijo como [] tener una prioridad más alta que los operadores unarios como *, por lo que la anterior se analiza como

val = *(p[i]); 

El tipo de la expresión *p[i] es char, por lo que la declaración de p es char *p[5].

En el último caso, p es un puntero a una matriz de char, por lo que para acceder a un valor Char tenemos que eliminar la referencia al puntero de la lista y luego subíndice en el resultado:

val = (*p)[i]; 

Debido [] tiene mayor precedencia que unario *, tenemos que usar paréntesis para agrupar explícitamente con p (a diferencia de p[i]). De nuevo, el tipo de expresión (*p)[i] es char, por lo que la declaración de p es char (*p)[5].

EDITAR

Punteros a matrices se muestran en los siguientes contextos:

  1. usted está tomando explícitamente la dirección de una matriz de N dimensiones:

    int x[10]; 
    int (*px)[10] = &x; 
    
    Tenga en cuenta que mientras que las expresiones y x&x producen el mismo valor (la dirección del primer elemento de la matriz), tienen tipos diferentes (int * frente a int (*)[10]).

  2. Estás asignar dinámicamente un objeto de tipo array: expresión de matriz

    int (*px)[10] = malloc(sizeof *px); 
    

  3. un N-dimensional "decae" en un puntero a un (N-1) -Dimensiones array:

    int x[10][20]; 
    foo(x); 
    ... 
    void foo(int (*px)[20]){...} 
    

+0

+1. Muy buena explicación! ¡Gracias, realmente dejó en claro cómo pensar sobre las declaraciones! – jpmelos

+0

En su edición, primer contexto, usted dice que 'x' tiene tipo' int * 'y' & x' tiene tipo 'int (*) [10]'. ¿En realidad quieres decir 'x' tiene tipo' int [10] ', supongo? – jpmelos

+1

@jpmelos: Como no es un operando para 'sizeof' o' & ',' x' decaería a 'int *'. –

Cuestiones relacionadas