c++ declaration d'un int (probleme simple)
Répondre à la discussion
Affichage des résultats 1 à 21 sur 21

c++ declaration d'un int (probleme simple)



  1. #1
    cosmoff

    c++ declaration d'un int (probleme simple)


    ------

    Bonjour,

    mon compilateur crie si je met :
    Code:
    int main() 
    {
    int a = 5;
    int a = 5;		
    }
    ce qui me parait logique car la variable 'a' a déja été déclaré, mais si je met :

    Code:
    int main() 
    {
    	while(1)
    	{
    		int a = 5;		
    	}
    }
    alors aucun soucis, pourtant dans la pile il va y avoir plusieurs déclaration d'une meme variable, pourquoi le compilateur ne crie pas ?

    Merci d'avance pour votre aide

    -----

  2. #2
    pm42

    Re : c++ declaration d'un int (probleme simple)

    Il n'y a pas plusieurs déclarations d'une même variable mais 1 seule locale à la boucle.
    Tu confonds le code source où il est évident qu'il n'y en a qu'une seule avec l'exécution. Ou là aussi il y en a une seule qui est créée puis détruite à chaque itération.

  3. #3
    Bluedeep

    Re : c++ declaration d'un int (probleme simple)

    Bonjour

    Là, il faut revoir la notion de portée des identificateurs.

    http://sdz.tdct.org/sdz/les-identifi...nomsetmasquage
    Dernière modification par Bluedeep ; 11/07/2017 à 08h59.

  4. #4
    cosmoff

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par pm42 Voir le message
    Il n'y a pas plusieurs déclarations d'une même variable mais 1 seule locale à la boucle.
    Tu confonds le code source où il est évident qu'il n'y en a qu'une seule avec l'exécution. Ou là aussi il y en a une seule qui est créée puis détruite à chaque itération.
    pour moi la variable 'a' est détuite que lorsque qu'on quitte le boucle (sortie du bloc), et vu que celle ci est une boucle infini alors la variable n'est jamais détruite (car on reste toujours dans le bloc), mais c'est a chaque rebouclage que les variables locales de la boucle sont détruites ?

  5. A voir en vidéo sur Futura
  6. #5
    minushabens

    Re : c++ declaration d'un int (probleme simple)

    Il est heureux que les variables soient détruites après chaque itération, autrement on aurait vite fait de remplir la mémoire de l'ordinateur.

  7. #6
    jacknicklaus

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par minushabens Voir le message
    Il est heureux que les variables soient détruites après chaque itération, autrement on aurait vite fait de remplir la mémoire de l'ordinateur.
    Non, pas détruite à chaque itération.
    Détruite en sortie du bloc { }, qui définit sa portée, puisque la variable est ici locale à cette portée.
    Code:
    int main()
    {
        {
            int a = 0;
        }
        {
            int a = 1;
        }
    
        return 0;
    }

    est valide.

    Donc jamais détruite dans le cas d'une boucle infinie comme ici, ou en fin d'itération dans un cas plus réaliste.
    There are more things in heaven and earth, Horatio, Than are dreamt of in your philosophy.

  8. #7
    Jack
    Modérateur

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par minushabens Voir le message
    Il est heureux que les variables soient détruites après chaque itération, autrement on aurait vite fait de remplir la mémoire de l'ordinateur.
    Les variables ne sont pas détruites après chaque itération, mais lorsque la boucle est terminée.

  9. #8
    pm42

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Jack Voir le message
    Les variables ne sont pas détruites après chaque itération, mais lorsque la boucle est terminée.
    Vous êtes sur ? Que se passe t-il si je mets une variable de taille différente à chaque fois :

    Code:
    void foo()
    {
    	for(int i=0; i<10; i++)
    	{
    		char c[i];
    		c[i-1]='A';
    	}
    }
    Ou en C++ une instance de classe avec un constructeur/destructeur ? J'ai l'impression que la variable va bien être détruite à chaque itération.

  10. #9
    Ikhar84
    Animateur Informatique

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par pm42 Voir le message
    Vous êtes sur ? Que se passe t-il si je mets une variable de taille différente à chaque fois :

    Code:
    void foo()
    {
    	for(int i=0; i<10; i++)
    	{
    		char c[i];
    		c[i-1]='A';
    	}
    }
    Ou en C++ une instance de classe avec un constructeur/destructeur ? J'ai l'impression que la variable va bien être détruite à chaque itération.
    Pour moi une nouvelle variable est "créée" sur la pile (stack), puis détruite à la fin du bloc signalé par l'accolade fermante (et donc de la fin de la portée des variable de ce bloc sur la pile)
    Il s'agit donc de variables différentes...

    Pour l'exemple de PM42, ici, on ne travaille pas avec la pile mais le tas (heap) car pointeur (tableau)...
    L'espace mémoire allouée et pointé n'est pas detruit, mais à chaque itération, on réalloue un nouvel espace mémoire sur le tas pour le pointeur: fuite mémoire...

    Quant à l'indice i, je pense qu'à la 2eme itération, i=1, soit pour a[1], on joue un peu avec le feu en allouant pas explicitement (ou réallouant dynamiquement) l'espace mémoire.

    Mais je me trompe sûrement ?
    Cela fais bien longtemps le c/c++ pour moi...

  11. #10
    pm42

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Ikhar84 Voir le message
    Pour l'exemple de PM42, ici, on ne travaille pas avec la pile mais le tas (heap) car pointeur (tableau)...
    Non, ce genre de tableau est sur la pile. Dans le doute, prendre le programme, le compiler et lire l'assembleur généré pour s'en convaincre.

    Après, si la variable est de type simple ou de taille fixe, il est effectivement possible d'utiliser le même espace mémoire à chaque itération, c'est même naturel. Mais on peut voir cela comme une optimisation et considéré que sémantiquement, c'est une nouvelle variable à chaque fois.

  12. #11
    Chanur

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Ikhar84 Voir le message
    Citation Envoyé par pm42 Voir le message
    Vous êtes sur ? Que se passe t-il si je mets une variable de taille différente à chaque fois :

    Code:
    void foo()
    {
        for(int i=0; i<10; i++)
        {
            char c[i];
            c[i-1]='A';
        }
    }
    Ou en C++ une instance de classe avec un constructeur/destructeur ? J'ai l'impression que la variable va bien être détruite à chaque itération.
    Pour moi une nouvelle variable est "créée" sur la pile (stack), puis détruite à la fin du bloc signalé par l'accolade fermante (et donc de la fin de la portée des variable de ce bloc sur la pile)
    Il s'agit donc de variables différentes...
    C'est ce que je crois aussi. (mais là, j'aurais fait commencer i à 1, parce que char c[0]; c[-1] = 'A'; ça fait carrément froid dans le dos )

    Citation Envoyé par Ikhar84 Voir le message
    Pour l'exemple de PM42, ici, on ne travaille pas avec la pile mais le tas (heap) car pointeur (tableau)...
    L'espace mémoire allouée et pointé n'est pas detruit, mais à chaque itération, on réalloue un nouvel espace mémoire sur le tas pour le pointeur: fuite mémoire...
    Non, c'est bien sur la pile. Et de toute façon on ne détruit pas d'espace mémoire : on déplace le pointeur de la pile. Il n'y pas de fuite mémoire. (voir exemple plus bas)

    Citation Envoyé par Ikhar84 Voir le message
    Quant à l'indice i, je pense qu'à la 2eme itération, i=1, soit pour a[1], on joue un peu avec le feu en allouant pas explicitement (ou réallouant dynamiquement) l'espace mémoire.
    Ben du coup non : c'est parfaitement fiable.

    Citation Envoyé par Ikhar84 Voir le message
    Mais je me trompe sûrement ?
    Effectivement.
    Mais en même temps c'est normal. Moi aussi, il a fallut que je me bricole un exemple pour me clarifier les idées.


    Bon, maintenant l'exemple en question. C'est le même foo, mais un peu plus compliqué : j'ai mis deux tableaux et affiché leur adresse et leur contenu, pour voir où ils sont alloués.
    Code:
    #include <stdio.h>
    int main ()
    {   
        int k; // une première variable pour voir à quoi ressemblent les adresses de la pile
        printf ("k %p\n", &k);
    
    
        for (int i=1; i<20; i++) // la boucle où je crée les tableaux (jusqu'à 20 pour qu'ils changent d'adresse)
        {   
            char c[i]; // premier tableau
            c[i-1]=1;
            printf ("c %p", c); // son adresse
            for (int j=0; j<i; j++)
                printf (" %d", c[j]); // son contenu
            printf ("\n");
    
    
            char d[i]; // deuxième tableau idem
            d[i-1]=2;
            printf ("d %p", d);
            for (int j=0; j<i; j++)
                printf (" %d", d[j]);
            printf ("\n");
        }   
    
    
        return 0;
    }
    ​(et je sais que certains n'aiment pas qu'on utilise printf en C++, mais j'aime bien contrôler le format de ce que j'affiche. Na ! )

    g++ foo.cpp -ofoo
    foo
    [ avec en bleu des commentaires que j'ai ajoutés ]
    Code:
    k 0x7fff06e84110  une première adresse sur la pile
    c 0x7fff06e840d0 1   l'adresse de c, manifestement sur la pile : c'est presque la même que celle de k
    d 0x7fff06e840c0 2   l'adresse de d
    c 0x7fff06e840c0 2 1      deuxième itération : c a changé d'adresse (elle est maintenant à l'ancienne adresse de d)
    d 0x7fff06e840a0 -80 2    d a aussi changé d'adresse
    c 0x7fff06e840c0 2 1 1      troisième itération : les adresses n'ont pas changé (et le contenu de c non plus) : le compilo a prévu de la marge
    d 0x7fff06e840a0 -80 5 2    d n'a pas changé d'adresse mais son contenu a été modifié (par les appels à printf : j'ai vérifié)
    c 0x7fff06e840c0 2 1 1 1       le contenu de c ne change pas
    d 0x7fff06e840a0 -80 5 64 2    le contenu de d est écrasé à chaque fois par les appels à printf
    c 0x7fff06e840c0 2 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 -48 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 -48 -70 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 -48 -70 127 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 -48 -70 127 0 2
    c 0x7fff06e840c0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    d 0x7fff06e840a0 -80 5 64 0 0 0 0 0 116 28 -24 -48 -70 127 0 0 2
    c 0x7fff06e840b0 2 64 -24 6 -1 127 0 0 124 7 64 0 0 0 0 0 2 1            il n'y a plus assez de place : on change d'adresse
    d 0x7fff06e84080 -32 8 27 -47 -70 127 0 0 48 65 -24 6 -1 127 0 0 -80 2   idem
    c 0x7fff06e840b0 2 64 -24 6 -1 127 0 0 124 7 64 0 0 0 0 0 2 1 1            pas besoin de changer d'adresse : le compilo a prévu de la marge
    d 0x7fff06e84080 -32 8 27 -47 -70 127 0 0 48 65 -24 6 -1 127 0 0 -80 5 2   etc.
    Maintenant, un exemple avec une classe : c'est beaucoup plus simple à suivre
    Code:
    #include <stdio.h>
    class A
        {
        int attribut;
        public:
        A (int i) { attribut = i; printf ("constructeur %d\n", attribut); };
        ~A () { printf ("destructeur %d\n", attribut); };
        };
    int main ()
        {
        for (int i=0; i<3; i++)
            A a(i);
        return 0;
        }
    Code:
    constructeur 0
    destructeur 0
    constructeur 1
    destructeur 1
    constructeur 2
    destructeur 2
    C'est clair ...
    Ce qui se conçoit bien s'énonce clairement ; et les mots pour le dire arrivent aisément.

  13. #12
    minushabens

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Jack Voir le message
    Les variables ne sont pas détruites après chaque itération, mais lorsque la boucle est terminée.
    comme je ne connais pas c++ je suppose que c'est toi qui as raison. Mais alors ce phénomène est propre à ce langage. Dans le temps je programmais en c (ansi) et j'ai fait tourner des simulations très longues et je pense que sans récupération de la mémoire entre deux itérations ça aurait planté. De mémoire, je pouvais répéter un million de fois un calcul mettant en jeu des matrices 100x100. On est là dans les 10^10 octets.

  14. #13
    Bluedeep

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Jack Voir le message
    Les variables ne sont pas détruites après chaque itération, mais lorsque la boucle est terminée.
    Je n'ai pas touché au C++ depuis .... de longues années mais cette affirmation m'étonne beaucoup : dans ce cas, une boucle avec une variable déclarée dans le bloc d'itération saturerait la pile très vite.

  15. #14
    Chanur

    Re : c++ declaration d'un int (probleme simple)

    Il n'y a pas de fuite de mémoire : les variables sont déclarées et effacées exactement comme ça se passerait si chaque passage dans la boucle était un appel de fonction.

    En C++, ça marche comme en C, la différence est que la taille d'un tableau peut être variable alors qu'en C elle doit être constante (connue lors de la compilation), et qu'on ne peut déclarer une variable qu'au début d'un bloc (en C++ on peut la déclarer n'importe où).

    Donc on peut toujours faire des boucles qui s’exécutent des milliards de fois, même en déclarant des variables au milieu.

    Il faut juste éviter de le faire en déclarant des objets dont le constructeur ou le destructeur prendrait un temps prohibitif.
    Ce qui se conçoit bien s'énonce clairement ; et les mots pour le dire arrivent aisément.

  16. #15
    Tryss2

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Chanur Voir le message
    C'est ce que je crois aussi. (mais là, j'aurais fait commencer i à 1, parce que char c[0]; c[-1] = 'A'; ça fait carrément froid dans le dos )
    Tu veux faire des cauchemars?

    Code:
    void foo()
    {
        for(int i=0; 1; i++)
        {
            char a = 'A';
            char c[i];
            c[i-1]=a;
        }
    }



    Ce code ne déclenche généralement pas d'erreur Les joies du C !

  17. #16
    Chanur

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Tryss2 Voir le message
    Tu veux faire des cauchemars?


    Code:
    void foo()
    {
        for(int i=0; 1; i++)
        {
            char a = 'A';
            char c[i];
            c[i-1]=a;
        }
    }







    Ce code ne déclenche généralement pas d'erreur Les joies du C !
    Ah ? chez moi, ça plante (Erreur de segmentation (core dumped)) quand i atteint la valeur -2147483648
    Curieusement, il accepte le "int c[i];", mais dans le debugger, il dit :
    Code:
    (gdb) p c
    $1 = 0x7fffee50ab90 <Address 0x7fffee50ab90 out of bounds>

    Par contre, mon tout premier bug m'avait laissé perplexe :
    Code:
    int main ()
        {
        int i;
        int tableau[10];
        for (i=1; i<=10; i++)
            tableau[i] = 0;
        }
    ce code là (en C, pas en C++) ne plante pas, mais c'est une boucle sans fin.
    J'avoue humblement qu'à l'époque, le fait que ce soit une boucle sans fin ne m'avait pas paru évident ...
    Dernière modification par Chanur ; 15/07/2017 à 02h51.
    Ce qui se conçoit bien s'énonce clairement ; et les mots pour le dire arrivent aisément.

  18. #17
    Tryss2

    Re : c++ declaration d'un int (probleme simple)

    Ça n'est pas plutôt celui ci qui ne plante généralement pas ?

    Code:
    int main ()
        {
        int tableau[10];
        int i;
        for (i=1; i<=10; i++)
            tableau[i] = 0;
        }
    Mais oui, c'est de cette idée là dont je voulais parler... on déborde du tableau et on écrit dans les autres variables qui se trouvent à coté.

    Mais pardon pour le HS

  19. #18
    CM63

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par Chanur Voir le message
    Par contre, mon tout premier bug m'avait laissé perplexe :
    Code:
    int main ()
        {
        int i;
        int tableau[10];
        for (i=1; i<=10; i++)
            tableau[i] = 0;
        }
    ce code là (en C, pas en C++) ne plante pas, mais c'est une boucle sans fin.
    J'avoue humblement qu'à l'époque, le fait que ce soit une boucle sans fin ne m'avait pas paru évident ...
    Non, ce n'est pas une boucle sans fin. Par contre il devrait planter parce qu'il y a un débordement de tableau. Mais en fait il ne va peut-être pas planter, car l'optimiseur va se rendre compte que tu n'utilises pas les résultats et il ne va pas exécuter le code.

  20. #19
    Tryss2

    Re : c++ declaration d'un int (probleme simple)

    CM63 : Le C et le C++, ça ne plante pas si tu écris en dehors d'un tableau, ça plante si tu écris sur une zone mémoire protégée.

    Il faut bien voir ce qui se passe en mémoire en général. Le code va allouer 44 octets contigus, 40 pour t, le tableau, et 4 pour i

    Code:
    Adresse : t     .    .    .    .    .    .   .    .    .    &i
    Contenu : t[0] t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8] t[9]  i
    Ensuite, il faut bien comprendre que t[n], c'est, en gros *(t+n), ce qui se trouve à l'adresse de t plus n fois la taille d'un élément. Ici, ce qui se trouve à l'adresse de t+10, c'est i, donc ça ne plante pas, mais ça écrit sur la zone mémoire de i.

    Tu peux le vérifier en testant &i == &(t[10]). Donc dans son code, quand il fait t[10] = 0, ça revient en fait à faire i=0, donc i ne va jamais dépasser 10

    Après, le résultat exact dépend fortement du compilateur, voir même, dans le cas des variables allouées, de l’exécution. Ce genre de trucs, c'est un des gros danger/problèmes du C/C++.
    Dernière modification par Tryss2 ; 19/07/2017 à 10h38.

  21. #20
    CM63

    Re : c++ declaration d'un int (probleme simple)

    Oui enfin en même temps, on sait très bien qu'on déborde du tableau, et que ça a beaucoup de chance de faire n'importe quoi.

  22. #21
    Chanur

    Re : c++ declaration d'un int (probleme simple)

    Citation Envoyé par CM63 Voir le message
    Oui enfin en même temps, on sait très bien qu'on déborde du tableau, et que ça a beaucoup de chance de faire n'importe quoi.
    C'est ce que dit la norme, en fait : le comportement est "indéterminé".
    On laisse libre cours à l'imagination de l'ordinateur, quoi ...
    Ce qui se conçoit bien s'énonce clairement ; et les mots pour le dire arrivent aisément.

Discussions similaires

  1. Supprimer un noeud d'un arbre / problème de déclaration
    Par VeryCuriousMan dans le forum Programmation et langages, Algorithmique
    Réponses: 20
    Dernier message: 22/03/2015, 19h16
  2. déclaration en C
    Par philouxy dans le forum Programmation et langages, Algorithmique
    Réponses: 2
    Dernier message: 15/07/2014, 11h04
  3. probleme de declaration des timers et des interruption
    Par elmhamdi dans le forum Électronique
    Réponses: 1
    Dernier message: 07/04/2012, 18h52
  4. programmation C++, problème déclaration de string
    Par invite1bc1ddb5 dans le forum Logiciel - Software - Open Source
    Réponses: 4
    Dernier message: 10/01/2009, 19h34