¿Hay una función estándar en C que devuelva la longitud de una matriz?

¿Hay una función estándar en C que devuelva la longitud de una matriz?

A menudo, la técnica descrita en otras respuestas se encapsula en una macro para que sea más fácil para los ojos. Algo como:

#define COUNT_OF( arr) (sizeof(arr)/sizeof(0[arr])) 

Tenga en cuenta que la macro anterior usa un pequeño truco para poner el nombre de la matriz en el operador de índice (‘ [] ‘) en lugar de 0 – esto se hace en caso de que la macro se use erróneamente en código C ++ con un elemento que sobrecarga al operator[]() . El comstackdor se quejará en lugar de dar un mal resultado.

Sin embargo, también tenga en cuenta que si pasa un puntero en lugar de una matriz, la macro dará silenciosamente un resultado negativo: este es uno de los principales problemas al usar esta técnica.

Recientemente comencé a usar una versión más compleja que robé de la base de código de Google Chromium:

 #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 

En esta versión, si un puntero se pasa erróneamente como argumento, el comstackdor se quejará en algunos casos, especialmente si el tamaño del puntero no es divisible de manera uniforme por el tamaño del objeto al que apunta el puntero. En esa situación, una división por cero hará que el comstackdor salga de error. En realidad, al menos un comstackdor que he usado da una advertencia en lugar de un error. No estoy seguro de qué genera para la expresión que tiene una división por cero en ella.

Ese macro no cierra la puerta al usarlo erróneamente, pero se acerca lo más posible que he visto en C.

Si desea una solución aún más segura para cuando trabaja en C ++, eche un vistazo al tiempo de comstackción sizeof_array sin usar una macro que describa un método basado en plantillas bastante complejo que Microsoft usa en winnt.h .

No no hay.

Para las matrices de tamaño constante puede usar el truco común que Andrew mencionó, sizeof(array) / sizeof(array[0]) – pero esto solo funciona en el ámbito en el que se declaró la matriz.
sizeof(array) te da el tamaño de toda la matriz, mientras que sizeof(array[0]) te da el tamaño del primer elemento.
Vea la respuesta de Michaels sobre cómo envolverlo en una macro.

Para las matrices asignadas dinámicamente, puede realizar un seguimiento del tamaño en un tipo integral o hacerlo terminado en 0 si es posible (es decir, asignar 1 elemento más y establecer el último elemento en 0).

 sizeof array / sizeof array[0] 

La cantidad de elementos en una matriz x se puede obtener de la siguiente manera:

 sizeof(x)/sizeof(x[0]) 

Debe tener en cuenta que las matrices, cuando se pasan a funciones, se degradan en punteros que no llevan la información de tamaño. En realidad, la información de tamaño nunca está disponible para el tiempo de ejecución ya que se calcula en tiempo de comstackción, pero puede actuar como si estuviera disponible donde la matriz es visible (es decir, donde no se ha degradado).

Cuando paso las matrices a una función que necesito tratar como matrices, siempre me aseguro de que se pasen dos argumentos:

  • la longitud de la matriz; y
  • el puntero a la matriz.

Entonces, aunque la matriz se puede tratar como una matriz donde se declara, se trata como un tamaño y un puntero en cualquier otro lugar.

Tiendo a tener código como:

 #define countof(x) (sizeof(x)/sizeof(x[0])) : : : int numbers[10]; a = fn (countof(numbers),numbers); 

entonces fn() tendrá la información de tamaño disponible para él.

Otro truco que he usado en el pasado (un poco más desordenado en mi opinión pero lo daré aquí para completarlo) es tener una matriz de una unión y hacer que el primer elemento tenga la longitud, algo así como:

 typedef union { int len; float number; } tNumber; tNumber number[10]; : : : number[0].len = 5; a = fn (number); 

entonces fn() puede acceder a la longitud y a todos los elementos y no tiene que preocuparse por la dicotomía matriz / puntero.

Esto tiene la ventaja adicional de permitir que la duración varíe (es decir, la cantidad de elementos en uso, no la cantidad de unidades asignadas). Pero tiendo a no usar esto más ya que considero mejor la versión de matriz de dos argumentos (tamaño y datos).

La respuesta simple, por supuesto, es no. Pero la respuesta práctica es “Necesito saber de todos modos”, así que analicemos los métodos para evitar esto.

Una forma de salirse con la suya por un tiempo, como se menciona un millón de veces, es con sizeof() :

 int i[] = {0, 1, 2}; ... size_t i_len = sizeof(i) / sizeof(i[0]); 

Esto funciona, hasta que intentemos pasarle a una función, o tomar un puntero a i . Entonces, ¿qué pasa con las soluciones más generales?

La solución general aceptada es pasar la longitud de la matriz a una función junto con la matriz. Vemos esto mucho en la biblioteca estándar:

 void *memcpy(void *s1, void *s2, size_t n); 

Copiará n bytes de s1 a s2 , lo que nos permitirá usar n para garantizar que nuestros buffers nunca se desborden. Esta es una buena estrategia: tiene una sobrecarga baja, y en realidad genera un código eficiente (compárelo con strcpy() , que debe verificar el final de la cadena y no tiene forma de “saber” cuántas iteraciones debe realizar, y el pobre y confuso strncpy() , que tiene que verificar ambos: ambos pueden ser más lentos y se puede acelerar usando memcpy() si por alguna razón ya has calculado la longitud de la cadena.

Otro enfoque es encapsular su código en una struct . El truco común es este:

 typedef struct _arr { size_t len; int arr[0]; } arr; 

Si queremos una matriz de longitud 5, hacemos esto:

 arr *a = malloc(sizeof(*a) + sizeof(int) * 5); a->len = 5; 

Sin embargo, este es un truco que solo está moderadamente bien definido (C99 le permite usar int arr[] ) y requiere mucha mano de obra. Una manera “mejor definida” de hacer esto es:

 typedef struct _arr { size_t len; int *arr; } arr; 

Pero luego nuestras asignaciones (y desasignaciones) se vuelven mucho más complicadas. El beneficio de cualquiera de estos enfoques es, por supuesto, que ahora las matrices que fabriques llevarán con ellas todo su scope. Es ligeramente menos eficiente con la memoria, pero es bastante seguro. Si elige una de estas rutas, asegúrese de escribir funciones auxiliares para que no tenga que asignar y desasignar manualmente (y trabajar con) estas estructuras.

Si tiene un objeto del tipo de matriz, la cantidad de elementos en la matriz se puede express como sizeof a / sizeof *a . Si permitía que su objeto de matriz decayera a tipo de puntero (o solo tenía un objeto de puntero para comenzar), entonces, en general, no hay forma de determinar la cantidad de elementos en la matriz.