2010-05-23 16 views
14

Soy un asistente de enseñanza de un curso de introducción a la programación, y algunos estudiantes hacen este tipo de error:"Dirección de" (&) una matriz/dirección de ser ignorada ser gcc?

char name[20]; 
scanf("%s",&name); 

lo cual no es sorprendente, ya que están aprendiendo ... Lo que es sorprendente es que, además de la advertencia gcc, el código funciona (al menos esta parte). He estado tratando de entender y escribí el siguiente código:

void foo(int *v1, int *v2) { 
    if (v1 == v2) 
    printf("Both pointers are the same\n"); 
    else 
    printf("They are not the same\n"); 
} 

int main() { 
    int test[50]; 
    foo(&test, test); 
    if (&test == test) 
    printf("Both pointers are the same\n"); 
    else 
    printf("They are not the same\n"); 
} 

Compilar y ejecutar:

$ gcc test.c -g 
test.c: In function ‘main’: 
test.c:12: warning: passing argument 1 of ‘foo’ from incompatible pointer type 
test.c:13: warning: comparison of distinct pointer types lacks a cast 
$ ./a.out 
Both pointers are the same 
Both pointers are the same 

Puede alguien explicar por qué no son diferentes?

Sospecho que es porque no puedo obtener la dirección de una matriz (ya que no puedo tener & &x), pero en este caso el código no debería compilarse.

Editar: Sé que una matriz en sí misma es igual a la dirección del primer elemento, pero esto no está relacionado con este problema, creo. Por ejemplo:

int main() { 
    int a[50]; 
    int * p = a; 
    printf("%d %d %d\n", p == a, p == &a[0], &p[0] == a); 
    printf("%d %d %d\n", p == &a, &p == a, &p == &a); 
} 

impresiones:

$ ./a.out 
1 1 1 
1 0 0 

no entiendo por qué la segunda línea comienza con 1.

+1

Su edición indica que cree que hay algún puntero almacenado junto con la matriz. Pero ese no es el caso. Una matriz consiste * solo * de sus elementos. –

+0

Sabía que una matriz solo son elementos, por eso pensé que no debería compilarse. – dbarbosa

Respuesta

22

En su ejemplo, la matriz test es un bloque de 50 ints. Por lo que se ve así:

| int | int | ... | int | 

Cuando se aplica el operador unitario & a una matriz, se obtiene la dirección de la matriz . Al igual que cuando lo aplicas a cualquier otra cosa, realmente. Así &test es un puntero que apunta a ese bloque de 50 ints:

(&test) -----------> | int | int | ... | int | 

Un puntero que apunta a un array de 50 enteros tiene tipo int (*)[50] - ese es el tipo de &test.

Cuando sólo tiene que utilizar el nombre test en cualquier lugar donde no es el operando de cualquiera de las sizeof o unary- & operadores, se evalúa a un puntero a su primer elemento. Por lo que el test que se pasa a foo() se evalúa como un puntero al elemento test[0]:

(test) -----------------\ 
         v 
(&test) -----------> | int | int | ... | int | 

se puede ver que ambos están apuntando a la misma dirección - a pesar de &test está apuntando a todo el conjunto, y test está señalando al primer elemento de la matriz (que solo aparece en los diferentes tipos que tienen esos valores).

+0

+1; a veces una imagen vale más que 1,000 palabras :-) –

+6

Me gusta el arte ascii :) Ahora con esa foto, es fácil explicar por qué agregar '1' a' & test' se mueve más allá de la matriz y agrega '1' a' prueba' se mueve solo más allá del primer elemento. –

+0

¡Después de eso tuve que cambiar la "respuesta aceptada"! – dbarbosa

9

En realidad, son diferentes, al menos no tienen el mismo tipo.

Pero en C, la dirección de la matriz es la misma que la dirección del primer elemento de la matriz por lo que "no son diferentes", básicamente apuntan a lo mismo.

+0

"la dirección de la matriz es la misma que la dirección del primer elemento en la matriz" Siempre supe que la matriz en sí misma (y * no * la dirección de la matriz) es la misma que la dirección de la matriz primer elemento, es decir, 'test' es exactamente lo mismo que' & test [0] '. Acabo de registrar K & R, y eso es lo que está escrito allí ... Voy a editar mi pregunta para agregar esto. – dbarbosa

+3

@WhirlWind: No, depende del sistema * no *. Al aplicar el operador de dirección a una matriz tiene una semántica bien definida, debe producir la dirección de la matriz misma. La matriz se define como una secuencia consecutiva de objetos del tipo base, y por lo tanto la dirección de la matriz y la dirección del primer objeto son el mismo lugar (pero con diferentes tipos). – caf

-2

Creo que esto es una optimización de gcc. Piénsalo.

  • &test apunta a la dirección de test
  • test puntos para el primer elemento de test o &test[0]
  • [0] es el mismo (en su mayor parte) como *

Así según esto &testpodría ser diferente que test pero gcc optim lo aleja porque no hay ningún propósito de tener un nivel extra de indirección en ese punto.

+2

No es una optimización de gcc; es un comportamiento requerido por el estándar C. – caf

+0

Parece que @Earlz está confundido con el significado de & test exactamente como yo. – dbarbosa

+1

@dba wow Yo era.La respuesta aceptada para esto lo borra por completo – Earlz

5

Si se define como un conjunto

char name[20]; 

name es convertir implícitamente a char*, pero &name es del tipo char (*)[20] (un puntero a una matriz de 20 caracteres). Las direcciones son iguales.

Compruebe la dirección de (&name + 1). Se diferencia del formulario &name por el sizeof(char [20]).

+0

Gracias, ha hecho que sea más fácil entender la respuesta de James McNellis. – dbarbosa

+0

El placer es todo mío :) –

2

El nombre de una matriz, en la mayoría de los casos, evalúa a la dirección de su elemento inicial. Las dos excepciones son cuando es el operando de sizeof o el único &.

El unario & da la dirección de su argumento. La dirección de una matriz es la misma que la dirección de su elemento inicial, por lo que (void*)&array == (void*)array siempre será verdadero.

array, cuando se convierte en un puntero a su elemento inicial, tiene el tipo T *. El tipo de &array es T (*)[n], donde n es la cantidad de elementos en la matriz. Por lo tanto,

int* p = array;  // Works; p is a pointer to array[0] 
int* q = &array;  // Doesn't work; &array has type int (*)[10] 
int (*r)[10] = &array; // Works; r is a pointer to array 
+0

Gracias, solo sabía la excepción de sizeof. – dbarbosa

Cuestiones relacionadas