una - Experimentos utilizando sizeof con matrices y punteros.
punteros en c (3)
Por favor responda las preguntas y corríjame si alguna de las observaciones es incorrecta.
- ¿Es la salida
20
caso 1 porqueb
se declaró como unaarray
deint
inters, es decir,int[]
? El bloque total en bytes se devuelve como lo confirma Fact1. ¿No es así?
Sí, el resultado muestra la sizeof(int [5])
. Así que a partir de Fact1, el tamaño es 5*4
- Supongo que lanzar
b
toint*
hizo la diferencia aquí. Aquíb
se considera un puntero. Confirmé esto utilizando Fact2. ¿Bien o mal?
Derecha. Pero agregar más información: sizeof
necesita solo el tipo de expresión y no evalúa la expresión (para valor) a menos que sea del tipo VLA. (De la sección 6.5.3.4 El operador sizeof de especificaciones C99 )
Debido a que está aplicando elenco en el resultado final, nada de eso no importa.
&b[0]
decae a un punterob
. La salida coincide con Fact2.
No y sí. El tipo de b[0]
es int
y, por lo tanto, el tipo de &b[0]
ya es int *
(Recuerde que [...]
une más que &
). No hay decadencia. Y sí, la salida coincide con Fact2.
- Esperaba 16 aquí pero obtuve 8 como salida. Llegué a la conclusión de que esto se debe a que, después de todo, es un puntero y la salida coincide con Fact2. Tengo la salida similar a la pregunta 2.
como a
puntero a la matriz 2 de int
. Así que el tamaño impreso es de puntero (a una matriz int
).
int (*a)[2];
declara a
puntero a la matriz 2 de int
. Así obtienes el tamaño de pointer to array
.
Para obtener el resultado deseado (tamaño de la matriz 2 de punteros a int
) use: int *a[2];
int (*a)[2];
a anonymous
+----+ +----+----+
| a |----->|int |int |
+----+ +----+----+
int *b[2];
b
+----+----+
|int*|int*|
+----+----+
b[0] b[1]
a[0]
es puntero. La salida coincide con Fact2.a[2]
es el puntero. La salida coincide con Fact2.
Como se indicó anteriormente, a
es un puntero a la matriz 2 de int
. Entonces a[index]
es una matriz 2 si es int
. Entonces, el tipo de a[0]
y a[1]
son la matriz 2 de int
. Así que la salida es 2*4
de Hecho 1.
Posiblemente irrelevante para esta respuesta, pero no está inicializado y su uso en la expresión causaría un comportamiento indefinido . Aunque está bien para usar en sizeof
Para entender el resultado, analicemos el tipo de argumento de sizeof
printf("sizeof(b) : %zu/n",sizeof(b)); // int [5]
printf("sizeof((int*)b) : %zu/n",sizeof((int*)b)); // int *
printf("sizeof(&b[0]) : %zu/n",sizeof(&b[0])); // int *
printf("sizeof(a) : %zu/n",sizeof(a)); // int (*) [2]
printf("sizeof(a[0]) : %zu/n",sizeof(a[0])); // int [2]
printf("sizeof(a[1]) : %zu/n",sizeof(a[1])); // int [2]
Un programa portátil (no infalible) para confirmar los tipos se ve así:
assert(sizeof(b) == sizeof(int [5]));
assert(sizeof((int*)b) == sizeof(int *));
assert(sizeof(&b[0]) == sizeof(int *));
assert(sizeof(a) == sizeof(int(*)[2]));
assert(sizeof(a[0]) == sizeof(int[2]));
assert(sizeof(a[1]) == sizeof(int[2]));
Para el programa:
#include<stdio.h>
int main(void)
{
int (*a)[2];
int b[5];
printf("sizeof(int) : %zu/n", sizeof(int));
printf("sizeof(int*) : %zu/n", sizeof(int*));
printf("sizeof(b) : %zu/n",sizeof(b));
printf("sizeof((int*)b) : %zu/n",sizeof((int*)b));
printf("sizeof(&b[0]) : %zu/n",sizeof(&b[0]));
printf("sizeof(a) : %zu/n",sizeof(a));
printf("sizeof(a[0]) : %zu/n",sizeof(a[0]));
printf("sizeof(a[1]) : %zu/n",sizeof(a[1]));
return 0;
}
La salida es:
sizeof(int) : 4 -> Fact 1
sizeof(int*) : 8 -> Fact 2
sizeof(b) : 20 -> Case 1
sizeof((int*)b) : 8 -> Case 2
sizeof(&b[0]) : 8 -> Case 3
sizeof(a) : 8 -> Case 4
sizeof(a[0]) : 8 -> Case 5
sizeof(a[1]) : 8 -> Case 6
Preguntas / Observaciones (en caso de orden):
¿Es el caso 1 la salida 20 porque
b
se declaró como una matriz de enteros, es decir,int[]
? El bloque total en bytes se devuelve como lo confirma Fact1. ¿No es así?Supongo que lanzar
b
toint*
hizo la diferencia aquí. Aquíb
se considera un puntero. Confirmé esto utilizando Fact2. ¿Bien o mal?&b[0]
decae a un punterob
. La salida coincide con Fact2.Esperaba 16 aquí pero obtuve 8 como salida. Llegué a la conclusión de que esto se debe
a
que, después de todo, es un puntero y la salida coincide con Fact2. Tengo la salida similar a la pregunta 2.a[0]
es puntero. La salida coincide con Fact2.a[1]
es puntero. La salida coincide con Fact2.
Por favor responda las preguntas y corríjame si alguna de las observaciones es incorrecta.
Aquí hay un poco de investigación individual sobre el tema. He ejecutado su código de prueba en cuatro entornos diferentes, dos de 64 bits y dos de 32 bits.
Utilicé tres compiladores diferentes: llvm, gcc y mipsPro cc.
Aquí está la comparación comentada de los resultados :
// 64-bit environment - all compilers
sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes
sizeof(int*) : 8 -> Fact 2 -this and other pointers in a 64-bit system are 8-bytes long
sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes
sizeof((int*)b) : 8 -> Case 2
sizeof(&b[0]) : 8 -> Case 3
sizeof(a) : 8 -> Case 4
sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints
sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints
// 32-bit environments - all compilers
sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes
sizeof(int*) : 4 -> Fact 2 -this and other pointers in a 32-bit system are 4-bytes long
sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes
sizeof((int*)b) : 4 -> Case 2
sizeof(&b[0]) : 4 -> Case 3
sizeof(a) : 4- > Case 4
sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints
sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints
Interpretación : todos los resultados coinciden constantemente con el siguiente patrón:
- El tamaño de
int
solía depender del compilador, y quizás todavía lo hace, AFAIK Se encuentra en todos los entornos probados y compiladores de 4 bytes (Hecho 1). - El tamaño de todos los punteros está predeterminado para el entorno, ya sea 64 bits o 32 bits (Hecho 2, Caso 2, 3, 4).
- El tamaño de una matriz de dos ints de cuatro bytes es igual a
2*sizeof(int)
(Caso 5, 6). -
a[0]
se puede reescribir como*a
;a[1]
también se puede escribir como*(a + 1)
. El siguiente post de SO lo explica en detalle.
Espero que esto pueda contribuir a su tema.
El operador sizeof
es una de las pocas cosas que pueden distinguir entre una matriz (suponiendo que no sea un parámetro de función) y un puntero.
-
b
se reconoce como una matriz de 5 elementos donde cada uno es de 4 bytes, por lo quesizeof(b)
evalúa a 20. - La conversión convierte la matriz en un puntero de forma similar a como lo haría pasarla a una función. Así que el tamaño es 8.
- Esto no está realmente decayendo a un puntero. Es un puntero. Está tomando la dirección de un
int
, por lo que, por supuesto, el tipo esint *
. Al abordar uno de sus comentarios, todavía no es exacto decir que la expresión&b[0]
descompone en un puntero si lo pasa a una función, porque de hecho es un puntero, no una matriz. - Dado que
a
es un puntero a una matriz, el tamaño es el tamaño de un puntero, es decir, 8. Esto es diferente deint *c[2]
, que es una matriz de punteros y tendría el tamaño 16. -
a[0]
no es un puntero sino una matriz de tamaño 2 . La sintaxisa[0]
es equivalente a*(a + 0)
. Entonces, dado quea
es un puntero a una matriz, la anulación de la referenciaa
nos da una matriz. Dado que cada elemento tiene 4 bytes, el tamaño es 8. Sia
se definió comoint (*a)[3]
,sizeof(a[0])
evalúa como 12. - Similar al número 5,
a[1]
es una matriz de tamaño 2. Por lo tanto,sizeof(a[1])
evalúa como 8 porque es una matriz de 2 elementos de tamaño 4.
Un ejemplo de cómo usar a
es el siguiente:
int (*a)[2];
int d[3][2];
a=d;
d[0][0]=1;
d[0][1]=2;
d[1][0]=3;
d[1][1]=4;
d[2][0]=5;
d[3][1]=6;
printf("a00=%d/n",a[0][0]);
printf("a01=%d/n",a[0][1]);
printf("a10=%d/n",a[1][0]);
printf("a11=%d/n",a[1][1]);
printf("a20=%d/n",a[2][0]);
printf("a21=%d/n",a[3][1]);
Salida:
a00=1
a01=2
a10=3
a11=4
a20=5
a21=6
También usas esto cuando pasas una matriz 2D a una función:
void f(int (*a)[2])
{
...
}
int main()
{
int x[3][2];
f(x);
}