IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion :

Comment allouer dynamiquement un tableau ?

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut Comment allouer dynamiquement un tableau ?
    Bonjour à tous,

    je vous explique mon besoin, je voudrai avoir un tableau de "double" de X éléments (au début du programme X est connu (par un define)).
    La déclaration de ce tableau doit être global.
    Bien sur, je veux que ce tableau soit accessible en écriture/lecture par élément.
    Et pourquoi dynamique, parce que j'ai un champ dans lequel j'entre une valeur, et cette valeur correspond à la taille de ma structure, ce qui veut dire que dès que je commence à changer la valeur de mon champ, la taille de mon tableau change "en live".

    Voilà, j'espère avoir été clair.

    Merci d'avance

  2. #2
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut
    Je vais m'auto-répondre, j'ai utilisé un QVector, de la manière suivante :

    Pour les déclarations:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      QVector<double> vector(DEFINE_SIZE);
      double *dDataVector = vector.data();
      int iIndexVector = 0;
    Pour l'utilisation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // Redefinir la taille
    vector.resize(NEW_SIZE);
    ....
    // Sauvegarder une valeur à l'index en cours
    dDataVector[iIndexVector] = dValue;
    En espérant que ça puisse aider quelqu'un

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Tu n'as aucun besoin de passer par un pointeur : un std::vector<double> suffit amplement, vu que std::vector représente, justement, la notion de tableau d'éléments contigus en mémoire.

    Si, pour une raison ou une autre -- qu'il faudra vraiment me justifier très sérieusement vu que tu travailles avec Qt, tu as besoin de récupérer ces informations sous la forme d'un tableau C style (double *), tu peux effectivement passer par la fonction membre data() pour l'obtenir.

    Mais attention! tu ne peux pas te contenter de récupérer ce pointeur une fois au début du programme, même si tu lui donne une taille minimale à ce moment là, car tu dois partir du principe qu'à chaque fois que tu vas ajouter / supprimer un élément de ton tableau, std::vector va sans doute réallouer un espace mémoire "plus adapté" au nombre d'éléments qu'ils contient, surtout si ce nombre se met subitement à excéder le maximum que tu as prévu.

    Le pointeur que tu obtiens avec cette fonction membre n'est donc valable qu'entre deux instruction d'ajout ou de suppression d'élément

    Enfin, pourquoi voudrais tu définir la taille maximale par un #define

    Primo, define, c'est de la saloperie! utilises de préférence un static const size_t MAX_SIZE= xxx ou, mieux encore, vu que l'on est en 2019, un static constexpr size_t MAX_SIZE= xxxSecundo, std::vector est parfaitement en mesure de gérer par lui même sa propre taille. Pourquoi voudrais tu choisir arbitrairement une taille qui -- par sa nature arbitraire -- risque fort de ne pas suffire à l'usage (qu'est ce qui t'empêche, au cours de l'exécution, d'essayer d'obtenir MAX_SIZE +1 élément Et surtout, pourquoi voudrais tu empêcher (chose que tu ne pourras pas faire) std::vector de contenir plus d'éléments que ta limite arbitraire

    Généralement, lorsque l'on impose une limite arbitraire, c'est, justement, pour créer un tableau de taille fixe, clairement connue à la compilation. Mais pourquoi vouloir avoir recours à la taille fixe lorsqu'une taille variable est parfaitement utilisable (ou, du moins, alors que tu n'a rien dit qui puisse m'inciter à croire que tu as absolument besoin de la taille fixe), et présentera en outre de nombreux avantages (comme le fait de s'assurer que tous les éléments accessibles en mémoire soient bel et bien utilisés et existent en mémoire)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut
    Salut Loala01,

    merci pour ta réponse, mais je t'avouerai que je n'ai pas tout compris. Bon déjà pour planter le décor, je suis novice en Qt Creator, et surtout je viens du monde du C, alors déjà le passage au C++, se fait dans la douleur et en plus avec la couche Qt, c'est encore moins facile

    Voici mon besoin, j'ai besoin d'un tableau d'une certaine dimension au départ, mais la taille de celui-ci peut évoluer, mais il n'y a pas de maximum à sa taille. Donc pour ne pas bloquer de la mémoire pour rien, je ne veux pas mettre une dimension énorme en me disant que peut être, éventuellement, un jour on aura besoin d'une grande taille mémoire.

    D'où l'utilisation du pointeur sur un vector.

    Aurais-tu un exemple de code à me montrer comment je pourrai faire cela ?

    Autre question, pourquoi dis tu que le #define est à proscrire ? et qu'apporte un static const size_t MAX_SIZE= xxx ou, static constexpr size_t MAX_SIZE= xxx par rapport au define ?

    Merci d'avance

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    merci pour ta réponse, mais je t'avouerai que je n'ai pas tout compris. Bon déjà pour planter le décor, je suis novice en Qt Creator, et surtout je viens du monde du C,
    Bon, alors, on va faire simple : une variable du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<double> allDoubles; //tu l'appelles comme tu veux, bien sur
    va faire automatiquement pour toit tout ce que tu aurais du faire toi-même avec ton pointeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double * alldoubles;// j'ai pris le même nom par facilité
    pour gérer correctement la taille du tableau en C; la facilité et la sécurité en plus:
    • la taille et la capacité sont connues et gérées de manière indépendante : tu peux t'arranger pour que ton tableau puisse contenir plus d'éléments que ce qu'il n'en contient à un instant T, si tu sais qu'il devra en contenir un certain nombre au final, pour t'éviter d'avoir à réallouer un espace supplémentaire à chaque insertion
    • la gestion de la mémoire se fait de manière tout à fait automatique et parfaitement sécurisée : la capacité est augmentée quand c'est nécessaire, la mémoire est libérée quand le tableau est détruit, et tout ce que tu peux imaginer entre les deux
    • tu disposes de la notion d'itérateurs, qui te permet de parcourir les éléments de manière totalement indépendante de la manière dont ils sont représentés en mémoire, et qui permet la même chose pour les liste, les piles, les files et autres structures dynamiques
    • tu peux à n'importe quel moment obtenir une information de taille (le nombre d'éléments que ton tableau contient) et de capacité (le nombre d'éléments qu'il peut contenir avant de devoir allouer de l'espace supplémentaire)
    • tu disposes de fonctions qui automatisent l'ajout (en fin de tableau), l'insertion (entre deux éléments) et la suppression d'éléments
    • tu peux copier ton tableau de manière sécurisante (les deux copies évolueront de manière indépendante), comparer deux tableaux contenant des éléments de même type, transmettre le tableau sous forme de référence
    • la const correctness est respectée : si tu transmet le tableau sous forme de référence constante, le compilateur t'engueulera si tu essaye d'en modifier le contenu
    • j'en passe, et sans doute de meilleures.


    alors déjà le passage au C++, se fait dans la douleur et en plus avec la couche Qt, c'est encore moins facile
    Hummpfff... Je comprends parfaitement ton souhait d'utiliser Qt, et je ne le remets pas en cause.

    Seulement, il faut savoir marcher avant de vouloir courir ! Or, on ne programme pas en C++ comme on programme en C! Ceux qui te disent que C++ est du C évolué te mentent! C++ n'est pas du C évolué, et ne l'a jamais été! Le C with classes, qui a été développé entre les deux pouvait correspondre à cette définition, mais, dés qu'l a commencé à s'appeler C++, ce n'était plus le cas.

    C++ n'a absolument rien à voir avec le C, et la plupart des habitudes que tu pourrait avoir acquises en C seront nocives en C++. Pour notre malheur, Qt fait un usage intensif de l'héritage publique, qui nous fait -- justement -- entrer dans une logique dans laquelle l'allocation dynamique est souvent de mise, ce qui peut prêter à confusion.

    Mais, idéalement, malgré ta connaissance de C, tu dois envisager l'apprentissage du C++ comme l'apprentissage de n'importe quel nouveau langage totalement inconnu comme java, python, C# ou brainf**ck : en commençant par les bases et en évoluant à ton rythme.

    Alors, je sais que cela fait beaucoup moins sexy, mais, dans l'idéal, tu devrais commencer par apprendre le C++, quitte à ne faire que des programmes console au début, avant de passer à Qt et ses spécificités propres
    D'où l'utilisation du pointeur sur un vector.
    Justement! Si tu avais pris le temps d'apprendre correctement le C++ avant de te lancer dans l'utilisation de Qt, tu aurais su que cela ne servait à rien

    pourquoi dis tu que le #define est à proscrire ? et qu'apporte un static const size_t MAX_SIZE= xxx ou, static constexpr size_t MAX_SIZE= xxx par rapport au define ?
    Parce que #define ne fait que du remplacement de texte, sans qu'il y ait la moindre vérification de type au moment où le symbole est défini, ce qui est un comble dans un langage fortement typé comme C++

    Pour le préprocesseur, que tu écrive #define SYMBOL 3, #define SYMBOL 3.1415926 ou #define SYMBOL "Hello world", cela renviendra exactement au même! Sauf que le premier représentera une valeur entière (de type int ou assimilable), le second représentera une valeur réell (de type float ou assimilable) et le troisième représentera une chaine de caractères.

    Les alternatives proposées auront un résultat exactement similaire (créer des constantes de compilation), mais avec un petit "plus" des plus intéressant : elles seront directement correctement typées, avec tout ce que cela implique

    Note d'ailleurs qu'il existe une troisième possibilité dont je n'ai pas parlé : lorsque plusieurs symboles devraient travailler "de concert" sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #define FIRST 1
    #define SECOND 2
    #define THIRD 3
    l'utilisation d'une énumération sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    enum MyEnum{
        first =1,
        second, // = 2 est implicite
        third // = 3 est implicite
    };
    sera préféable, car le compilateur pourra alors faire des vérifications supplémentaires (par exemple, en s'assurant que toutes les valeurs énumérées ont été prises en compte dans un switch ... case)

    Voici mon besoin, j'ai besoin d'un tableau d'une certaine dimension au départ, mais la taille de celui-ci peut évoluer, mais il n'y a pas de maximum à sa taille. Donc pour ne pas bloquer de la mémoire pour rien, je ne veux pas mettre une dimension énorme en me disant que peut être, éventuellement, un jour on aura besoin d'une grande taille mémoire.
    D'abord et avant tout: pour quelle raison as tu besoin d'une certaine dimension au départ

    Je ne refuse pas l'idée, mais j'avoue ne pas en voir l'intérêt particulier que tu espères en tirer, et, tant que tu ne m'auras pas convaincu que tu dois effectivement travailler de la sorte, je considérerai que tu n'as aucun besoin de le faire, parce que cela ne ferait que rajouter de la complexité inutile
    Aurais-tu un exemple de code à me montrer comment je pourrai faire cela ?
    Oh, je peux te donner des tonnes d'exemples sur des tonnes de cas différents ... A condition que les cas exposés me semblent cohérents, ce qui n'est pas le cas pour l'instant

    D'ailleurs, au passage, t'ai-je dit que LES VARIABLES GLOBALES, C'EST MAL!!!
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut
    Quelle narration Koala01, merci pour toutes ces explications, fortes intéressantes.
    Alors pour répondre à tes questions, pourquoi passer du C directement au C++ avec l'IDE Qt, bon déjà, de formation et de mon expérience professionnelle, je n'ai quasiment fait que du développement C en embarqué. Seulement là, pour mon projet, j'ai développé en C sur un µc contrôleur, mais je dois aussi mettre en place une communication entre ma carte et une IHM développée sous Windows. J'ai donc cherché en urgence (parce qu'il faut que ça avance), un outil de développement gratuit qui offre des fonctionnalités graphiques et de communication, et je me suis arrêté sur Qt Creator, ai-je bien fait ou pas, je ne sais pas ???
    J'ai donc développé (et je suis toujours en cours) mon IHM sous Qt où j'ai dû apprendre sur le terrain, le C++ avec l'environnement Qt, et certaines choses se sont faites dans la douleur
    Maintenant pourquoi vouloir utiliser un tableau de "double" à dimension variable, donc j'ai une carte électronique qui m'envoie toutes les 10ms des données que mon IHM doit traiter, mais j'ai aussi une autre carte électronique qui m'envoie aussi des données(pas les mêmes) toutes les 10ms que l'IHM doit aussi traiter.
    Là où ça se complique c'est que les données d'une carte sont directement affichées dans un graphique, sous forme de courbe, mais que mes autres données doivent être aussi affichées dans le même graphique mais avec un temps de retard (on va prendre par exemple 1s de retard), à tout cela tu ajoutes le fait que je dois faire des calculs entre données.
    Donc mon idée, était de sauvegarder dans un tableau de dimension 100 (= 1s/10ms) mes données et ainsi pouvoir venir afficher les données d'il y a 1s avant, j'espère avoir était clair.
    Mais l'autre particularité est aussi que ce temps 1s peut varier et peut passer par exemple à 2.3s ou 1h, enfin bref un temps que je ne maitrise pas au début.
    J'ai donc besoin d'un tableau à dimension variable

    Pour commencer à apprendre le C++, que me préconises-tu ?

    Voilà, tu sais tout maintenant

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Excuses le délais, je viens à peine de me rendre compte de ta réponse.

    Ce que j'utiliserais alors, c'est un système fifo comme std::queue, sans essayer de définir de taille à la base.

    Et pour être précis, je placerais les données des deux cartes dans deux std::queue distinctes.

    Mais, pour t'expliquer le plus clairement possible, je vais devoir prendre un exemple tout à fait arbitraire qu'il faudra, du coup, que tu adaptes à tes propres besoins

    Je créerais donc deux std::queue distinctes que j'appellerais
    • std::queue firstCard; qui serait destinées à recevoir les donnée de la première carte et
    • std::queu secondCard; dont tu auras surement compris qu'elle sera destinée à recevoir les données de la deuxième carte

    Ensuite, je calculerais le nombre de données nécessaires à la satisfaction de mes besoins d'affichage. Bien que ce soit sans doute un peu lent, on pourrait envisager une mise à jour toutes les 0.01 secondes, si bien que l'on devrait prévoir d'afficher 10 valeurs consécutives.

    Cela signifie que l'on ne lancerait la procédure "d'extraction" des données de firstCard en vue de leur affichage que si elle contient au minimum ... 10 valeurs susceptibles d'être affichée.

    En gros, cela pourrait se traduire par une logique (je la présente en pseudo-code ) proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SI la taille de firstCard >= 10
        Pour i = 0 à 10 (exclus) par pas de 1
           extraire première valeur de firstCard
           positionner le point correspondant à la valeur extraite
        FIn Pour
    Fin Si
    Afin d'assurer le "retard d'affichage" pour les données issues de la deuxième carte, la logique serai sensiblement pareille, sauf que la condition vérifierait que la taille de secondCard soit égale à 10 (nombre de données qui seront extraite) * délais (exprimé en centième de seconde, selon mon exemple) + 10.

    Pour un délais de 1 seconde, cela reviendrait à 10 * 100 + 10 = 1010. Voici le pseudo-code corrigé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SI la taille de secondCard >= 1010
        Pour i = 0 à 10 (exclus) par pas de 1
           extraire première valeur de secondCard
           positionner le point correspondant à la valeur extraite
        FIn Pour
    Fin Si
    Au final, nous pourrions regrouper le tout dans une seule boucle sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SI la taille de firstCard >= 10
        Pour i = 0 à 10 (exclus) par pas de 1
           extraire première valeur de firstCard
           positionner le point correspondant à la valeur extraite
           SI taille de secondCard >= REQUIERED_VALUE * DELAYS- i
               extraire première valeur de secibdCard
               positionner le point correspondant à la valeur extraite
           FIN si
        FinPour
    FinSi
    Et, pour peu que tu puisse t'arranger pour que cette logique ne soit, effectivement, mise en branle que lorsque le délais entre deux affichage est écoulé (et donc, que l'on a pour ainsi dire la certitude que firstCard contient effectivement assez de données, la première condition pourrait presque être ignorée

    Par contre, je vais être très méchant avec toi, car je ne vais rien donner de plus que ces deux algorithmes, et te laisser te renseigner sur les possibilités que la classe std::queue t'offre, de manière à ce que cela puisse te servir de leçon au passage
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Allouer dynamiquement un tableau à 2 dimensions
    Par Franck.H dans le forum Télécharger
    Réponses: 1
    Dernier message: 11/09/2011, 12h24
  2. Comment initialiser dynamiquement un tableau 2 dimensions
    Par ttttnht dans le forum Collection et Stream
    Réponses: 8
    Dernier message: 14/08/2009, 10h41
  3. FAQ: Comment allouer un tableau dynamique
    Par beb30 dans le forum C
    Réponses: 14
    Dernier message: 02/05/2006, 16h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo