Forum Programmation.c++ taille d'un tableau avec sizeof

Posté par  .
Étiquettes : aucune
0
23
mar.
2005
Je voudrais récuperer le nombre d'elements d'un tableau C++ declaré statiquement en passant par :
sizeof / sizeof 'type d'un element';

Mais le sizeof du tableau ne fonctionne plus une fois que je l'ai passe en paramètre d'une fonction.
Ou est le problème ?


#include

using namespace std;


int func(int array[], int* pointer)
{
int n1 = sizeof(array); // no, it isn't
int n2 = sizeof(pointer);
cout << "[]" << n1 << endl;
cout << "*" << n2 << endl;
return n1 - n2;
}

int main()
{
int v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << "local " << sizeof v << endl;
func (v, v);
return 0;
}


Résultat :

local 40
[]4
*4


desole pour le code illisible, j'ai pas réussi a faire mieux.
  • # Commentaire supprimé

    Posté par  . Évalué à 2.

    Ce commentaire a été supprimé par l’équipe de modération.

    • [^] # Re: Le paramètre de la fonction

      Posté par  . Évalué à 1.

      Ok,
      Ca explique que n1 = n2.

      Mais pourquoi n1 != 'sizeof v ' ?

      Mais surtout, est-il possible d'obtenir la taille réelle du tableau (40) depuis la fonction func ?
      • [^] # Commentaire supprimé

        Posté par  . Évalué à 4.

        Ce commentaire a été supprimé par l’équipe de modération.

      • [^] # Re: Le paramètre de la fonction

        Posté par  (site web personnel) . Évalué à 2.

        en fait, c'est plutôt le fait que gcc donne la "bonne" taille dans le main() qui est "surprenant"

        sizeof est un operator résolu à la compilation, donc rien d'étonnant à ce que sur des paramètres il ne puisse que donner la taille du pointeur.

        Je ne sais pas exactement comment gcc fait, mais il doit se souvenir que v n'est pas n'importe quel int*, mais celui initialisé juste au dessus.
        à noter que même dans le main(), un simple sizeof((int*)v) donne bien 4. (ce qui est heureux d'ailleurs :))

        En résumé, non il n'est pas possible d'obtenir 40 dans ta fonction sans retenir l'info quelque part.
        • [^] # Re: Le paramètre de la fonction

          Posté par  . Évalué à 0.

          en fait, c'est plutôt le fait que gcc donne la "bonne" taille dans le main() qui est "surprenant"

          je crois que c'est une fonctionnalité du c++
          que de renvoyer la bonne taille ( (indexmax+1) * sizeof(typeelement) )

          je l'avais oublié aussi en ayant passé trop de temps à
          faire du perl ou du c...
        • [^] # Re: Le paramètre de la fonction

          Posté par  . Évalué à 2.


          en fait, c'est plutôt le fait que gcc donne la "bonne" taille dans le main() qui est "surprenant"

          à l'intérieur du main, v est un tableau statique dont la taille a été déterminée à la compilation (déclaration en []). rien d'étonnant à ce que sizeof trouve le bon résultat. v se comporte alors comme un pointeur sur entier, mais ce n'est pas un pointeur sur entier, c'est un bon vieux tableau statique à taille fixe.
  • # vu que...

    Posté par  . Évalué à 2.

    vu que tu es en c++, pourquoi ne pas créer une classe
    de tableau enrichie de fonction de détermination de taille
    ou une variable d'instance stockant cette taille?
    • [^] # Re: vu que...

      Posté par  . Évalué à 2.

      Ou alors un bete std::vector<int> ?
      const unsigned int theSize = myVect.size();
      std::cout << "the size = " << theSize << std::endl;

      C'est du C++, alors pourquoi ne pas utiliser les classes qui sont deja la ?
      Sauf si le but est didactique, je ne vois pas trop l'interet de recoder une enieme classe de tableaux.
      • [^] # Re: vu que...

        Posté par  . Évalué à 1.

        Ou alors un bete std::vector ?

        bête ?!

        Je suis pas trop adepte de l'"obfuscated C++" (rapport au prefixe std::)
        ni des "vector" d'entier (template?) pour manipuler un tableau d'entiers...

        Je veux dire par là que j'aurais le défaut de réimplémenter
        une roue simple plutôt que d'utiliser l'arsenal multi-essieux
        que tu as apparemment la bonne habitude de manipuler...

        (ou encore que je n'utilise pas assez c++ pour faire ça :\ )
        • [^] # Re: vu que...

          Posté par  . Évalué à 4.

          Ben vector, c'est quand meme assez standard (d'ailleurs c'est dans la Standard Template Library ;).
          Ensuite dire que c'est du code obscure parce qu'il y a le namespace std qui est prefixe devant... c'est limite de la mauvaise foi : on peut toujours mettre un "using namespace std;" (soit dit en passant, mettre ce genre de chose dans un header, c'est mal, cela pollue l'espace de nommage des clients du code en question. Bon pour std c'est pas trop grave, c'est le standard mais c'est quand meme "bad practice")

          Je dis pas que c'est simple a utiliser *des le debut*, mais l'interface des conteneurs de la STL est assez homogene. Une fois bien familiarise avec un des conteneurs (vector<T> par exemple) on peut ensuite facilement utiliser les autres conteneurs avec un minimum de connaissances a acquerir en plus.

          De plus une fois qu'on a goute aux facilites de manipulation des conteneurs de la STL et surtout experimente un peu la panoplie d'algorithmes a notre disposition... Coder devient plus facile, plus concis et plus clair (donc moins de bugs?).

          Osons les classes de la STL partie integrante des built-ins de C++ :P
          • [^] # Re: vu que...

            Posté par  . Évalué à 1.

            J'espère que t'es content de toi maintenant !
            A cause de toi je vais encore passer des nuits blanches
            tout ça parce que tu m'as donné envie d'approfondir
            la stl !

            ralala, le corps il suit plus !
      • [^] # Re: vu que...

        Posté par  . Évalué à 1.

        Un merci global pour toutes vos réponse.

        En fait, je code justement a coder une classe Vecteur proche de vector.

        Je cherchais à autoriser une construction de la forme :

        Vecteur v( {1.0, 2.0)};
        ou bien Vecteur v( (double[]){1.0, 2.0)};

        et une affectation de la forme
        v= {1.0, 2.0);
        ou bien v = (double[]){1.0, 2.0);


        Mais si c'est pas possible, tant pis.

        Question subsidiaire, l'operateur delete[] se debrouille comment pour connaitre la taille de la mémoire a desallouer ? C'est au niveau du systeme (donc inaccessible) ?
        • [^] # Re: vu que...

          Posté par  . Évalué à 3.

          quand tu alloues un tableau statique de taille 10 par exemple, comme tu l'as fait, tu réserves la mémoire dans un endroit réservé que l'on appelle la pile.
          Tout objet créé ***statiquement*** (ie à la compilation) de cette manière sera automatiquement détruit lorsque tu sortiras de la portée ou il a été créé (au prochain '}' pour un objet local, lors d'une sortie de fonction pour une variable locale, lors de la sortie du programme pour une variable globale).

          Par contre pour stocker des grands tableaux (10, ça va je te rassure) ou pour des gros objets, il vaut mieux utiliser le tas, qui est prévu pour ça.

          Le tas permet de créer ***dynamiquement*** les objets, c'est-à-dire à la demande. Pour créer un tableau de taille 10 dynamiquement, tu feras un int* v = new int[10];
          Mais du coup il ne faut pas oublier de l'effacer, sinon il y aura des fuites mémoires : delete[] v;

          Dans le cas de la pile, la gestion mémoire est gérée par le système grace à une... pile (et oui), donc c'est très simple tu n'y peux rien. Par contre, dans le cas du tas le système gère la mémoire de manière plus compliquée (quels blocs ont été alloués avec quelle taille, quels blocs viennent d'être désalloués, quel est le prochain bloc libre, classement des blocs libres suivant leur taille et la fragmentation mémoire, etc...) mais la bonne nouvelle, c'est que si tu es ***très*** motivé, tu peux surcharger ce comportement et gérer toi même la mémoire, mais bon courage !

          Si ça t'intéresses, il n'y a qu'à surcharger les opérateurs ::new ::delete globaux ou bien les new delete propre à une classe donnée.
  • # Passage

    Posté par  . Évalué à 3.

    Dans le main, v "est" en fait un int[10], le int[] = {} est une facilité d'écriture.
    Mais un int[10] n'est pas une l-value, ni passable directement en paramètre.
    Par contre, int v[10] -> int v[] == int *v est possible
    (il suffit de prendre l'adresse du premier élément) et utilisé pour le passage de paramètres.

    L'exemple suivant affiche "size is obviously : 20\nnot so obviously : 4 ".


    namespace nSizeof
    {
    void func1(int faTruc[5])
    {
    // the [5] ne sert à rien
    cout << "not so obviously : " << sizeof(*faTruc) << endl;
    }

    void func5(int (*faTruc)[5])
    {
    cout << "size is obviously : " << sizeof(*faTruc) << endl;
    }

    bool doTest()
    {
    int lDummy = 5;
    int laTab5[] = {1,2,3,4,5};
    func5(&laTab5);
    func1(laTab5);
    //int laTab5_2[5];
    //laTab5_2 = laTab5; // not a l-value
    //laTab5_2 = (int*)laTab5; // no conversion to array types
    //laTab5 = &lDummy; // idem
    return true;
    }
    };

    int main()
    {
    nSizeof::doTest();
    return 0;
    }


    indent :(

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.