Bonsoir,
Je me posais une petite question, est-ce qu'un pointeur sur NULL prend une quelconque place en mémoire, ou alors strictement rien du tout ?
Merci
Version imprimable
Bonsoir,
Je me posais une petite question, est-ce qu'un pointeur sur NULL prend une quelconque place en mémoire, ou alors strictement rien du tout ?
Merci
ça veut rien dire... un pointeur pointe sur une zone mémoire, ce qui prend de la place c'est la zone allouée, pas le pointeur. Que tu le fasse pointer vers NULL ou une zone réellement allouée, ça change rien.
Ouais le pointeur n'occupera pas plus ou moins d'espace si tu changes la variable pointée. L'espace occupé correspond à l'espace requis pour identifier une adresse mémoire.
Tu peux connaître la taille d'un pointeur grâce à un sizeof.
J'obtiens une taille de 32 bits quelque soit la variable pointée.
Tu peux faire le test grâce à ce programme:
Et j'obtiens:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <iostream> using namespace std; int main() { int* pointeur = NULL; cout << "pointeur = NULL: " << sizeof(pointeur)*8 << "bits" << endl; int a=3; pointeur = &a; cout << "pointeur = &a: " << sizeof(pointeur)*8 << "bits" << endl; double b = 5.56; double* pointeur2 = &b; cout << "pointeur sur double: " << sizeof(pointeur2)*8 << "bits" << endl; return 0; }
Code:
1
2
3 pointeur = NULL: 32bits pointeur = &a: 32bits pointeur sur double: 32bits
Ok merci :).
sizeof est une constante de compilation, qui ne dépend pas de la valeur de son argument, juste de son type. En fait l'argument de sizeof n'est pas évalué. On peut donc faire sizeof une variable non-initialisée (très courant) :
On pourrait même faire des choses "interdites" dans sizeof :Code:
1
2
3 int i; cout << i ; // NON! comportement indéfini! cout << sizeof i; // OK
Code:cout << sizeof (*(int*)0); // équivaut à sizeof (int)
Et c'est d'ailleurs parce qu'il est évalué à la compilation qu'on le retrouve souvent dans des techniques de métaprogrammation.
Excusez moi de changer de sujet mais :
Code:cout << i ; // NON! comportement indéfini!
?
Pourquoi?
Ici i n'est pas initialisé.
Lire une variable (d'un type de base) non initialisée donne un comportement indéfini, par exemple :
Un pointeur qui a été désalloué ne peut plus être examiné non plus :Code:
1
2 int i, j; i = j; // comportement indéfini : j n'est pas initialisé
Même sans utiliser delete, on peut avoir le cas : soit un pointeur vers une variable dont la durée de vie est terminée :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 int *p = new int; cout << p; // OK, imprime l'adresse de l'entier cout << *p; // comportement indéfini : l'entier n'as pas de valeur *p = 1; cout << *p; // OK, imprime 1 int *q = p; // pas de pb delete p; // pas de pb // à partir de là, p ne contient plus une adresse valide cout << p; // comportement indéfini : lecture de p cout << q; // comportement indéfini : q n'est plus valide cout << p == q ? "égal" : "différent"; // comportement indéfini p = new int; // pas de pb q = p; cout << p == q ? "égal" : "différent"; // imprime égal
Les seules choses qu'on peut faire avec une variable primitive non-initialisée, un pointer désalloué (avec free, delete, etc.), ou un pointeur contenait l'adresse d'une variable dont la durée de vie est terminée :Code:
1
2
3
4
5
6
7 int *p; { int i; p = &i; cout << p; // imprime l'adresse de i } // fin de la portée de i, fin de la durée de vie de i cout << p; // comportement indéfini : i n'existe plus
- le "détruire" (terminer sa durée de vie, ce qui ne fait rien, les scalaires ont des destructeurs triviaux)
- lui affecter une nouvelle valeur
(unsigned char est particulier et échappe à la règle.)
Dites-moi si je me trompe mais, si on ne voit pas vraiment le comportement indéfini que pourrait provoquer le cout << d'un entier non initialisé (simple valeur non prédictible), on comprend mieux avec le simple cout << d'un pointeur non initialisé et déréférencé. Or le principe est bien le même : l'utilisation d'une variable T non initialisée.
Maintenant, ce n'est peut-être pas ce que dis vraiment la norme, je ne l'ai pas lue.
C'eut été intéressant de nous dire en quoi. :)Citation:
(unsigned char est particulier et échappe à la règle.)
Euh, là, je me permets de douter: Où est le problème tant qu'on ne déréférence pas le pointeur ?Citation:
Envoyé par corrector
Est-il justement dans l'absence de garantie que le pointeur ne sera pas déréférencé ?
Faux !Citation:
Lire une variable (d'un type de base) non initialisée donne un comportement indéfini, par exemple :
Lire cette valeur est totalement défini. C'est la valeure qui est totalement hasardeuse.
Cela doit surement dépendre de l'espace de travail utilisé en tout cas pour Visual Studio 2005 voilà les résultats pour :Citation:
Lire cette valeur est totalement défini. C'est la valeure qui est totalement hasardeuse
En mode debug :Code:
1
2int i, j; i = j;
Et idem pour i bien sur, l'assertion permet cependant de continuer, les variables sont par défaut à -858993460.Citation:
Run-Time Check Failure #3 - The variable 'j' is being used without being initialized.
En mode release, les variables sont simplement initialisées à 0...
C'est plutôt intéressant comme résultat... (je ne dit surtout pas qu'il faut le faire:aie:) mais quelle serait le comportement d'un telle code, cela dépend-t-il vraiment du compilateur et donc "pourrait" produire un code(/application) "stable" ou non? (Simple curiosité :mrgreen:)
En debug la pile est marqée par le code hexa #CC pour que les pointeurs pointent dans la moquette. En debug tu verras donc souvent des acces a #CCCCCCD0 qui est juste un offset de #CCCCCCCC
en release la variable n'est _pas initialisée_ du tout. si tu recois 0 c'est que la precedente variable qui etait a cet endroit avait decidé d'y mettre 0. si elle avait decidé d'y mettre 72 tu etais fichu.
Cela a par contre effet assez ennuyeux, c'est que les booleens sont toujours initialisé a #CC donc "true", et cela peut faire marcher un truc en debug mais pas en release. Quand je lis "ca marche en debug mais pas en release" je pense immediatement a une initialisation du mode debug (la pile, le tas) qui aurait mis un booleen a true, et je recommande de verifier l'initialisation des booléens. 3 fois ou cela c'est produit (avec comme seul diagnostique "ca marche en debug mais pas en release") et 3 fois la reponse etait un booléen initialisé comme un pied.
Je crois que tu ne saisis pas exactement le concept de comportement indéfini : c'est juste ce qui n'est pas défini! Ce n'est pas un comportement précis.
La norme ne place aucune exigence sur l'implémentation concernant ce code.Le programme peut faire n'importe quoi, le compilateur sera toujours conforme.
La norme décrit la conversion de lvalue en rvalue :
(Ce n'est pas bien formulé d'ailleurs : il faut lire "or if T is a non-class type, and T is not char or unsigned char, and if the object is uninitialized, ...". Parce que là...)Citation:
Envoyé par draft C++, 4.1/1
En gros tu peux les lire, mais la valeur n'est pas définie, et elle n'est même pas garantie d'être deux fois la même :
Ceci dit, ça n'est écrit clairement nul part. C'est une inférence à partir de la norme et aussi "common wisdom". J'aurai du mal à le justifier formellement. :oops: (La norme n'est vraiment pas assez formalisée.)Code:
1
2
3
4 unsigned char c; // ou char cout << (int)c; // affiche un nombre entre 0 et UCHAR_MAX cout << (int)c; // affiche encore un nombre entre 0 et UCHAR_MAX, pas forcément le même cout << c == c ? "OK" : "étrange"; // affiche soit OK soit étrange
La valeur du pointeur ne doit plus être utilisée. Comme s'il était non-initialisé. Tu ne peux même pas recopier la valeur.
Non, copier, ou afficher un pointeur ne le déréférence pas, encore heureux. :lol:Citation:
Envoyé par C++ draft, 3.7.3.2/4 [basic.stc.dynamic.deallocation]
Je n'ai plus le standard en tête, mais je suis sûr de moi.
Imagine le code suivant :
La 1er ligne créer une variable sur la pile sans lui affecté de valeur.Code:
1
2
3int a; cout<<a;
Elle prend donc la valeur de ce qui se trouvait avant à cette place.
Il n'y a pas de moyen de connaitre cette valeur. C'est dans ce sens que je dis que la valeur est indéfinie.
Par contre la 2eme ligne, elle a un comportement totalement défini.Elle va t'afficher la valeur de a, qui peut être n'importe quoi.
Oui, le cout est tout à fait défini.
Pour preuve, effectue-la deux fois, et tu obtiendras le même résultat.
Code:
1
2
3 int a; cout << a << endl; cout << a << endl; // affiche deux fois la même valeur
Moi si, lis mon autre réponse.
C'est un comportement observable possible. Ce n'est pas le seul.
Sur certains systèmes, les entiers signés ne sont pas représentés en complément à 2 mais en complément à 1 ou en signe-magnitude. Parfois en signe-magnitude on considère que l'entier représentant 0 doit avoir un signe positif (signe 0). Si un entier représentant 0 a un signe négatif (représentation binaire un 1 suivit de zéros), c'est une erreur, et le processeur déclenche une exception. Si tu es sur un tel système, a peut avoir ce que la norme C appelle une "trap representation", un motif de bits qui n'a pas de sens pour le type de la variable. Tenter d'accèder à la valeur de la variable va alors déclencher une trap, une exception processeur. Qui peut se traduire par un signal et terminer brutalement (abort) le programme.
Sur ce système, selon ce qui se trouvait avant à l'adresse de a, le programme peut planter ou pas. Ce qui est un autre exemple de comportement observable.
Ces différents comportements sont permis par la norme puisque elle ne défini rien à propos du comportement d'un programme qui accède à une variable non initialisée. Ce qu'on appelle donc un comportement indéfini.
Formellement (selon la sémantique définie par la norme C++), a n'a pas de valeur.
Avant qu'on lui affecte une valeur, le compilateur n'est même pas obligé de lui allouer un emplacement rien qu'à elle dans la pile (ou un registre rien qu'à elle).
NON.
Qu'est-ce que c'est censé prouver? Encore une fois : le comportement N'EST PAS défini. J'ai déjà cité la norme. J'ai déjà expliqué ce que cela signifiait.
De plus, babar63 a donné un exemple de comportement très sympathique qui ne correspond pas à ce que tu dis.
Je me demande si certains savent lire. :evilred: Ou alors ils croient que leur expérience personnelle (limitée, forcément limité) leur donne la connaissance absolue.
PS : tester (une, plusieurs, un million de fois) un programme ne garantit qu'il est correct. Par contre un test qui échoue démontre qu'il est bugué.