Para determinar el tamaño de su matriz en bytes, puede usar el sizeof
operador:
int a[17];size_t n =sizeof(a);
En mi computadora, los ints tienen 4 bytes de largo, entonces n es 68.
Para determinar el número de elementos en la matriz, podemos dividir el tamaño total de la matriz por el tamaño del elemento de la matriz. Podrías hacer esto con el tipo, así:
int a[17];size_t n =sizeof(a)/sizeof(int);
y obtener la respuesta adecuada (68/4 = 17), pero si el tipo de
acambio tuvieras un error desagradable si también olvidaras cambiarlo sizeof(int).
Entonces el divisor preferido es sizeof(a[0])o el equivalente sizeof(*a), el tamaño del primer elemento de la matriz.
int a[17];size_t n =sizeof(a)/sizeof(a[0]);
Otra ventaja es que ahora puede parametrizar fácilmente el nombre de la matriz en una macro y obtener:
#define NELEMS(x)(sizeof(x)/sizeof((x)[0]))int a[17];size_t n = NELEMS(a);
El código generado será idéntico, ya que el compilador conoce el tipo de * int_arr en tiempo de compilación (y, por lo tanto, el valor de sizeof (* int_arr)). Será una constante, y el compilador puede optimizar en consecuencia.
Mark Harrison
10
Debería ser el caso con todos los compiladores, ya que los resultados de sizeof se definen como una constante de tiempo de compilación.
Mark Harrison
451
Importante : ¡No dejes de leer aquí, lee la siguiente respuesta! Esto solo funciona para matrices en la pila , por ejemplo, si está usando malloc () o accediendo a un parámetro de función, no tiene suerte. Vea abajo.
Markus
77
Para la programación de API de Windows en C o C ++, existe el ARRAYSIZEmakro definido en WinNT.h(que se obtiene de otros encabezados). Por lo tanto, los usuarios de WinAPI no necesitan definir su propio makro.
Lumi
17
@ Markus funciona para cualquier variable que tenga un tipo de matriz; esto no tiene que estar "en la pila". Por ej static int a[20];. Pero su comentario es útil para los lectores que pueden no darse cuenta de la diferencia entre una matriz y un puntero.
MM
808
El sizeofcamino es el correcto si se trata de matrices no recibidas como parámetros. Una matriz enviada como parámetro a una función se trata como un puntero, por sizeoflo que devolverá el tamaño del puntero, en lugar de la matriz.
Por lo tanto, las funciones internas de este método no funcionan. En su lugar, siempre pase un parámetro adicional que size_t sizeindique el número de elementos en la matriz.
Prueba:
#include<stdio.h>#include<stdlib.h>void printSizeOf(int intArray[]);void printLength(int intArray[]);int main(int argc,char* argv[]){intarray[]={0,1,2,3,4,5,6};
printf("sizeof of array: %d\n",(int)sizeof(array));
printSizeOf(array);
printf("Length of array: %d\n",(int)(sizeof(array)/sizeof(array[0])));
printLength(array);}void printSizeOf(int intArray[]){
printf("sizeof of parameter: %d\n",(int)sizeof(intArray));}void printLength(int intArray[]){
printf("Length of parameter: %d\n",(int)(sizeof(intArray)/sizeof(intArray[0])));}
Salida (en un sistema operativo Linux de 64 bits):
sizeof of array:28sizeof of parameter:8Length of array:7Length of parameter:2
Salida (en un sistema operativo Windows de 32 bits):
sizeof of array:28sizeof of parameter:4Length of array:7Length of parameter:1
¿por qué length of parameter:2si solo se pasa un puntero al primer elemento de matriz?
Bbvarghe
16
@Bbvarghe Eso se debe a que los punteros en los sistemas de 64 bits tienen 8 bytes (sizeof (intArray)), pero los ints aún tienen (generalmente) 4 bytes de longitud (sizeof (intArray [0])).
Elideb
13
@Pacerier: no hay un código correcto; la solución habitual es pasar la longitud junto con la matriz como un argumento separado.
Jean Hominal
10
Espera, ¿no hay forma de acceder a la matriz directamente desde un puntero y ver su tamaño? Nuevo en C aquí.
sudo
77
@ Michael Trouw: puede utilizar la sintaxis de operador si se hace sentir mejor: (sizeof array / sizeof *array).
chqrlie
134
Vale la pena señalar que eso sizeofno ayuda cuando se trata de un valor de matriz que se ha descompuesto en un puntero: aunque apunta al comienzo de una matriz, para el compilador es lo mismo que un puntero a un solo elemento de esa matriz . Un puntero no "recuerda" nada más sobre la matriz que se usó para inicializarlo.
int a[10];int* p = a;
assert(sizeof(a)/sizeof(a[0])==10);
assert(sizeof(p)==sizeof(int*));
assert(sizeof(*p)==sizeof(int));
@ Magnus: el estándar define sizeof como el rendimiento del número de bytes en el objeto y ese sizeof (char) es siempre uno. El número de bits en un byte es específico de la implementación. Editar: ANSI C ++ sección estándar 5.3.3 Sizeof: "El operador sizeof produce el número de bytes en la representación de objeto de su operando. Sizeof (char), sizeof (char con signo) y sizeof (char sin signo) son 1; el resultado de sizeof aplicado a cualquier otro tipo fundamental está definido por la implementación ".
Skizz
Sección 1.6 El modelo de memoria C ++: "La unidad de almacenamiento fundamental en el modelo de memoria C ++ es el byte. Un byte es al menos lo suficientemente grande como para contener cualquier miembro del conjunto de caracteres de ejecución básica y está compuesto por una secuencia contigua de bits, el número de los cuales está definido por la implementación ".
Skizz
2
Recuerdo que el CRAY tenía C con char32 bits. Todo lo que dice el estándar es que se pueden representar valores enteros de 0 a 127, y su rango es al menos -127 a 127 (char está firmado) o 0 a 255 (char no está firmado).
vonbrand 01 de
55
Esta es una excelente respuesta. Quiero comentar que todas las afirmaciones anteriores se evalúan como VERDADERAS.
Javad
49
El tamaño del "truco" es la mejor manera que conozco, con un cambio pequeño pero importante (para mí, esto es una gran molestia) en el uso de paréntesis.
Como deja en claro la entrada de Wikipedia, C sizeofno es una función; Es un operador . Por lo tanto, no requiere paréntesis alrededor de su argumento, a menos que el argumento sea un nombre de tipo. Esto es fácil de recordar, ya que hace que el argumento parezca una expresión emitida, que también usa paréntesis.
Entonces: si tiene lo siguiente:
int myArray[10];
Puede encontrar la cantidad de elementos con un código como este:
size_t n =sizeof myArray /sizeof*myArray;
Eso, para mí, se lee mucho más fácil que la alternativa con paréntesis. También estoy a favor del uso del asterisco en la parte derecha de la división, ya que es más conciso que la indexación.
Por supuesto, todo esto es tiempo de compilación también, por lo que no hay necesidad de preocuparse por la división que afecta el rendimiento del programa. Utilice este formulario siempre que pueda.
Siempre es mejor usar sizeof en un objeto real cuando tiene uno, en lugar de un tipo, ya que no necesita preocuparse por cometer un error y decir el tipo incorrecto.
Por ejemplo, supongamos que tiene una función que genera algunos datos como una secuencia de bytes, por ejemplo, a través de una red. Llamemos a la función send()y hagamos que tome como argumentos un puntero al objeto a enviar y el número de bytes en el objeto. Entonces, el prototipo se convierte en:
void send(constvoid*object,size_t size);
Y luego debes enviar un número entero, así que codifícalo así:
int foo =4711;
send(&foo,sizeof(int));
Ahora, ha introducido una forma sutil de dispararse en el pie, especificando el tipo de fooen dos lugares. Si uno cambia pero el otro no, el código se rompe. Por lo tanto, siempre hazlo así:
send(&foo,sizeof foo);
Ahora estás protegido. Claro, duplica el nombre de la variable, pero eso tiene una alta probabilidad de romperse de una manera que el compilador puede detectar, si la cambia.
Por cierto, ¿son instrucciones idénticas a nivel de procesador? ¿ sizeof(int)Requiere menos instrucciones que sizeof(foo)?
Pacerier
@Pacerier: no, son idénticos. Piensa en int x = 1+1;versus int x = (1+1);. Aquí, los paréntesis son puramente estéticos.
quetzalcoatl
@Aidiakapi Eso no es cierto, considere los VLA C99.
Descansa el
@unwind Gracias, estoy corregido. Para corregir mi comentario, sizeofsiempre será constante en C ++ y C89. Con las matrices de longitud variable de C99, se puede evaluar en tiempo de ejecución.
Aidiakapi
2
sizeofpuede ser un operador, pero debe tratarse como una función de acuerdo con Linus Torvalds. Estoy de acuerdo. Lea su racional aquí: lkml.org/lkml/2012/7/11/103
Nitpick pequeño: el resultado de la resta del puntero tiene tipo ptrdiff_t. (Normalmente en un sistema de 64 bits, este será un tipo más grande que int). Incluso si cambia inta ptrdiff_teste código, todavía tiene un error si arrocupa más de la mitad del espacio de direcciones.
MM
2
@MM Otro pequeño detalle: Dependiendo de la arquitectura de su sistema, el espacio de direcciones no es tan grande como el tamaño del puntero en la mayoría de los sistemas. Windows, por ejemplo, limita el espacio de direcciones para aplicaciones de 64 bits a 8 TB o 44 bits. Entonces, incluso si tiene una matriz más grande que la mitad de su espacio de direcciones 4.1TB, por ejemplo, no será un error. Solo si su espacio de direcciones supera los 63 bits en esos sistemas, es posible incluso encontrar dicho error. En general, no te preocupes por eso.
Aidiakapi
1
@Aidiakapi en Linux x86 de 32 bits o en Windows con la /3Gopción de que tenga división de usuario / núcleo 3G / 1G, lo que le permite tener un tamaño de matriz de hasta el 75% del tamaño del espacio de direcciones.
Ruslan
1
Considerar foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];como variables globales. buf3[]la declaración falla ya (&buf1)[1] - buf1que no es una constante.
chux - Restablece a Mónica
2
Este es un comportamiento técnicamente indefinido ya que el estándar no permite explícitamente la desreferenciación más allá del final de una matriz (incluso si no intenta leer el valor almacenado)
MM
26
Puede usar el operador sizeof pero no funcionará para las funciones porque tomará la referencia del puntero. Puede hacer lo siguiente para encontrar la longitud de una matriz:
Si conoce el tipo de datos de la matriz, puede usar algo como:
int arr[]={23,12,423,43,21,43,65,76,22};int noofele =sizeof(arr)/sizeof(int);
O si no conoce el tipo de datos de la matriz, puede usar algo como:
noofele =sizeof(arr)/sizeof(arr[0]);
Nota: Esto solo funciona si la matriz no está definida en tiempo de ejecución (como malloc) y la matriz no se pasa en una función. En ambos casos, arr(nombre de matriz) es un puntero.
int noofele = sizeof(arr)/sizeof(int);es solo hasta la mitad mejor que la codificación int noofele = 9;. El uso sizeof(arr)mantiene la flexibilidad en caso de que cambie el tamaño de la matriz. Sin embargo, sizeof(int)necesita una actualización si el tipo de arr[]cambio. Mejor usar sizeof(arr)/sizeof(arr[0])incluso si el tipo es bien conocido. No está claro por qué usar intpara noofelevs. size_t, el tipo devuelto por sizeof().
chux - Restablece a Monica
19
La macro de la ARRAYELEMENTCOUNT(x)que todos hacen uso se evalúa incorrectamente . Esto, de manera realista, es solo una cuestión delicada, porque no puede tener expresiones que den como resultado un tipo de "matriz".
Esto realmente no tiene mucho que ver con el tamaño de las matrices explícitamente. Acabo de notar muchos errores al no observar realmente cómo funciona el preprocesador C. Siempre envuelve el parámetro macro, no puede estar involucrada una expresión.
Esto es correcto; Mi ejemplo fue malo. Pero eso es exactamente lo que debería suceder. Como mencioné anteriormente p + 1, terminará como un tipo de puntero e invalidará toda la macro (al igual que si intentara usar la macro en una función con un parámetro de puntero).
Al final del día, en este caso particular , la falla realmente no importa (así que solo estoy perdiendo el tiempo de todos; ¡huzzah!), Porque no tienes expresiones con un tipo de 'matriz'. Pero realmente el punto sobre la evaluación del preprocesador es sutil, creo que es importante.
Gracias por la explicación. La versión original produce un error en tiempo de compilación. Clang informa que "el valor suscrito no es una matriz, puntero o vector". Este comportamiento parece preferible en este caso, aunque sus comentarios sobre el orden de evaluación en macros están bien tomados.
Mark Harrison
1
No había pensado en la queja del compilador como una notificación automática de un tipo incorrecto. ¡Gracias!
3
¿Hay alguna razón para no usar (sizeof (x) / sizeof (*x))?
seriousdev
16
Para matrices multidimensionales es un poco más complicado. A menudo las personas definen constantes macro explícitas, es decir
Dependiendo del tipo que arraytenga, no necesita usar sizeof(array) / sizeof(array[0])si arrayes una matriz de cualquiera de ellos char, unsigned charo signed char- Cita de C18,6.5.3.4 / 4: "Cuando sizeof se aplica a un operando que tiene el tipo char, unsigned char o firmado char , (o una versión calificada del mismo) el resultado es 1. " En este caso, simplemente puede hacer lo sizeof(array)que se explica en mi respuesta dedicada .
RobertS apoya a Monica Cellio el
15
Tamaño de una matriz en C:
int a[10];size_t size_of_array =sizeof(a);// Size of array aint n =sizeof(a)/sizeof(a[0]);// Number of elements in array asize_t size_of_element =sizeof(a[0]);// Size of each element in array a // Size of each element = size of type
Curioso que el código utilizado size_t size_of_elementtodavía intcon int n = sizeof (a) / sizeof (a[0]); nosize_t n = sizeof (a) / sizeof (a[0]);
Chux - Restablecer Monica
1
Hola @Yogeesh HT, ¿puedes responder a la duda de chux? También tengo mucha curiosidad por saber cómo int n = sizeof (a) / sizeof (a [0]) está dando la longitud de la matriz y por qué no estamos usando size_t para la longitud de la matriz. ¿Alguien puede responder?
Cerebro
1
@Brain sizeof (a) da el tamaño de todos los elementos presentes en la matriz a sizeof (a [0]) da el tamaño de los primeros elementos. Supongamos que a = {1,2,3,4,5}; sizeof (a) = 20bytes (si sizeof (int) = 4bytes multiplica 5), sizeof (a [0]) = 4bytes, entonces 20/4 = 5 es decir, sin elementos
Yogeesh HT
2
@YogeeshHT Para matrices muy grandes como char a[INT_MAX + 1u];, int ncomo se usa en, int n = sizeof (a) / sizeof (a[0]);es insuficiente (es UB). El uso size_t n = sizeof (a) / sizeof (a[0]);no incurre en este problema.
chux - Restablece a Monica
13
Aconsejaría nunca usar sizeof(incluso si se puede usar) para obtener cualquiera de los dos tamaños diferentes de una matriz, ya sea en número de elementos o en bytes, que son los dos últimos casos que muestro aquí. Para cada uno de los dos tamaños, las macros que se muestran a continuación se pueden usar para hacerlo más seguro. La razón es hacer obvia la intención del código para los mantenedores, y la diferencia con sizeof(ptr)respecto sizeof(arr)a primera vista (lo que está escrito de esta manera no es obvio), de modo que los errores son obvios para todos los que leen el código.
No estoy de acuerdo con la solución que proporciona Linus, que es nunca usar la notación de matriz para los parámetros de las funciones.
Me gusta la notación de matriz como documentación de que se está utilizando un puntero como matriz. Pero eso significa que se debe aplicar una solución infalible para que sea imposible escribir código con errores.
De una matriz tenemos tres tamaños que podríamos querer saber:
El tamaño de los elementos de la matriz.
El número de elementos en la matriz.
El tamaño en bytes que la matriz usa en la memoria
El tamaño de los elementos de la matriz.
El primero es muy simple, y no importa si estamos tratando con una matriz o un puntero, porque se hace de la misma manera.
qsort() necesita este valor como su tercer argumento.
Para los otros dos tamaños, que son el tema de la pregunta, queremos asegurarnos de que estamos tratando con una matriz, y romper la compilación si no, porque si estamos tratando con un puntero, obtendremos valores incorrectos . Cuando la compilación se interrumpe, podremos ver fácilmente que no estábamos tratando con una matriz, sino con un puntero, y solo tendremos que escribir el código con una variable o una macro que almacena el tamaño de la matriz. matriz detrás del puntero.
El número de elementos en la matriz.
Este es el más común, y muchas respuestas le han proporcionado la típica macro ARRAY_SIZE:
Dado que el resultado de ARRAY_SIZE se usa comúnmente con variables de tipo con signo ptrdiff_t, es bueno definir una variante con signo de esta macro:
Las matrices con más de PTRDIFF_MAXmiembros darán valores no válidos para esta versión firmada de la macro, pero al leer C17 :: 6.5.6.9, matrices como esa ya están jugando con fuego. Solo ARRAY_SIZEy size_tdebe usarse en esos casos.
Las versiones recientes de compiladores, como GCC 8, le avisarán cuando aplique esta macro a un puntero, por lo que es seguro (existen otros métodos para hacerlo seguro con compiladores más antiguos).
Funciona dividiendo el tamaño en bytes de toda la matriz por el tamaño de cada elemento.
Ejemplos de uso:
void foo(ptrdiff_t nmemb){char buf[nmemb];
fgets(buf, ARRAY_SIZE(buf), stdin);}void bar(ptrdiff_t nmemb){int arr[nmemb];for(ptrdiff_t i =0; i < ARRAY_SSIZE(arr); i++)
arr[i]= i;}
Si estas funciones no usaran matrices, sino que las obtuvieron como parámetros, el código anterior no se compilaría, por lo que sería imposible tener un error (dado que se usa una versión reciente del compilador o que se usa algún otro truco) , y necesitamos reemplazar la llamada de macro por el valor:
void foo(ptrdiff_t nmemb,char buf[nmemb]){
fgets(buf, nmemb, stdin);}void bar(ptrdiff_t nmemb,int arr[nmemb]){for(ptrdiff_t i =0; i < nmemb; i++)
arr[i]= i;}
El tamaño en bytes que la matriz usa en la memoria
ARRAY_SIZE se usa comúnmente como una solución al caso anterior, pero este caso rara vez se escribe de manera segura, tal vez porque es menos común.
La forma común de obtener este valor es usar sizeof(arr). El problema: el mismo que el anterior; Si tiene un puntero en lugar de una matriz, su programa se volverá loco.
La solución al problema consiste en usar la misma macro que antes, que sabemos que es segura (rompe la compilación si se aplica a un puntero):
Cómo funciona es muy simple: deshace la división que lo ARRAY_SIZEhace, por lo que después de las cancelaciones matemáticas terminas con solo una sizeof(arr), pero con la seguridad adicional de la ARRAY_SIZEconstrucción.
Hoy descubrí que la nueva advertencia en GCC solo funciona si la macro se define en un encabezado que no es un encabezado del sistema. Si define la macro en un encabezado que está instalado en su sistema (generalmente /usr/local/include/o /usr/include/) ( #include <foo.h>), el compilador NO emitirá una advertencia (probé GCC 9.3.0).
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a),typeof(b))#define is_array(a)(!is_same_type((a),&(a)[0]))#defineStatic_assert_array(a)_Static_assert(is_array(a),"Not a `[]` !")#define ARRAY_SIZE(arr)( \
{ \
Static_assert_array(arr); \
sizeof(arr)/sizeof((arr)[0]); \
} \
)
Ahora ARRAY_SIZE()es completamente seguro y, por lo tanto, todos sus derivados estarán seguros.
Actualización: libbsd proporciona __arraycount():
Libbsd ofrece la macro __arraycount()en <sys/cdefs.h>, lo que no es seguro porque carece de un par de paréntesis, pero podemos añadir esos paréntesis, a nosotros mismos, y por lo tanto ni siquiera necesita para escribir la división en nuestra cabecera (¿por qué habríamos de duplicar el código que ya existe? ) Esa macro se define en un encabezado del sistema, por lo que si la usamos nos vemos obligados a usar las macros anteriores.
Algunos sistemas proporcionan nitems()en su <sys/param.h>lugar, y algunos sistemas proporcionan ambos. Debe verificar su sistema y usar el que tiene, y tal vez usar algunos condicionales de preprocesador para portabilidad y soporte para ambos.
Actualización: Permita que la macro se use en el alcance del archivo:
Desafortunadamente, la ({})extensión gcc no se puede usar en el alcance del archivo. Para poder usar la macro en el ámbito del archivo, la aserción estática debe estar dentro sizeof(struct {}). Luego, multiplíquelo por 0para no afectar el resultado. Una conversión a (int)podría ser buena para simular una función que devuelve (int)0(en este caso no es necesario, pero luego es reutilizable para otras cosas).
¿Te importaría explicar por qué el voto negativo? Este muestra una solución a una construcción inseguro y común ( sizeof(arr)) que no se muestra en otra parte ARRAY_BYTES(arr).
Cacahuete Frito
2
ARRAY_SIZE es lo suficientemente común como para usarse libremente, y ARRAY_BYTES es muy explícito en su nombre, debe definirse junto a ARRAY_SIZE para que un usuario pueda ver ambos fácilmente, y por su uso, no creo que nadie que lea el código tenga dudas sobre qué lo hace. Lo que quise decir es no usar un simple sizeof, sino usar estas construcciones en su lugar; si tiene ganas de escribir estas construcciones cada vez, es probable que cometa un error (muy común si copia pegar, y también muy común si las escribe cada vez porque tienen muchos paréntesis) ...
Cacahuete Frito
3
..., así que estoy en la conclusión principal: una sola sizeofes claramente insegura (las razones están en la respuesta), y no usar macros sino usar las construcciones que proporcioné, cada vez es aún más inseguro, por lo que la única forma de hacerlo es macros
Cacahuete Frito
3
@ MarkHarrison Sé la diferencia entre punteros y matrices. Pero ha habido ocasiones en que tuve una función que luego refactoricé en pequeñas funciones, y lo que primero fue una matriz, luego fue un puntero, y ese es un punto en el que si olvidas cambiar el tamaño de, lo atornillas, y es fácil no verlo uno de esos.
Cacahuete Frito
3
@hyde También sé que la diferencia no significa que todos sepan la diferencia, y ¿por qué no usar algo que básicamente elimine el 100% de esos errores? Ese error casi llegó a Linux; llegó a Linus, lo que significa que pasó mucho escrutinio, y también significa que existe la posibilidad de que el mismo error haya llegado a Linux en otra parte del núcleo, como él dice.
Cacahuete Frito
11
"has introducido una forma sutil de dispararte en el pie"
Las matrices C 'nativas' no almacenan su tamaño. Por lo tanto, se recomienda guardar la longitud de la matriz en una variable / constante separada y pasarla cada vez que pase la matriz, es decir:
Siempre DEBE evitar las matrices nativas (a menos que no pueda, en cuyo caso, cuidar su pie) Si está escribiendo C ++, use el contenedor 'vector' de STL . "En comparación con las matrices, proporcionan casi el mismo rendimiento", ¡y son mucho más útiles!
// vector is a template, the <int> means it is a vector of intsvector<int> numbers;// push_back() puts a new value at the end (or back) of the vectorfor(int i =0; i <10; i++)
numbers.push_back(i);// Determine the size of the array
cout << numbers.size();
Tenga en cuenta que esto solo funciona para matrices reales, no para punteros que apuntan a matrices.
David Schwartz
5
Si realmente desea hacer esto para pasar su matriz, sugiero implementar una estructura para almacenar un puntero al tipo del que desea una matriz y un número entero que represente el tamaño de la matriz. Entonces puedes pasar eso a tus funciones. Simplemente asigne el valor de la variable de matriz (puntero al primer elemento) a ese puntero. Luego puede ir Array.arr[i]a obtener el elemento i-ésimo y usarlo Array.sizepara obtener el número de elementos en la matriz.
Incluí un código para ti. No es muy útil, pero podría ampliarlo con más funciones. Sin embargo, para ser sincero, si estas son las cosas que desea, debe dejar de usar C y usar otro lenguaje con estas funciones integradas.
/* Absolutely no one should use this...
By the time you're done implementing it you'll wish you just passed around
an array and size to your functions *//* This is a static implementation. You can get a dynamic implementation and
cut out the array in main by using the stdlib memory allocation methods,
but it will work much slower since it will store your array on the heap */#include<stdio.h>#include<string.h>/*
#include "MyTypeArray.h"
*//* MyTypeArray.h
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/typedefstructMyType{int age;char name[20];}MyType;typedefstructMyTypeArray{int size;MyType*arr;}MyTypeArray;MyType new_MyType(int age,char*name);MyTypeArray newMyTypeArray(int size,MyType*first);/*
#endif
End MyTypeArray.h *//* MyTypeArray.c */MyType new_MyType(int age,char*name){MyType d;
d.age = age;
strcpy(d.name, name);return d;}MyTypeArray new_MyTypeArray(int size,MyType*first){MyTypeArray d;
d.size = size;
d.arr = first;return d;}/* End MyTypeArray.c */void print_MyType_names(MyTypeArray d){int i;for(i =0; i < d.size; i++){
printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);}}int main(){/* First create an array on the stack to store our elements in.
Note we could create an empty array with a size instead and
set the elements later. */MyType arr[]={new_MyType(10,"Sam"), new_MyType(3,"Baxter")};/* Now create a "MyTypeArray" which will use the array we just
created internally. Really it will just store the value of the pointer
"arr". Here we are manually setting the size. You can use the sizeof
trick here instead if you're sure it will work with your compiler. */MyTypeArrayarray= new_MyTypeArray(2, arr);/* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
print_MyType_names(array);return0;}
Cualquier razón de int elementsfrente size_t elements?
chux - Restablece a Monica
3
La función sizeofdevuelve el número de bytes que utiliza su matriz en la memoria. Si desea calcular el número de elementos en su matriz, debe dividir ese número con el sizeoftipo de variable de la matriz. Digamos que int array[10];si el entero de tipo variable en su computadora es de 32 bits (o 4 bytes), para obtener el tamaño de su matriz, debe hacer lo siguiente:
Puedes usar el &operador. Aquí está el código fuente:
#include<stdio.h>#include<stdlib.h>int main(){int a[10];int*p;
printf("%p\n",(void*)a);
printf("%p\n",(void*)(&a+1));
printf("---- diff----\n");
printf("%zu\n",sizeof(a[0]));
printf("The size of array a is %zu\n",((char*)(&a+1)-(char*)a)/(sizeof(a[0])));return0;};
Aquí está la salida de muestra
15492166721549216712---- diff----4The size of array a is 10
No voté en contra, pero esto es como golpear un clavo con un ladrillo porque no notaste un martillo a tu lado. Además, las personas tienden a fruncir el ceño al usar variables no inicializadas ... pero aquí supongo que sirve a su propósito lo suficientemente bien.
Dmitri
2
@Dmitri no se accede a variables no inicializadas aquí
MM
1
Hmmm La sustracción del puntero conduce a ptrdiff_t. sizeof()resultados en size_t. C no define cuál es más ancho o más alto / mismo rango. Por lo tanto, el tipo de cociente ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))no es seguro size_ty, por lo tanto, imprimir con él zpuede conducir a UB. Simplemente usar printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);es suficiente.
chux - Restablece a Monica
1
(char *)(&a+1)-(char *)ano es una constante y puede calcularse en tiempo de ejecución, incluso con un tamaño fijo a[10]. sizeof(a)/sizeof(a[0])se realiza constantemente en tiempo de compilación en este caso.
Además de las respuestas ya proporcionadas, quiero señalar un caso especial mediante el uso de
sizeof(a)/sizeof(a[0])
Si aes una matriz de char, unsigned charo signed charno necesita usar sizeofdos veces, ya sizeofque siempre resulta una expresión con un operando de estos tipos 1.
Cita de C18,6.5.3.4 / 4:
" Cuando sizeofse aplica a un operando que tiene tipo char, unsigned charo signed char, (o una versión calificada de la misma) el resultado es 1".
Por sizeof(a) / sizeof (a[0])lo tanto, sería equivalente a NUMBER OF ARRAY ELEMENTS / 1si aes una matriz de tipo char, unsigned charo signed char. La división a través de 1 es redundante.
En este caso, simplemente puede abreviar y hacer:
sizeof(a)
Por ejemplo:
char a[10];size_t length =sizeof(a);
Si desea una prueba, aquí hay un enlace a GodBolt .
No obstante, la división mantiene la seguridad, si el tipo cambia significativamente (aunque estos casos son raros).
Probablemente prefiera seguir aplicando una macro con la división, porque el tipo puede cambiar en el futuro (aunque tal vez sea poco probable), y la división se conoce en el momento de la compilación, por lo que el compilador la optimizará (si no lo hace, cambie tu compilador).
Cacahuete Frito
1
@CacahueteFrito Sí, mientras tanto, también he pensado en eso. Lo tomé como una nota al margen de la respuesta. Gracias.
RobertS apoya a Monica Cellio el
-1
Nota: Este puede darle un comportamiento indefinido como lo señala MM en el comentario.
Este es un comportamiento técnicamente indefinido; el *operador no se puede aplicar a un puntero pasado-fin
MM
3
"comportamiento indefinido" significa que el Estándar C no define el comportamiento. Si lo intentas en tu programa, entonces puede pasar cualquier cosa
MM
@MM, ¿estás diciendo que *(&a+1) - a;es diferente al (&a)[1] - a;anterior, no ambos *(&a+1)y (&a)[1]cuentan como 1 más allá del final?
QuentinUK
@QuentinUK sus dos expresiones son las mismas, x[y]se define como*(x + (y))
MM
@ MM, creo que sí. Pero la otra respuesta, por Arjun Sreedharan, tiene 38 flechas hacia arriba y esta tiene -1. Y la respuesta de Arjun Sreedharan no menciona el comportamiento indefinido.
Respuestas:
Resumen Ejecutivo:
Respuesta completa:
Para determinar el tamaño de su matriz en bytes, puede usar el
sizeof
operador:En mi computadora, los ints tienen 4 bytes de largo, entonces n es 68.
Para determinar el número de elementos en la matriz, podemos dividir el tamaño total de la matriz por el tamaño del elemento de la matriz. Podrías hacer esto con el tipo, así:
y obtener la respuesta adecuada (68/4 = 17), pero si el tipo de
a
cambio tuvieras un error desagradable si también olvidaras cambiarlosizeof(int)
.Entonces el divisor preferido es
sizeof(a[0])
o el equivalentesizeof(*a)
, el tamaño del primer elemento de la matriz.Otra ventaja es que ahora puede parametrizar fácilmente el nombre de la matriz en una macro y obtener:
fuente
ARRAYSIZE
makro definido enWinNT.h
(que se obtiene de otros encabezados). Por lo tanto, los usuarios de WinAPI no necesitan definir su propio makro.static int a[20];
. Pero su comentario es útil para los lectores que pueden no darse cuenta de la diferencia entre una matriz y un puntero.El
sizeof
camino es el correcto si se trata de matrices no recibidas como parámetros. Una matriz enviada como parámetro a una función se trata como un puntero, porsizeof
lo que devolverá el tamaño del puntero, en lugar de la matriz.Por lo tanto, las funciones internas de este método no funcionan. En su lugar, siempre pase un parámetro adicional que
size_t size
indique el número de elementos en la matriz.Prueba:
Salida (en un sistema operativo Linux de 64 bits):
Salida (en un sistema operativo Windows de 32 bits):
fuente
length of parameter:2
si solo se pasa un puntero al primer elemento de matriz?(sizeof array / sizeof *array)
.Vale la pena señalar que eso
sizeof
no ayuda cuando se trata de un valor de matriz que se ha descompuesto en un puntero: aunque apunta al comienzo de una matriz, para el compilador es lo mismo que un puntero a un solo elemento de esa matriz . Un puntero no "recuerda" nada más sobre la matriz que se usó para inicializarlo.fuente
char
32 bits. Todo lo que dice el estándar es que se pueden representar valores enteros de 0 a 127, y su rango es al menos -127 a 127 (char está firmado) o 0 a 255 (char no está firmado).El tamaño del "truco" es la mejor manera que conozco, con un cambio pequeño pero importante (para mí, esto es una gran molestia) en el uso de paréntesis.
Como deja en claro la entrada de Wikipedia, C
sizeof
no es una función; Es un operador . Por lo tanto, no requiere paréntesis alrededor de su argumento, a menos que el argumento sea un nombre de tipo. Esto es fácil de recordar, ya que hace que el argumento parezca una expresión emitida, que también usa paréntesis.Entonces: si tiene lo siguiente:
Puede encontrar la cantidad de elementos con un código como este:
Eso, para mí, se lee mucho más fácil que la alternativa con paréntesis. También estoy a favor del uso del asterisco en la parte derecha de la división, ya que es más conciso que la indexación.
Por supuesto, todo esto es tiempo de compilación también, por lo que no hay necesidad de preocuparse por la división que afecta el rendimiento del programa. Utilice este formulario siempre que pueda.
Siempre es mejor usar sizeof en un objeto real cuando tiene uno, en lugar de un tipo, ya que no necesita preocuparse por cometer un error y decir el tipo incorrecto.
Por ejemplo, supongamos que tiene una función que genera algunos datos como una secuencia de bytes, por ejemplo, a través de una red. Llamemos a la función
send()
y hagamos que tome como argumentos un puntero al objeto a enviar y el número de bytes en el objeto. Entonces, el prototipo se convierte en:Y luego debes enviar un número entero, así que codifícalo así:
Ahora, ha introducido una forma sutil de dispararse en el pie, especificando el tipo de
foo
en dos lugares. Si uno cambia pero el otro no, el código se rompe. Por lo tanto, siempre hazlo así:Ahora estás protegido. Claro, duplica el nombre de la variable, pero eso tiene una alta probabilidad de romperse de una manera que el compilador puede detectar, si la cambia.
fuente
sizeof(int)
Requiere menos instrucciones quesizeof(foo)
?int x = 1+1;
versusint x = (1+1);
. Aquí, los paréntesis son puramente estéticos.sizeof
siempre será constante en C ++ y C89. Con las matrices de longitud variable de C99, se puede evaluar en tiempo de ejecución.sizeof
puede ser un operador, pero debe tratarse como una función de acuerdo con Linus Torvalds. Estoy de acuerdo. Lea su racional aquí: lkml.org/lkml/2012/7/11/103Mira este enlace para una explicación
fuente
ptrdiff_t
. (Normalmente en un sistema de 64 bits, este será un tipo más grande queint
). Incluso si cambiaint
aptrdiff_t
este código, todavía tiene un error siarr
ocupa más de la mitad del espacio de direcciones./3G
opción de que tenga división de usuario / núcleo 3G / 1G, lo que le permite tener un tamaño de matriz de hasta el 75% del tamaño del espacio de direcciones.foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
como variables globales.buf3[]
la declaración falla ya(&buf1)[1] - buf1
que no es una constante.Puede usar el operador sizeof pero no funcionará para las funciones porque tomará la referencia del puntero. Puede hacer lo siguiente para encontrar la longitud de una matriz:
Código originalmente encontrado aquí: programa C para encontrar el número de elementos en una matriz
fuente
Si conoce el tipo de datos de la matriz, puede usar algo como:
O si no conoce el tipo de datos de la matriz, puede usar algo como:
Nota: Esto solo funciona si la matriz no está definida en tiempo de ejecución (como malloc) y la matriz no se pasa en una función. En ambos casos,
arr
(nombre de matriz) es un puntero.fuente
int noofele = sizeof(arr)/sizeof(int);
es solo hasta la mitad mejor que la codificaciónint noofele = 9;
. El usosizeof(arr)
mantiene la flexibilidad en caso de que cambie el tamaño de la matriz. Sin embargo,sizeof(int)
necesita una actualización si el tipo dearr[]
cambio. Mejor usarsizeof(arr)/sizeof(arr[0])
incluso si el tipo es bien conocido. No está claro por qué usarint
paranoofele
vs.size_t
, el tipo devuelto porsizeof()
.La macro de la
ARRAYELEMENTCOUNT(x)
que todos hacen uso se evalúa incorrectamente . Esto, de manera realista, es solo una cuestión delicada, porque no puede tener expresiones que den como resultado un tipo de "matriz".Realmente evalúa como:
Mientras
Evalúa correctamente a:
Esto realmente no tiene mucho que ver con el tamaño de las matrices explícitamente. Acabo de notar muchos errores al no observar realmente cómo funciona el preprocesador C. Siempre envuelve el parámetro macro, no puede estar involucrada una expresión.
Esto es correcto; Mi ejemplo fue malo. Pero eso es exactamente lo que debería suceder. Como mencioné anteriormente
p + 1
, terminará como un tipo de puntero e invalidará toda la macro (al igual que si intentara usar la macro en una función con un parámetro de puntero).Al final del día, en este caso particular , la falla realmente no importa (así que solo estoy perdiendo el tiempo de todos; ¡huzzah!), Porque no tienes expresiones con un tipo de 'matriz'. Pero realmente el punto sobre la evaluación del preprocesador es sutil, creo que es importante.
fuente
(sizeof (x) / sizeof (*x))
?Para matrices multidimensionales es un poco más complicado. A menudo las personas definen constantes macro explícitas, es decir
Pero estas constantes también se pueden evaluar en tiempo de compilación con sizeof :
Tenga en cuenta que este código funciona en C y C ++. Para matrices con más de dos dimensiones use
etc., ad infinitum.
fuente
fuente
array
tenga, no necesita usarsizeof(array) / sizeof(array[0])
siarray
es una matriz de cualquiera de elloschar
,unsigned char
osigned char
- Cita de C18,6.5.3.4 / 4: "Cuando sizeof se aplica a un operando que tiene el tipo char, unsigned char o firmado char , (o una versión calificada del mismo) el resultado es 1. " En este caso, simplemente puede hacer losizeof(array)
que se explica en mi respuesta dedicada .Tamaño de una matriz en C:
fuente
size_t size_of_element
todavíaint
conint n = sizeof (a) / sizeof (a[0]);
nosize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
,int n
como se usa en,int n = sizeof (a) / sizeof (a[0]);
es insuficiente (es UB). El usosize_t n = sizeof (a) / sizeof (a[0]);
no incurre en este problema.Aconsejaría nunca usar
sizeof
(incluso si se puede usar) para obtener cualquiera de los dos tamaños diferentes de una matriz, ya sea en número de elementos o en bytes, que son los dos últimos casos que muestro aquí. Para cada uno de los dos tamaños, las macros que se muestran a continuación se pueden usar para hacerlo más seguro. La razón es hacer obvia la intención del código para los mantenedores, y la diferencia consizeof(ptr)
respectosizeof(arr)
a primera vista (lo que está escrito de esta manera no es obvio), de modo que los errores son obvios para todos los que leen el código.TL; DR:
must_be_array(arr)
(definido a continuación) SE necesita como-Wsizeof-pointer-div
está con errores (a partir de abril / 2020):Ha habido errores importantes con respecto a este tema: https://lkml.org/lkml/2015/9/3/428
No estoy de acuerdo con la solución que proporciona Linus, que es nunca usar la notación de matriz para los parámetros de las funciones.
Me gusta la notación de matriz como documentación de que se está utilizando un puntero como matriz. Pero eso significa que se debe aplicar una solución infalible para que sea imposible escribir código con errores.
De una matriz tenemos tres tamaños que podríamos querer saber:
El tamaño de los elementos de la matriz.
El primero es muy simple, y no importa si estamos tratando con una matriz o un puntero, porque se hace de la misma manera.
Ejemplo de uso:
qsort()
necesita este valor como su tercer argumento.Para los otros dos tamaños, que son el tema de la pregunta, queremos asegurarnos de que estamos tratando con una matriz, y romper la compilación si no, porque si estamos tratando con un puntero, obtendremos valores incorrectos . Cuando la compilación se interrumpe, podremos ver fácilmente que no estábamos tratando con una matriz, sino con un puntero, y solo tendremos que escribir el código con una variable o una macro que almacena el tamaño de la matriz. matriz detrás del puntero.
El número de elementos en la matriz.
Este es el más común, y muchas respuestas le han proporcionado la típica macro ARRAY_SIZE:
Dado que el resultado de ARRAY_SIZE se usa comúnmente con variables de tipo con signo
ptrdiff_t
, es bueno definir una variante con signo de esta macro:Las matrices con más de
PTRDIFF_MAX
miembros darán valores no válidos para esta versión firmada de la macro, pero al leer C17 :: 6.5.6.9, matrices como esa ya están jugando con fuego. SoloARRAY_SIZE
ysize_t
debe usarse en esos casos.Las versiones recientes de compiladores, como GCC 8, le avisarán cuando aplique esta macro a un puntero, por lo que es seguro (existen otros métodos para hacerlo seguro con compiladores más antiguos).
Funciona dividiendo el tamaño en bytes de toda la matriz por el tamaño de cada elemento.
Ejemplos de uso:
Si estas funciones no usaran matrices, sino que las obtuvieron como parámetros, el código anterior no se compilaría, por lo que sería imposible tener un error (dado que se usa una versión reciente del compilador o que se usa algún otro truco) , y necesitamos reemplazar la llamada de macro por el valor:
El tamaño en bytes que la matriz usa en la memoria
ARRAY_SIZE
se usa comúnmente como una solución al caso anterior, pero este caso rara vez se escribe de manera segura, tal vez porque es menos común.La forma común de obtener este valor es usar
sizeof(arr)
. El problema: el mismo que el anterior; Si tiene un puntero en lugar de una matriz, su programa se volverá loco.La solución al problema consiste en usar la misma macro que antes, que sabemos que es segura (rompe la compilación si se aplica a un puntero):
Cómo funciona es muy simple: deshace la división que lo
ARRAY_SIZE
hace, por lo que después de las cancelaciones matemáticas terminas con solo unasizeof(arr)
, pero con la seguridad adicional de laARRAY_SIZE
construcción.Ejemplo de uso:
memset()
necesita este valor como su tercer argumento.Como antes, si la matriz se recibe como un parámetro (un puntero), no se compilará, y tendremos que reemplazar la llamada de macro por el valor:
Actualización (23 / abr / 2020):
-Wsizeof-pointer-div
tiene errores :Hoy descubrí que la nueva advertencia en GCC solo funciona si la macro se define en un encabezado que no es un encabezado del sistema. Si define la macro en un encabezado que está instalado en su sistema (generalmente
/usr/local/include/
o/usr/include/
) (#include <foo.h>
), el compilador NO emitirá una advertencia (probé GCC 9.3.0).Entonces tenemos
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
y queremos hacerlo seguro. Necesitaremos C11_Static_assert()
y algunas extensiones de GCC: declaraciones y declaraciones en expresiones , __builtin_types_compatible_p :Ahora
ARRAY_SIZE()
es completamente seguro y, por lo tanto, todos sus derivados estarán seguros.Actualización: libbsd proporciona
__arraycount()
:Libbsd ofrece la macro
__arraycount()
en<sys/cdefs.h>
, lo que no es seguro porque carece de un par de paréntesis, pero podemos añadir esos paréntesis, a nosotros mismos, y por lo tanto ni siquiera necesita para escribir la división en nuestra cabecera (¿por qué habríamos de duplicar el código que ya existe? ) Esa macro se define en un encabezado del sistema, por lo que si la usamos nos vemos obligados a usar las macros anteriores.Algunos sistemas proporcionan
nitems()
en su<sys/param.h>
lugar, y algunos sistemas proporcionan ambos. Debe verificar su sistema y usar el que tiene, y tal vez usar algunos condicionales de preprocesador para portabilidad y soporte para ambos.Actualización: Permita que la macro se use en el alcance del archivo:
Desafortunadamente, la
({})
extensión gcc no se puede usar en el alcance del archivo. Para poder usar la macro en el ámbito del archivo, la aserción estática debe estar dentrosizeof(struct {})
. Luego, multiplíquelo por0
para no afectar el resultado. Una conversión a(int)
podría ser buena para simular una función que devuelve(int)0
(en este caso no es necesario, pero luego es reutilizable para otras cosas).fuente
sizeof(arr)
) que no se muestra en otra parteARRAY_BYTES(arr)
.sizeof
, sino usar estas construcciones en su lugar; si tiene ganas de escribir estas construcciones cada vez, es probable que cometa un error (muy común si copia pegar, y también muy común si las escribe cada vez porque tienen muchos paréntesis) ...sizeof
es claramente insegura (las razones están en la respuesta), y no usar macros sino usar las construcciones que proporcioné, cada vez es aún más inseguro, por lo que la única forma de hacerlo es macros"has introducido una forma sutil de dispararte en el pie"
Las matrices C 'nativas' no almacenan su tamaño. Por lo tanto, se recomienda guardar la longitud de la matriz en una variable / constante separada y pasarla cada vez que pase la matriz, es decir:
Siempre DEBE evitar las matrices nativas (a menos que no pueda, en cuyo caso, cuidar su pie) Si está escribiendo C ++, use el contenedor 'vector' de STL . "En comparación con las matrices, proporcionan casi el mismo rendimiento", ¡y son mucho más útiles!
Ver: http://www.cplusplus.com/reference/stl/vector/
fuente
enum
declaración.fuente
Si realmente desea hacer esto para pasar su matriz, sugiero implementar una estructura para almacenar un puntero al tipo del que desea una matriz y un número entero que represente el tamaño de la matriz. Entonces puedes pasar eso a tus funciones. Simplemente asigne el valor de la variable de matriz (puntero al primer elemento) a ese puntero. Luego puede ir
Array.arr[i]
a obtener el elemento i-ésimo y usarloArray.size
para obtener el número de elementos en la matriz.Incluí un código para ti. No es muy útil, pero podría ampliarlo con más funciones. Sin embargo, para ser sincero, si estas son las cosas que desea, debe dejar de usar C y usar otro lenguaje con estas funciones integradas.
fuente
strcpy(d.name, name);
sin manejar el desbordamiento.La mejor manera es guardar esta información, por ejemplo, en una estructura:
Implemente todas las funciones necesarias, como crear, destruir, verificar la igualdad y todo lo que necesite. Es más fácil pasar como parámetro.
fuente
int elements
frentesize_t elements
?La función
sizeof
devuelve el número de bytes que utiliza su matriz en la memoria. Si desea calcular el número de elementos en su matriz, debe dividir ese número con elsizeof
tipo de variable de la matriz. Digamos queint array[10];
si el entero de tipo variable en su computadora es de 32 bits (o 4 bytes), para obtener el tamaño de su matriz, debe hacer lo siguiente:fuente
Puedes usar el
&
operador. Aquí está el código fuente:Aquí está la salida de muestra
fuente
ptrdiff_t
.sizeof()
resultados ensize_t
. C no define cuál es más ancho o más alto / mismo rango. Por lo tanto, el tipo de cociente((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
no es segurosize_t
y, por lo tanto, imprimir con élz
puede conducir a UB. Simplemente usarprintf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
es suficiente.(char *)(&a+1)-(char *)a
no es una constante y puede calcularse en tiempo de ejecución, incluso con un tamaño fijoa[10]
.sizeof(a)/sizeof(a[0])
se realiza constantemente en tiempo de compilación en este caso.La respuesta más simple:
fuente
Una solución más elegante será
fuente
Además de las respuestas ya proporcionadas, quiero señalar un caso especial mediante el uso de
Si
a
es una matriz dechar
,unsigned char
osigned char
no necesita usarsizeof
dos veces, yasizeof
que siempre resulta una expresión con un operando de estos tipos1
.Cita de C18,6.5.3.4 / 4:
Por
sizeof(a) / sizeof (a[0])
lo tanto, sería equivalente aNUMBER OF ARRAY ELEMENTS / 1
sia
es una matriz de tipochar
,unsigned char
osigned char
. La división a través de 1 es redundante.En este caso, simplemente puede abreviar y hacer:
Por ejemplo:
Si desea una prueba, aquí hay un enlace a GodBolt .
No obstante, la división mantiene la seguridad, si el tipo cambia significativamente (aunque estos casos son raros).
fuente
Nota: Este puede darle un comportamiento indefinido como lo señala MM en el comentario.
Para más detalles ver aquí y también aquí .
fuente
*
operador no se puede aplicar a un puntero pasado-fin*(&a+1) - a;
es diferente al(&a)[1] - a;
anterior, no ambos*(&a+1)
y(&a)[1]
cuentan como 1 más allá del final?x[y]
se define como*(x + (y))