2010-01-09 22 views
6

cuando tengo que pasar una matriz a una función, parece todas las siguientes declaraciones de la función trabajarántipo de matriz - Reglas para la asignación/uso como parámetro de la función

void f(int arr[]) 
void f(int arr[4]) // is this one correct? 

para esto:

int a[]={1,2,3,4}; 
f(a); 

Pero cuando le asigno una matriz a otra matriz, falla

int a[]={1,2,3,4}; 
int b[4] = a; // error: array must be initialized with a brace-enclosed initializer 

Entonces, ¿por una matriz pasa como un argum de una función está bien, pero se usa en el rhs de asignación simple ¿está mal?

+3

El título de la pregunta debe ser reescrito, el actual es excesivamente genérico y minúsculo. –

Respuesta

12

Para entender la diferencia, tenemos que entender dos diferentes contextos .

  • En valor contextos, el nombre de una matriz de tipo T es equivalente a un puntero para escribir T, y es igual a un puntero a primer elemento de la matriz.
  • En objeto contextos, el nombre de una matriz de tipo T no se reduce a un puntero.

¿Qué es object context?

En a = b;, a se encuentra dentro del contexto del objeto. Cuando tomó la dirección de una variable, se usa en el contexto del objeto. Finalmente, cuando usa el operador sizeof en una variable, se usa en el contexto del objeto. En todos los demás casos, una variable se usa en contexto de valor.

Ahora que tenemos este conocimiento, cuando hacemos:

void f(int arr[4]); 

Es exactamente equivalente a

void f(int *arr); 

Como has descubierto, podemos omitir el tamaño (4 anterior) de la declaración de la función. Esto significa que no puede saber el tamaño de la "matriz" pasada a f().Más tarde, cuando lo hace:

int a[]={1,2,3,4}; 
f(a); 

En la llamada a la función, el nombre a está en el contexto de valor, por lo que se reduce a un puntero a int. Esto es bueno, porque f espera un puntero a int, por lo que la definición y el uso de la función coinciden. Lo que se pasa a f() es el puntero al primer elemento de a (&a[0]).

En el caso de

int a[]={1,2,3,4}; 
int b[4] = a; 

El nombre b se utiliza en un contexto de objeto, y no se reduce a un puntero. (Por cierto, aquí aes en un contexto de valor, y se reduce a un puntero.)

Ahora, int b[4]; asigna pena de almacenamiento de 4 int s y le da el nombre b a ella. a también se le asignó un almacenamiento similar. Entonces, en efecto, la asignación anterior significa, "Quiero que la ubicación de almacenamiento sea la misma que la ubicación anterior". Esto no tiene sentido.

Si desea copia el contenido de a en b, entonces se podría hacer:

#include <string.h> 
int b[4]; 
memcpy(b, a, sizeof b); 

O, si desea un puntero b que apuntaba a a:

int *b = a; 

Aquí, a está en contexto de valor y se reduce a un puntero a int, por lo que podemos asignar a a un int *.

Por último, al inicializar una matriz, puede asignarle valores explícitos:

int a[] = {1, 2, 3, 4}; 

Aquí, un 4 elementos, ha inicializado a 1, 2, 3 y 4. También puede hacer :

int a[4] = {1, 2, 3, 4}; 

Si hay menos elementos de la lista que el número de elementos de la matriz, a continuación, el resto de los valores se toman a ser 0:

int a[4] = {1, 2}; 

conjuntos a[2] y a[3] a 0.

+0

Muy bien escrito. – benzado

+0

¿Puede proporcionar una referencia sobre dónde lee sobre objetos y contextos de valores? Estoy interesado en leer más. –

+0

Nunca escuché hablar de "contexto de objetos" vs "contexto de valores". –

7
void f(int arr[]); 
void f(int arr[4]); 

La sintaxis es engañosa. Ambos son lo mismo que esto:

void f(int *arr); 

es decir, que están pasando un puntero al comienzo de la matriz. No estás copiando la matriz.

+3

Sí, sin embargo (en C99) 'void f (int arr [static 4]) {...}' es especial porque permite al compilador suponer que 'arr' no es' 'NULL' y que tiene un tamaño mínimo 4. – Jed

6

C no admite la asignación de matrices. En el caso de una llamada de función, la matriz se desintegra a un puntero. C no admite la asignación de punteros. Esto se pregunta aquí todos los días: ¿qué libro de texto de C leen ustedes que no explica esto?

3

Pruebe memcpy.

int a[]={1,2,3,4}; 
int b[4]; 
memcpy(b, a, sizeof(b)); 

Gracias por señalarlo, Steve, que ha pasado un tiempo desde que he utilizado C.

+1

'memcpy (b, a, 4 * sizeof (int)'. O 'sizeof (b)'. –

1

para obtener su intuición al respecto, hay que entender lo que está pasando en el nivel de la máquina.

La semántica de inicialización (= {1,2,3,4}) significa "ponerlo en su imagen binaria exactamente de esta manera" para que pueda compilarse.

La asignación de la matriz sería diferente: el compilador tendría que traducirlo a un bucle, lo que en realidad sería iterar sobre los elementos. El compilador de C (o C++, para el caso) nunca hace tal cosa. Con razón, espera que lo hagas tú mismo. ¿Por qué? Porque tú puedes. Entonces, debería ser una subrutina, escrita en C (memcpy).Todo esto se trata de la simplicidad y la cercanía de tu arma, que se trata de C y C++.

0

Tenga en cuenta que el tipo de a en int a[4] es int [4].

Pero TypeOf (&a) == int (*)[4]! = int [4].

También tenga en cuenta que el tipo del valor de a es int *, que es distinto de todo lo anterior!

Aquí es un programa de ejemplo que puede probar:

int main() { 
    // All of these are different, incompatible types!  
    printf("%d\n", sizeof (int[4])); // 16 
    // These two may be the same size, but are *not* interchangeable! 
    printf("%d\n", sizeof (int (*)[4])); // 4 
    printf("%d\n", sizeof (int *)); // 4 
} 
+0

Debe usar "% zu" para imprimir size_t (en C99). – Jens

0

quiero aclarar. Hay algunos indicios engañosos en respuestas ... Todos siguientes funciones pueden tomar matrices de enteros:

void f(int arr[]) 
void f(int arr[4]) 
void f(int *arr) 

Pero argumentos formales no son los mismos. Entonces el compilador puede manejarlos de manera diferente. En el sentido de administración de memoria interna, todos los argumentos conducen a indicadores.

void f(int arr[]) 

... f() toma una matriz de cualquier tamaño.

void f(int arr[4]) 

... El argumento formal indica un tamaño de matriz.

void f(int *arr) 

... También puede pasar un puntero entero. f() no sabe nada sobre el tamaño.

Cuestiones relacionadas