¿Cómo determino el tamaño de mi matriz en C?
Es decir, ¿la cantidad de elementos que puede contener la matriz?
¿Cómo determino el tamaño de mi matriz en C?
Es decir, ¿la cantidad de elementos que puede contener la matriz?
Respuestas:
Resumen Ejecutivo:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Respuesta completa:
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
a
cambio 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);
ARRAYSIZE
makro definido en WinNT.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, por sizeof
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:
#include <stdio.h>
#include <stdlib.h>
void printSizeOf(int intArray[]);
void printLength(int intArray[]);
int main(int argc, char* argv[])
{
int array[] = { 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: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Salida (en un sistema operativo Windows de 32 bits):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
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.
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
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:
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(const void *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 foo
en 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.
sizeof(int)
Requiere menos instrucciones que sizeof(foo)
?
int x = 1+1;
versus int 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/103
int size = (&arr)[1] - arr;
Mira este enlace para una explicación
ptrdiff_t
. (Normalmente en un sistema de 64 bits, este será un tipo más grande que int
). Incluso si cambia int
a ptrdiff_t
este código, todavía tiene un error si arr
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:
len = sizeof(arr)/sizeof(arr[0])
Código originalmente encontrado aquí: programa C para encontrar el número de elementos en 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 int
para noofele
vs. size_t
, el tipo devuelto por sizeof()
.
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".
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Realmente evalúa como:
(sizeof (p + 1) / sizeof (p + 1[0]));
Mientras
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Evalúa correctamente a:
(sizeof (p + 1) / sizeof (p + 1)[0]);
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.
(sizeof (x) / sizeof (*x))
?
Para matrices multidimensionales es un poco más complicado. A menudo las personas definen constantes macro explícitas, es decir
#define g_rgDialogRows 2
#define g_rgDialogCols 7
static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
{ " ", " ", " ", " 494", " 210", " Generic Sample Dialog", " " },
{ " 1", " 330", " 174", " 88", " ", " OK", " " },
};
Pero estas constantes también se pueden evaluar en tiempo de compilación con sizeof :
#define rows_of_array(name) \
(sizeof(name ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name) \
(sizeof(name[0]) / sizeof(name[0][0]))
static char* g_rgDialog[][7] = { /* ... */ };
assert( rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);
Tenga en cuenta que este código funciona en C y C ++. Para matrices con más de dos dimensiones use
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
etc., ad infinitum.
sizeof(array) / sizeof(array[0])
array
tenga, no necesita usar sizeof(array) / sizeof(array[0])
si array
es una matriz de cualquiera de ellos char
, unsigned char
o 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 .
Tamaño de una matriz en C:
int a[10];
size_t size_of_array = sizeof(a); // Size of array a
int n = sizeof (a) / sizeof (a[0]); // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a
// Size of each element = size of type
size_t size_of_element
todavía int
con int 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 uso size_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 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.
TL; DR:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
must_be_array(arr)
(definido a continuación) SE necesita como -Wsizeof-pointer-div
está con errores (a partir de abril / 2020):
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
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 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:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
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.
Este es el más común, y muchas respuestas le han proporcionado la típica macro ARRAY_SIZE:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
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:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
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. Solo ARRAY_SIZE
y size_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:
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;
}
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):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
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 una sizeof(arr)
, pero con la seguridad adicional de la ARRAY_SIZE
construcción.
Ejemplo de uso:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
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:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-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 :
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_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.
__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.
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
__arraycount((arr)); \
} \
)
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
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.
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 0
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).
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
#define ARRAY_SIZE(arr) (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
sizeof(arr)
) que no se muestra en otra parte ARRAY_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:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
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 ints
vector<int> numbers;
// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
numbers.push_back(i);
// Determine the size of the array
cout << numbers.size();
enum
declaración.
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
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.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.
/* 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
*/
typedef struct MyType
{
int age;
char name[20];
} MyType;
typedef struct MyTypeArray
{
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. */
MyTypeArray array = new_MyTypeArray(2, arr);
/* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
print_MyType_names(array);
return 0;
}
strcpy(d.name, name);
sin manejar el desbordamiento.
La mejor manera es guardar esta información, por ejemplo, en una estructura:
typedef struct {
int *array;
int elements;
} list_s;
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.
int elements
frente size_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 el sizeof
tipo 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:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
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])));
return 0;
};
Aquí está la salida de muestra
1549216672
1549216712
---- diff----
4
The size of array a is 10
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_t
y, por lo tanto, imprimir con él z
puede conducir a UB. Simplemente usar printf("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 fijo a[10]
. sizeof(a)/sizeof(a[0])
se realiza constantemente en tiempo de compilación en este caso.
Una solución más elegante será
size_t size = sizeof(a) / sizeof(*a);
Además de las respuestas ya proporcionadas, quiero señalar un caso especial mediante el uso de
sizeof(a) / sizeof (a[0])
Si a
es una matriz de char
, unsigned char
o signed char
no necesita usar sizeof
dos veces, ya sizeof
que siempre resulta una expresión con un operando de estos tipos 1
.
Cita de C18,6.5.3.4 / 4:
" Cuando
sizeof
se aplica a un operando que tiene tipochar
,unsigned char
osigned char
, (o una versión calificada de la misma) el resultado es1
".
Por sizeof(a) / sizeof (a[0])
lo tanto, sería equivalente a NUMBER OF ARRAY ELEMENTS / 1
si a
es una matriz de tipo char
, unsigned char
o 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).
Nota: Este puede darle un comportamiento indefinido como lo señala MM en el comentario.
int a[10];
int size = (*(&a+1)-a) ;
*
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))