Hay un patrón cuando se trata de matrices y funciones; es un poco difícil de ver al principio.
Cuando se trata de matrices, es útil recordar lo siguiente: cuando aparece una expresión de matriz en la mayoría de contextos, el tipo de expresión se convierte implícitamente de "N-elemento matriz de T" a "puntero a T", y su valor está configurado para apuntar al primer elemento en la matriz. Las excepciones a esta regla son cuando la expresión del arreglo aparece como un operando de los operadores &
o sizeof
, o cuando se trata de un literal de cadena que se utiliza como un inicializador en una declaración.
Por lo tanto, cuando se llama a una función con una expresión de matriz como argumento, la función recibirá un puntero, no una matriz:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Es por eso que no utiliza el operador &
para los argumentos correspondientes a "% s" en scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
Debido a la conversión implícita, scanf()
recibe un valor char *
que apunta a th e principio de la matriz str
. Esto es válido para cualquier función llamada con una expresión de matriz como argumento (cualquiera de las funciones str*
, *scanf
y *printf
, etc.).
En la práctica, es probable que nunca se llama a una función con una expresión de matriz usando el operador &
, como en:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Tal código no es muy común; debe saber el tamaño de la matriz en la declaración de función, y la función solo funciona con punteros a matrices de tamaños específicos (un puntero a una matriz de 10 elementos de T es un tipo diferente a un puntero a una matriz de 11 elementos de T).
Cuando una expresión de matriz aparece como un operando al operador &
, el tipo de la expresión resultante es "puntero a la matriz N-elemento de T", o T (*)[N]
, que es diferente de una matriz de punteros (T *[N]
) y un puntero al tipo de base (T *
).
Cuando se trata de funciones y punteros, la regla para recordar es: si desea cambiar el valor de un argumento y hacerlo reflejar en el código de llamada, debe pasar un puntero al objeto que desea modificar. De nuevo, las matrices lanzan un poco de llave inglesa a las obras, pero primero trataremos con los casos normales.
Recuerde que C pasa todos los argumentos de la función por valor; el parámetro formal recibe una copia del valor en el parámetro real, y cualquier cambio en el parámetro formal no se refleja en el parámetro real. El ejemplo común es una función de intercambio:
void swap(int x, int y) { int tmp = x; x = y; y = x; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
Usted obtendrá el siguiente resultado:
before swap: a = 1, b = 2
after swap: a = 1, b = 2
Los parámetros formales x
y y
son objetos distintos de a
y b
, por lo que los cambios en x
y y
no se reflejan en a
y b
.Dado que queremos modificar los valores de a
y b
, debemos pasar punteros a ellos a la función de intercambio:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);
Ahora su salida será
before swap: a = 1, b = 2
after swap: a = 2, b = 1
Tenga en cuenta que, en el canje función, no cambiamos los valores de x
y y
, pero los valores de x
y y
apuntan a. Escribir en *x
es diferente de escribir en x
; no estamos actualizando el valor en x
, obtenemos una ubicación desde x
y actualizamos el valor en esa ubicación.
Esto es igualmente cierto si queremos modificar un valor de puntero; si escribimos
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
entonces estamos modificando el valor del parámetro de entrada stream
, no lo stream
puntos a, por lo que cambiar stream
no tiene ningún efecto sobre el valor de in
; Para que esto funcione, tenemos que pasar en un puntero al puntero:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Una vez más, las matrices tirar un poco de una llave inglesa en las obras. Cuando pasa una expresión de matriz a una función, lo que recibe la función es un puntero. Debido a cómo se define subíndices de matriz, se puede utilizar un operador subíndice en un puntero de la misma manera que se puede utilizar en una matriz:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
en cuenta que los objetos de matriz no pueden ser asignados; es decir, no se puede hacer algo como
int a[10], b[10];
...
a = b;
por lo que desea tener cuidado cuando se está tratando con punteros a las matrices; algo como
void (int (*foo)[N])
{
...
*foo = ...;
}
no funcionará.
Por favor, ilustra cómo ves que las cosas a veces funcionan de manera diferente. De lo contrario, tenemos que adivinar qué es lo que te está confundiendo. –
De acuerdo con Neil Butterworth. Probablemente va a obtener mucha más información obteniéndolo de primera mano de un libro, y la explicación de K & R es bastante clara. – Tom
Aunque * es * un tema difícil de buscar en esto se ha discutido una y otra vez en varias formas. Los siguientes están tomados de http://stackoverflow.com/search?q=c+pointer+basic y probablemente sean relevantes (estoy seguro de que hay un duplicado, pero no lo he encontrado): http: // stackoverflow .com/questions/5727/what-are-the-barriers-to-understanding-puninters-and-what-can-be-done-to-overcome http://stackoverflow.com/questions/897366/how-do- puntero-a-punteros-trabajo-en-c http://stackoverflow.com/questions/162941/why-use-pointers http://stackoverflow.com/questions/500886/how-to-approach-pointers-in- c – dmckee