Longitud de la matriz en el argumento de la función

Este es un código bien conocido para calcular la longitud de la matriz en C:

sizeof(array)/sizeof(type) 

Pero no puedo encontrar la longitud de la matriz pasada como argumento para una función:

 #include  int length(const char* array[]) { return sizeof(array)/sizeof(char*); } int main() { const char* friends[] = { "John", "Jack", "Jim" }; printf("%d %d", sizeof(friends)/sizeof(char*), length(friends)); // 3 1 } 

Supongo que esa matriz se copia por valor al argumento de la función, ya que el puntero constante y la referencia a ella deberían resolver esto, pero esta statement no es válida:

 int length(const char**& array); 

Considero que pasar la longitud de la matriz como segundo argumento es información redundante, pero ¿por qué la statement estándar de main así:

 int main(int argc, char** argv); 

Explique si es posible determinar la longitud de la matriz en el argumento de la función, y si es así, ¿por qué existe la redundancia en main ?


sizeof solo funciona para encontrar la longitud de la matriz si la aplicas a la matriz original.

 int a[5]; //real array. NOT a pointer sizeof(a); // :) 

Sin embargo, en el momento en que la matriz decaiga en un puntero, sizeof dará el tamaño del puntero y no de la matriz.

 int a[5]; int * p = a; sizeof(p); // :( 

Como ya ha señalado inteligentemente, main recibe la longitud de la matriz como argumento (argc). Sí, esto es por necesidad y no es redundante . (Bueno, es una especie de reduntant ya que argv está convenientemente terminado por un puntero nulo, pero estoy divagando)

Hay algunos razonamientos sobre por qué esto tendría lugar. ¿Cómo podríamos hacer las cosas para que una matriz C también conozca su longitud?

Una primera idea sería no tener matrices decayendo en punteros cuando se pasan a una función y continuar manteniendo la longitud de la matriz en el sistema de tipos. Lo malo de esto es que necesitarías tener una función separada para cada longitud de matriz posible y hacerlo no es una buena idea. (Pascal hizo esto y algunas personas piensan que esta es una de las razones por las que “perdió” a C)

Una segunda idea es almacenar la longitud de la matriz al lado de la matriz, tal como lo hace cualquier lenguaje de progtwigción moderno:

 a -> [5];[0,0,0,0,0] 

Pero luego estás creando una struct invisible detrás de escena y la filosofía C no aprueba este tipo de sobrecarga. Dicho esto, crear una estructura de este tipo a menudo es una buena idea para algunos tipos de problemas:

 struct { size_t length; int * elements; } 

Otra cosa que puedes pensar es cómo las cadenas en C son terminadas en nulo en lugar de almacenar una longitud (como en Pascal). Para almacenar una longitud sin preocuparse por los límites, se necesitan cuatro bytes, una cantidad inimaginablemente cara (al menos en aquel entonces). Uno podría preguntarse si las matrices también podrían terminar así, pero ¿cómo permitirías que la matriz almacenara un nulo?

La matriz se desintegra a un puntero cuando se pasa.

La sección 6.4 de las preguntas frecuentes de C lo cubre muy bien y proporciona las referencias de K & R, etc.


Aparte de eso, imagine que era posible que la función conociera el tamaño de la memoria asignada en un puntero. Puede llamar a la función dos o más veces, cada vez con diferentes matrices de entrada que son longitudes potencialmente diferentes; por lo tanto, la longitud tendría que pasarse como una variable secreta oculta de alguna manera. Y luego considere si transfirió en una compensación a otra matriz, o una matriz asignada en el montón ( malloc y todas son funciones de biblioteca, algo a lo que el comstackdor vincula, en lugar de ver y razonar sobre el cuerpo de).

Es cada vez más difícil imaginar cómo podría funcionar esto sin algunos objetos de corte entre bastidores y cosas así, ¿verdad?


Symbian tenía una función AllocSize() que devolvía el tamaño de una asignación con malloc() ; esto solo funcionó para el puntero literal devuelto por el malloc, y obtendrías gobbledygook o un locking si le pedías que supiera el tamaño de un puntero no válido o un desplazamiento de puntero desde uno.

No quieres creer que no es posible, pero realmente no lo es. La única manera de saber la longitud de algo pasado a una función es hacer un seguimiento de la longitud y pasarla a usted mismo como un parámetro explícito separado.

Según lo indicado por @Will, la disminución ocurre durante el paso del parámetro. Una forma de evitarlo es pasar la cantidad de elementos. Para agregarlo, es posible que la macro _countof() útil: equivale a lo que has hecho;

En primer lugar, un mejor uso para calcular el número de elementos cuando la statement de matriz real está en el scope es:

 sizeof array / sizeof array[0] 

De esta forma no repetirá el nombre del tipo, que por supuesto podría cambiar en la statement y hacer que termine con un cálculo de longitud incorrecto. Este es un caso típico de no te repitas .

En segundo lugar, como un punto menor, tenga en cuenta que sizeof no es una función, por lo que la expresión anterior no necesita ningún paréntesis alrededor del argumento de sizeof .

En tercer lugar, C no tiene referencias, por lo que su uso de & en una statement no funcionará.

Estoy de acuerdo en que la solución C adecuada es pasar la longitud (usando el tipo size_t ) como un argumento separado, y usar sizeof en el lugar donde se realiza la llamada si el argumento es una matriz “real”.

Tenga en cuenta que a menudo trabaja con memoria devuelta, por ejemplo, malloc() , y en esos casos nunca tiene una matriz “verdadera” para calcular el tamaño, por lo que diseñar la función para usar un conteo de elementos es más flexible.

En cuanto a int main ():

De acuerdo con el Estándar, argv apunta a una matriz con terminación NULL (de punteros a cadenas terminadas en nulo). (5.1.2.2.1: 1).

Es decir, argv = (char **){ argv[0], ..., argv[argc - 1], 0 }; .

Por lo tanto, el cálculo de tamaño se realiza mediante una función que es una modificación trivial de strlen() .

argc está solo allí para hacer el cálculo de longitud argv O (1).

El método count-until-NULL NO funcionará para la entrada de matriz genérica. Tendrá que especificar manualmente el tamaño como un segundo argumento.

Esta es una vieja pregunta, y el OP parece mezclar C ++ y C en sus intenciones / ejemplos. En C, cuando pasas una matriz a una función, se descompone en puntero. Por lo tanto, no hay forma de pasar el tamaño de la matriz, excepto mediante el uso de un segundo argumento en la función que almacena el tamaño de la matriz:

 void func(int A[]) // should be instead: void func(int * A, const size_t elemCountInA) 

Son muy pocos los casos en los que no es necesario, como cuando usa matrices multidimensionales:

 void func(int A[3][whatever here]) // That's almost as if read "int* A[3]" 

El uso de la notación de matriz en una firma de función sigue siendo útil para el desarrollador, ya que podría ser una ayuda saber cuántos elementos esperan sus funciones. Por ejemplo:

 void vec_add(float out[3], float in0[3], float in1[3]) 

es más fácil de entender que este (aunque, nada impide el acceso al 4º elemento en la función en ambas funciones):

 void vec_add(float * out, float * in0, float * in1) 

Si tuviera que usar C ++, entonces puede capturar el tamaño de la matriz y obtener lo que espera:

 template  void vec_add(float (&out)[N], float (&in0)[N], float (&in1)[N]) { for (size_t i = 0; i < N; i++) out[i] = in0[i] + in1[i]; } 

En ese caso, el comstackdor se asegurará de que no está agregando un vector 4D con un vector 2D (que no es posible en C sin pasar la dimensión de cada dimensión como argumentos de la función). Habrá tantas instancias de la función vec_add como la cantidad de dimensiones utilizadas para sus vectores.

 int arsize(int st1[]) { int i = 0; for (i; !(st1[i] & (1 << 30)); i++); return i; } 

Esto funciona para mí 🙂

El mejor ejemplo está aquí

gracias #define TAMAÑO 10

 void size(int arr[SIZE]) { printf("size of array is:%d\n",sizeof(arr)); } int main() { int arr[SIZE]; size(arr); return 0; }