web-dev-qa-db-fra.com

Calculer la longueur d'un tableau en C

Je veux faire une fonction qui calcule la taille du tableau passé.

Je vais passer un tableau en entrée et il devrait retourner sa longueur. Je veux une fonction

int ArraySize(int * Array   /* Or int Array[] */)
{
   /* Calculate Length of Array and Return it */

}

void main()
{
  int MyArray[8]={1,2,3,0,5};
  int length;

  length=ArraySize(MyArray);

  printf("Size of Array: %d",length);

}

La longueur devrait être de 5 car il contient 5 éléments bien que sa taille soit de 8 (Même 8 fera l'affaire, mais 5 serait excellent)

J'ai essayé ceci:

int ArraySize(int * Array)
{

  return (sizeof(Array)/sizeof(int));

}

Cela ne fonctionnera pas car "sizeof(Array)" reviendra à la taille de Int Pointer. Cette opération "sizeof" ne fonctionne que si vous êtes dans la même fonction.

En fait, je suis de retour en C après plusieurs jours de C # donc je ne me souviens plus (et Array.Length() manquant__) 

Cordialement!

11
Swanand

Vous ne pouvez pas calculer la taille d'un tableau lorsque tout ce que vous avez est un pointeur.

La seule façon de rendre cette "fonction" est de définir une macro:

#define ARRAY_SIZE( array ) ( sizeof( array ) / sizeof( array[0] ) )

Cela vient avec toutes les mises en garde habituelles des macros, bien sûr.

Modifier: (Les commentaires ci-dessous appartiennent vraiment à la réponse ...)

  1. Vous ne pouvez pas déterminer le nombre d'éléments initialisés dans un tableau, sauf si vous initialisez tous les éléments à un " invalide "en premier et en comptant les valeurs" valides "manuellement. Si votre tableau a été défini comme ayant 8 éléments, pour le compilateur, il en a 8, que vous ayez initialisé seulement 5 d'entre eux ou non.
  2. Vous ne pouvez pas déterminer la taille d'un tableau au sein d'une fonction à laquelle ce tableau a été passé en tant que paramètre. Pas directement, pas à travers une macro, en aucune façon. Vous pouvez uniquement déterminer la taille d'un tableau dans l'étendue dans laquelle il a été déclaré .

L’impossibilité de déterminer la taille du tableau dans une fonction appelée peut être comprise une fois que vous vous rendez compte que sizeof() est un heure de compilation opérateur . Cela pourrait ressembler à un appel de fonction d'exécution, mais ce n'est pas: Le compilateur détermine la taille des opérandes et les insère en tant que constantes.

Dans l'étendue où le tableau est déclaré, le compilateur a l'information qu'il s'agit en fait d'un tableau et du nombre d'éléments dont il dispose.

Dans une fonction à laquelle le tableau est passé, tout ce que voit le compilateur est un pointeur. (Considérez que la fonction peut être appelée avec plusieurs différents tableaux, et rappelez-vous que sizeof() est un opérateur de compilation .

Vous pouvez basculer vers C++ et utiliser <vector>. Vous pouvez définir un struct vector plus fonctions le gérant, mais ce n'est pas vraiment confortable:

#include <stdlib.h>

typedef struct
{
    int *  _data;
    size_t _size;
} int_vector;

int_vector * create_int_vector( size_t size )
{
    int_vector * _vec = malloc( sizeof( int_vector ) );
    if ( _vec != NULL )
    {
        _vec._size = size;
        _vec._data = (int *)malloc( size * sizeof( int ) );
    }
    return _vec;
}

void destroy_int_vector( int_vector * _vec )
{
    free( _vec->_data );
    free( _vec );
}

int main()
{
    int_vector * myVector = create_int_vector( 8 );
    if ( myVector != NULL && myVector->_data != NULL )
    {
        myVector->_data[0] = ...;
        destroy_int_vector( myVector );
    }
    else if ( myVector != NULL )
    {
        free( myVector );
    }
    return 0;
}

En bout de ligne: les tableaux C sont limités. Vous ne pouvez pas calculer leur longueur dans une sous-fonction, période. Vous devez vous écarter de cette limitation ou utiliser un langage différent (comme le C++).

25
DevSolar

Vous ne pouvez pas faire cela une fois que le tableau est décomposé en un pointeur - vous obtiendrez toujours la taille du pointeur.

Ce que vous devez faire est soit:

  • utilisez si possible une valeur sentinelle, telle que NULL pour les pointeurs ou -1 pour les nombres positifs.
  • calculez-le lorsqu'il s'agit encore d'un tableau et transmettez cette taille à n'importe quelle fonction.
  • idem que ci-dessus mais en utilisant une macro magique funky
    #define arrSz(a) (sizeof(a)/sizeof(*a)).
  • créez votre propre type de données abstrait qui conserve la longueur en tant qu'élément d'une structure, de sorte que vous ayez un moyen d'obtenir votre Array.length().
11
paxdiablo

Ce que vous demandez ne peut tout simplement pas être fait. 

Au moment de l'exécution, la seule information mise à la disposition du programme sur un tableau est l'adresse de son premier élément. Même la taille des éléments n'est déduite que du contexte de type dans lequel le tableau est utilisé.

2
JeremyP
int getArraySize(void *x)
{
    char *p = (char *)x;
    char i = 0;
    char dynamic_char = 0xfd;
    char static_char = 0xcc;

    while(1)
    {
        if(p[i]==dynamic_char || p[i]==static_char)
            break;
        i++;
    }
    return i;
}

int _tmain(int argc, _TCHAR* argv[])
{   
    void *ptr = NULL;
    int array[]={1,2,3,4,5,6,7,8,9,0};
    char *str;
    int totalBytes;

    ptr = (char *)malloc(sizeof(int)*3);
    str = (char *)malloc(10);

    totalBytes = getArraySize(ptr);
    printf("ptr = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));

    totalBytes = getArraySize(array);
    printf("array = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));

    totalBytes = getArraySize(str);
    printf("str = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(char)));
    return 0;
}
1
Mayuresh Sawant

En C, vous ne pouvez pas, car un tableau se décompose en un pointeur (sur le premier élément) lorsqu'il est transmis à une fonction.

Toutefois, en C++, vous pouvez utiliser Déduction d’arguments de modèle pour obtenir le même résultat.

1
Prasoon Saurav

Vous devez soit passer la longueur en tant que paramètre supplémentaire (comme strncpy le fait) ou mettre le tableau à zéro (comme le fait strcpy). 

Il existe de petites variantes de ces techniques, comme regrouper la longueur avec le pointeur dans sa propre classe ou utiliser un marqueur différent pour la longueur du tableau, mais ce sont fondamentalement vos seuls choix.

1
Blindy

C'est très tard. Mais j'ai trouvé une solution de contournement pour ce problème. Je sais que ce n'est pas la bonne solution, mais peut fonctionner si vous ne voulez pas parcourir un tableau entier d'entiers. 

cocher '\ 0' ne fonctionnera pas ici

D'abord, mettez n'importe quel caractère dans un tableau au moment de l'initialisation

for(i=0;i<1000;i++)
array[i]='x';

puis, après avoir passé les valeurs, vérifiez 'x'

i=0;
while(array[i]!='x')
{
i++;
return i;
}

laissez-moi savoir s'il est utile.

0
nakul parashar

Pas possible. Vous devez passer la taille du tableau à partir de la fonction à partir de laquelle vous appelez cette fonction. Lorsque vous transmettez le tableau à la fonction, seule l'adresse de départ est transmise, et non la taille entière. Lorsque vous calculez la taille du tableau, le compilateur ne sait pas combien de taille/mémoire, ce pointeur a été alloué par le compilateur. Ainsi, le dernier appel est, vous devez passer la taille du tableau pendant que vous appelez cette fonction.

0
Ajay Kumar