2012-04-20 26 views
17

¿Qué está haciendo el siguiente código?apuntador a la matriz C++

int g[] = {9,8}; 
int (*j) = g; 

Desde mi entender la creación de un puntero a un array de 2 enteros. Pero entonces ¿por qué este trabajo:

int x = j[0]; 

y esto no funciona:

int x = (*j)[0]; 
+15

@mjfgates: las matrices no son punteros. Deja de decirle a la gente eso. –

+7

@mjfgates De hecho, hay un objeto de matriz en C y C++. Simplemente sucede que hay reglas extrañas que, por ejemplo, causan conversiones implícitas de una matriz a un puntero al primer elemento de la matriz. – bames53

Respuesta

37

Los paréntesis son superfluos en su ejemplo. El puntero no le importa si hay una matriz involucrada - que sólo sabe que su apuntando a un int

int g[] = {9,8}; 
    int (*j) = g; 

también podría reescribirse como

int g[] = {9,8}; 
    int *j = g; 

que también podría ser reescrita como

int g[] = {9,8}; 
    int *j = &g[0]; 

un puntero-a-un-array se vería

int g[] = {9,8}; 
    int (*j)[2] = &g; 

    //Dereference 'j' and access array element zero 
    int n = (*j)[0]; 

Hay una buena lectura de las declaraciones de puntero (y la forma de asimilar ellos) en este enlace aquí: http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

+0

este artículo es muy útil, especialmente la regla de derecha a izquierda, gracias. –

+0

es el '2' necesario en' int (* j) [2] = & g; '? ¿Aún no sería un puntero a una matriz si se omitiera el '2'? – johnbakers

+0

@johnbakers sí, es absolutamente necesario especificar la longitud de la matriz; de lo contrario, no tendrá un puntero a matriz, y luego el código no se compilará a menos que use un molde. Apuntando a una matriz implica que tiene conocimiento de su longitud en tiempo de compilación. El mensaje del compilador resultante de omitir la longitud de la matriz en MSVC++ lee 'error C2440: 'inicializando': no ​​se puede convertir de 'int (*) [2]' a 'int (*) []'' –

9

j[0]; elimina referencia a un puntero a int, por lo que su tipo es int.

(*j)[0] no tiene ningún tipo. *j desreferencia un puntero a un int, por lo que devuelve un int, y (*j)[0] intenta desreferenciar un int. Es como intentar int x = 8; x[0];.

+3

Además, recuerde que 'j [0]' es equivalente a '* (j + 0)'. '(* j) [0]' es por lo tanto equivalente a 'j [0] [0]', que es equivalente a '* (* (j + 0) + 0)', que funciona como '** j '. De cualquier forma que lo mires, no funcionará. – chris

+0

entonces, ¿cómo crearías un puntero a un grupo de elementos de la matriz? –

+0

Establece el puntero al primer elemento y lo usa como una matriz, ya que 'j [1] == * (j + 1) == el siguiente elemento de la matriz'. – chris

19
int g[] = {9,8}; 

Esto declara un objeto de tipo int [2], e inicializa sus elementos a {9 , 8}

int (*j) = g; 

Esto declara un objeto de tipo int *, y lo inicializa con un puntero al primer elemento de g.

El hecho de que la segunda declaración inicialice j con algo que no sea g es bastante extraño. C y C++ solo tienen estas reglas extrañas sobre las matrices, y esta es una de ellas. Aquí la expresión g se convierte implícitamente de un lvalue que hace referencia al objeto g en un valor r de tipo int* que apunta al primer elemento de g.

Esta conversión se produce en varios lugares. De hecho, ocurre cuando haces g[0]. El operador de índice de matriz en realidad no funciona en matrices, solo en punteros. Por lo tanto, la instrucción int x = j[0]; funciona porque g[0] pasa a hacer la misma conversión implícita que se realizó cuando se inicializó j.

Un puntero a una matriz se declara como esto

int (*k)[2]; 

y que está en lo cierto acerca de cómo esto se utilizaría

int x = (*k)[0]; 

(observar cómo "declaration follows use", es decir, la sintaxis para declarar una variable de un tipo imita la sintaxis para usando una variable de ese tipo.)

Sin embargo, uno no suele usar un puntero a una matriz. El propósito total de las reglas especiales en torno a las matrices es que puede usar un puntero a un elemento de la matriz como si fuera una matriz. Por lo tanto, a la C idiomática generalmente no le importa que las matrices y punteros no sean la misma cosa, y las reglas le impiden hacer mucho de lo que sea útil directamente con las matrices. (Por ejemplo no se puede copiar una matriz como: int g[2] = {1,2}; int h[2]; h = g;)


Ejemplos:

void foo(int c[10]); // looks like we're taking an array by value. 
// Wrong, the parameter type is 'adjusted' to be int* 

int bar[3] = {1,2}; 
foo(bar); // compile error due to wrong types (int[3] vs. int[10])? 
// No, compiles fine but you'll probably get undefined behavior at runtime 

// if you want type checking, you can pass arrays by reference (or just use std::array): 
void foo2(int (&c)[10]); // paramater type isn't 'adjusted' 
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10] 

int baz()[10]; // returning an array by value? 
// No, return types are prohibited from being an array. 

int g[2] = {1,2}; 
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax 
h = g; // copying an array? No, assigning to arrays is prohibited 

Debido arrays son tan incompatibles con los otros tipos en C y C++ que sólo debe evitar ellos. C++ tiene std::array que es mucho más consistente y debe usarlo cuando necesite matrices de tamaño estático. Si necesita matrices de tamaño dinámico, su primera opción es std :: vector.

+0

+1 para la descripción precisa de la relación matriz/puntero, sin usar la palabra decaimiento. –

Cuestiones relacionadas