2012-04-01 23 views
7

Considere el código:¿Se pasa un argumento de matriz a una función, no un puntero constante?

void foo(char a[]){ 
    a++;   // works fine, gets compiled 
    //... 
} 

Ahora, considere esto:

void foo(){ 
    char a[50]; 
    a++;   // Compiler error 
    //... 
} 

oí una matriz es equivalente a un puntero constante y no se puede aumentar, ya que no es un valor-i ...

Entonces, ¿por qué se compila el primer código, es así porque los argumentos del conjunto de funciones se pasan como un puntero, es decir, T [] se convierte en T * para pasar ... Entonces, foo (a) pasa a como puntero.

Pero no es reconvertido a T [] de nuevo porque está declarada como:

void foo(char a[]); 
+2

Lea la sección 6 de las [preguntas frecuentes comp.lang.c] (http://c-faq.com). –

Respuesta

13

Cuando se pasa una matriz como argumento de una función, que se descompone a un puntero.
Así que lo que incrementa dentro del cuerpo de la función es un puntero, no una matriz.

+0

En particular, es como si declarara 'char * temp = a;' luego incrementado 'temp'. –

4

oí una matriz es equivalente a un puntero constante

Usted puede pensar de esa manera, pero no son equivalentes.

Una matriz se desintegra a un puntero cuando se pasa a una función, es por eso que dentro de la función es válida.

El hecho de que la firma sea void foo(char a[]) no convierte a en una matriz.

Fuera de la función, es solo una matriz, y no puede hacer aritmética de puntero sobre ella.

1

Cuando pasa una matriz a [] a una función, pasa el valor de 'a', una dirección, a la función. para que pueda usarlo como un puntero en la función. Si declara una matriz en la función, 'a' es constante porque no puede cambiar su dirección en la memoria.

8

Esta es una característica bastante desafortunada heredada del lenguaje C, con el nombre bastante asqueroso de "decaimiento". Como C una vez no permitió pasar los tipos de compuestos por valor, decidieron permitir a los programadores especificar matrices como tipos de parámetros de funciones, pero solo estéticamente. El tipo de matriz se desintegra a un tipo de puntero, implementando un tipo de semántica de referencia paso por punto diferente del resto del lenguaje. Feo.

Para recapitular (y otros ya han dicho esto), la firma

void foo(char a[]); // asking for trouble 

está destrozado sin contemplaciones en

void foo(char *a); 

... todo por el bien de la compatibilidad con el código C antigua. Como no está escribiendo código C antiguo, no debe utilizar esta "característica".

Sin embargo, puede pasar limpiamente una referencia a una matriz.C++ requiere que el tamaño de la matriz se conoce:

void foo(char (&a)[ 50 ]); 

Ahora a no se puede modificar dentro de la función (de edición: sus contenidos pueden, por supuesto - usted sabe lo que quiero decir), y sólo matrices de la el tamaño correcto puede ser pasado. Para todo lo demás, pase un puntero o un tipo de nivel superior.

-1

Dentro de la función, a es una dirección en sí, que apunta a una variable local. Puede incrementarlo porque es una dirección. También puede hacer algo como esto:

char a[50]; 
int i; 
for(i=0;i<50;i++) 
    *(a+i)='b'; 

Ningún error.

+2

No, la matriz no se pasa a la función, solo la dirección de su primer elemento. –

+0

No lo creo. En el primer tipo, me refiero a 'void foo (char [] a) {..}', los cambios en la matriz no afectan la matriz principal a la que regresa la función. – mtyurt

+1

Los cambios en 'a' afectan solo al parámetro, que es un objeto local * puntero *. Intenta modificar 'a [0]' y ver qué pasa. Luego lea la sección 6 de [preguntas frecuentes comp.lang.c] (http://c-faq.com). –

3

En C++, cualquier parámetro de función del tipo "array of T" se ajusta para que sea "puntero a T". Pruebe este código:

void foo(char a[]) {} 
void foo(char* a) {} //error: redefinition 

Son de hecho la misma función.

Entonces, ¿por qué podemos pasar un argumento de matriz a una función como un parámetro de puntero? No porque una matriz sea equivalente a un puntero constante, sino porque un tipo de matriz se puede convertir implícitamente en un valor r de tipo de puntero. También tenga en cuenta que el resultado de la conversión es un valor r, es por eso que no puede aplicar el operador ++ a una matriz, solo puede aplicar este operador a un valor l.

1

oí una matriz es equivalente a un puntero constante y no se puede aumentar, ya que no es un valor-i ...

Casi.

Una matriz expresión es una lvalue no modificable; puede no ser un operando para operadores como ++ o --, y puede no ser el destino de una expresión de asignación. Esto no es lo mismo que un puntero constante (es decir, un puntero declarado como T * const).

Una expresión de matriz será reemplazado con una expresión puntero cuyo valor es la dirección del primer elemento de la matriz excepto cuando la expresión de matriz es un operando de los sizeof o unario & operadores, o cuando la expresión de matriz es un literal de cadena que se usa para inicializar otra matriz en una declaración.

Cuando se llama a una función con un argumento de matriz, tales como

int a[N]; 
... 
foo(a); 

la expresión a se convierte de "array N-elemento de int" tipo a "puntero a int", y este valor del puntero es lo que pasa a foo; Por lo tanto, el prototipo de función correspondiente debe ser

void foo (int *arr) {...} 

Tenga en cuenta que en el contexto de una declaración parámetro de función, T a[] y T a[N] son idénticos a T *a; en los tres casos, a se declara como un puntero a T.Dentro de la función foo, el parámetro arr es una expresión de puntero, que es un valor l modificable, y como tal puede asignarse ay puede ser el operando de los operadores ++ y --.

Recuerde que todas estas conversiones se encuentran en la matriz expresión; es decir, el identificador de matriz u otra expresión que hace referencia a la matriz objeto en la memoria. El objeto de matriz (el fragmento de memoria que contiene los valores de matriz) no se convierte.

Cuestiones relacionadas