Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

allocation dynamique d'un pointeur

56 réponses
Avatar
prat
bonjour,

J'ai vu dans un bouquin de cours de langage C sur les pointeurs
l'algorithme suivant:

main( )
{
float * pr1,*pr2,*pr3,somme=3D0;


/*allocation dynamique */
pr1=3Dmalloc(sizeof(float));
pr2=3Dmalloc(sizeof(float));
pr3=3Dmalloc(sizeof(float));

/*saisie*/
printf("Entrez 3 notes: ");
scanf("%f %f %f ",pr1,pr2,pr3);

/*calcul de la somme*/
somme=3D*pr1+ *pr2+ *pr3;

/*calcul de la moyenne*/
printf("Moyenne :%f \n ",somme/3);

/*liberation de la m=E9moire*/
free(pr1);
free(pr2);
free(pr3);

}

Mes questions sont:
-les pointeurs ont =E9t=E9 d=E9clar=E9 initialement =E0 la premi=E8re
instruction,pourquoi en plus une allocation dynamique avec malloc( ) et
free( )?Est-elle n=E9cessaire?
-aurai-je pu utiliser l'allocation dynamique sans avoir au pr=E9alable
d=E9clar=E9 mes pointeurs comme =E0 la premi=E8re instruction?


merci.

10 réponses

1 2 3 4 5
Avatar
Pascal Bourguignon
Bruno Desthuilliers writes:

[...]

Il ne faut pas confondre du code simpliste avec du mauvais code.


On peut avoir du code débile justifié par une progression
pédagogique. Si on n'a pas à disposition le fil du chapitre, on peut
être injustement négatif sur le bout de code proposé.


Je conçois mal quelle "progression pédagogique" peut justifier le fait
de ne pas respecter la signature de main().


Peut être pas la progression pédagogique, mais l'histoire et la date
de rédaction du bouquin?


--
__Pascal Bourguignon__ http://www.informatimago.com/

"You can tell the Lisp programmers. They have pockets full of punch
cards with close parentheses on them." --> http://tinyurl.com/8ubpf



Avatar
Thierry Boudet
On 2007-01-18, Marc Boyer wrote:

Dans un interpreteur C, un pointeur pourrait tout a fait stoquer
une chaine qui soit le nom de la variable.


J'ai quand même du mal à concevoir l'incrémentation d'un nom.


--
"Internet, ça fait pas riche, mais ça fait aisé : tu veux les trucs que
t'as partout ailleurs pour les parisiengs, tu trouves. Mais pour les
traitements pour la mouche de l'olive, tin, t'as que dalle !"

Avatar
Marc Boyer
Le 19-01-2007, Thierry Boudet a écrit :
On 2007-01-18, Marc Boyer wrote:

Dans un interpreteur C, un pointeur pourrait tout a fait stoquer
une chaine qui soit le nom de la variable.


J'ai quand même du mal à concevoir l'incrémentation d'un nom.


Parce que tu raisonne sur l'implantation faite par le compilo.
Le ++ sert a passer a la variable suivante.

L'incrementation n'est possible que dans un tableau,
on peut donc stoquer nom+indice, et faire un hack pour le 'one past end'
eventuellement.
Ceci dit, mon but n'est pas de dire que ce serait une implantation
raisonnable, efficace, etc.
Mais le fait est que de mon experience d'enseignement, les notions
d'adresse que certains utilisent pour expliquer la notion de pointeur
recouvrent la meme chose, et n'expliquent rien, hormis pour
ceux qui savent deja (par des connaissances d'ASM par exemple).

Semantiquement, un pointeur sert a designer/referencer/garder
un doigt sur une autre variable (1).

Marc Boyer
(1) pour le debutant, on laissera de cote dans un premier temps
void *p= &p;
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)


Avatar
Antoine Leca
Bruno Desthuilliers wrote:
(snip)
Si le bouquin n'explique pas celà, il est de bien piètre qualité.
Un pointeur ne sert qu'à désigner une *autre* variable.


s/désigner une *autre* variable/stocker une adresse mémoire/


Tsk tsk. Non, je suis plutôt d'accord avec Marc.
Si tu avais raison, il n'y aurait pas de raison pour avoir plusieurs sortes
de pointeurs (liées à des contraintes internes d'architecture, dont le
programmeur C n'a que faire).


Le code
float* prt1;
déclare un pointeur prt1 qui désignera un float.


déclare une variable (de type pointeur sur float)


Si tu veux pinailler : cela dépend de l'endroit où se trouve la lige de
code. Parfois ce sera une déclaration, parfois (le plus souvent, en fait),
ce sera une définition.

[...] ptr1,


denoté par l'identificateur ptr1

[...] qui stockera une adresse mémoire


Ça, c'est l'implémentation. Rien n'oblige le compilateur à réellement
réserver d'adresse mémoire.

Par ailleurs, les règles du C disent qu'en fait, (le contenu dénoté par)
ptr1 désigne un élément d'un tableau (éventuellemnt dégénéré) de float;
autrement dit, si les tableaux sont alignés d'une certaine façon, ptr1 doit
nécessairement l'être, et ne peut être une adresse mémoire "quelconque" ;
idem si les floats ont des particularités de représentations.


[...] dont le contenu sera interprété comme un float
quand on déréférencera le pointeur (nb: opération consistant à lire
le contenu du bloc mémoire dont le pointeur donne l'adresse).


Pas exactement. Le déréférencement n'implique pas la lecture mémoire.


Mais ce float
n'est pas construit lorsque l'on déclare le pointeur.
L'instruction 'malloc(sizeof(float))' cherche de la place pour
stoquer un float. Si elle réussit (laissons de côté pour commencer
la getsion des échec), un tels float est créé.


s/un tels float est créé/un bloc mémoire d'une taille suffisante pour
stocker un float est réservée, et son adresse de départ retournée/.


Pas forcément. En fait, pas dans beaucoup d'implémentations de malloc, car
malloc a besoin (pour satisfaire les besoins de free) de conserver des
informations de maintenance, en particulier la taille du dit bloc; et
souvent (au moins dans l'algorithme "historique") cette information est
rangée au début du bloc, et la valeur retournée n'est pas le début du bloc,
mais quelque cases plus loin.



Mais tout cela est du pinaillage qui n'aidera en rien "prat", qui de toute
manière ne semble pas s'intéresser beaucoup à cette discussion.
Aurions-nous mordu à l'hameçon d'un bon vieux troll des familles ?


Antoine


Avatar
Antoine Leca
Bruno Desthuilliers écrivit:
int main(void) /* au minimum */


Ben non. Il me semble bien que
int main()
est tout à fait correct.
9.4 Quels sont les prototypes valides de main() ?

Oui, mais il ne s'agit pas AMHA d'un prototype ici,



En l'absence de déclaration préablable (ce qui est généralement le
cas pour main() !-), la définition vaut déclaration...


Oui. Et ? Quel rapport avec les prototypes ?


mais de la declaration de la fonction.


s/déclaration/définition/


Yep.


Si ma mémoire est bonne, le cas de main() est particulier, en ce que
c'est le point d'entrée du programme. Il y a donc une convention à
respecter entre le programme et l'environnement hôte.


Oui. En l'occurence, cette convention est exprimée par les possibles
prototypes que vous citâtes. Et il se trouve que "int main(){" la respecte
aussi (bien obligé, puisque c'est la formulation qui à l'origine de tout ce
capharnaüm!)

Toute
implémentation conforme à la norme garantie que les deux signatures
mentionnées sont valides. En dehors de ça, c'est au bon vouloir de
l'implémentation et de la plateforme hôte. En l'occurrence, et si ma
mémoire est bonne, la signature que tu proposes déclare une fonction
prenant un nombre indéterminé d'arguments...


Non. Comme il s'agit d'une définition (remarque pertinente que vous fîtes
plus haut), il se trouve qu'il n'y a PAS de paramètres (rien entre les
parenthèses), donc le nombre d'argument à passer est de zéro, ce qui est
compatible avec le prototype "int main(void);".


Antoine





Avatar
Bruno Desthuilliers
Bruno Desthuilliers écrivit:
int main(void) /* au minimum */
Ben non. Il me semble bien que

int main()
est tout à fait correct.
9.4 Quels sont les prototypes valides de main() ?

Oui, mais il ne s'agit pas AMHA d'un prototype ici,

En l'absence de déclaration préablable (ce qui est généralement le

cas pour main() !-), la définition vaut déclaration...


Oui. Et ? Quel rapport avec les prototypes ?


mais de la declaration de la fonction.
s/déclaration/définition/



Yep.


Si ma mémoire est bonne, le cas de main() est particulier, en ce que
c'est le point d'entrée du programme. Il y a donc une convention à
respecter entre le programme et l'environnement hôte.


Oui. En l'occurence, cette convention est exprimée par les possibles
prototypes que vous citâtes. Et il se trouve que "int main(){" la respecte
aussi (bien obligé, puisque c'est la formulation qui à l'origine de tout ce
capharnaüm!)


lol !-)

Toute
implémentation conforme à la norme garantie que les deux signatures
mentionnées sont valides. En dehors de ça, c'est au bon vouloir de
l'implémentation et de la plateforme hôte. En l'occurrence, et si ma
mémoire est bonne, la signature que tu proposes déclare une fonction
prenant un nombre indéterminé d'arguments...


Non. Comme il s'agit d'une définition (remarque pertinente que vous fîtes
plus haut),


S'il n'y a pas eu de déclaration préalable, il s'agit aussi d'une
déclaration, non ?






Avatar
Bruno Desthuilliers
(snip)
Si le bouquin n'explique pas celà, il est de bien piètre qualité.
Un pointeur ne sert qu'à désigner une *autre* variable.
s/désigner une *autre* variable/stocker une adresse mémoire/



Non, la presentation que tu donnes est ce qui est fait par les
compilateurs, et qui parait naturelle pour quiconque a des bases
d'assembleur, mais ce n'est qu'un moyen de realiser une semantique.


Je n'ai aucune connaissance en assembleur, et j'ai compris les pointeurs
quand on m'a expliqué la gestion de la mémoire. Et quoi qu'on en dise,
la sémantique du C est quand même très liée au fonctionnement effectif
de la machine...

Dans un interpreteur C, un pointeur pourrait tout a fait stoquer
une chaine qui soit le nom de la variable.


Laquelle chaine servirait de clé dans une table de haschage, permettant
d'accéder à la valeur associée. Auquel cas cette chaine est de facto
l'équivalent d'une adresse mémoire !-)


ptr1= malloc(sizeof(float));
signifie alors que ptr1 désigne la variable nouvellement crée.
s/désigne la variable nouvellement crée/a pour valeur l'adresse de

départ du bloc mémoire réservé/.


Ce qui est equivalent.


Pas pour moi. Chacun sa façon de comprendre, n'est-ce pas ?-)



Avatar
Marc Boyer
Bruno Desthuilliers
a écrit :
(snip)
Si le bouquin n'explique pas celà, il est de bien piètre qualité.
Un pointeur ne sert qu'à désigner une *autre* variable.
s/désigner une *autre* variable/stocker une adresse mémoire/



Non, la presentation que tu donnes est ce qui est fait par les
compilateurs, et qui parait naturelle pour quiconque a des bases
d'assembleur, mais ce n'est qu'un moyen de realiser une semantique.


Je n'ai aucune connaissance en assembleur, et j'ai compris les pointeurs
quand on m'a expliqué la gestion de la mémoire.


Et bien oui, dans une promo de 80, il y en a toujours 2 qui
comprennent du premier coup. Enseigner, c'est aussi travailler pour
les autres.

Et quoi qu'on en dise,
la sémantique du C est quand même très liée au fonctionnement effectif
de la machine...


oui, mais si on la presente a des gens qui n'ont pas (assez) de connaissance
du fonctionnement de la machine, on fait quoi ?

ptr1= malloc(sizeof(float));
signifie alors que ptr1 désigne la variable nouvellement crée.
s/désigne la variable nouvellement crée/a pour valeur l'adresse de

départ du bloc mémoire réservé/.


Ce qui est equivalent.


Pas pour moi. Chacun sa façon de comprendre, n'est-ce pas ?-)


Oui, mais je n'avais pas l'intention de t'apprendre quoi que
ce soit, mais de m'adresser a l'OP. C'est toi qui es venu me porter
la contradiction.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)




Avatar
Pascal Bourguignon
Bruno Desthuilliers writes:
Je n'ai aucune connaissance en assembleur, et j'ai compris les
pointeurs quand on m'a expliqué la gestion de la mémoire. Et quoi
qu'on en dise, la sémantique du C est quand même très liée au
fonctionnement effectif de la machine...


De certaines machines.

D'accord, la plupart des processeurs fabriqué de nos jours
fonctionnent comme ça, mais on peut facilement se bricoler (par
exemple en FGPA, ou en machine virtuelle) un processeur qui gère la
mémoire différement.


Dans un interpreteur C, un pointeur pourrait tout a fait stoquer
une chaine qui soit le nom de la variable.


Laquelle chaine servirait de clé dans une table de haschage,
permettant d'accéder à la valeur associée. Auquel cas cette chaine est
de facto l'équivalent d'une adresse mémoire !-)


Oui, mais ces "adresses" ne sont pas des valeurs arithmétiques. On ne
peut pas les incrémenter bêtement et "pointer" vers une case mémoire
aléatoire, puisqu'il n'y en a pas, il n'y a que des variables avec
leurs noms.

--
__Pascal Bourguignon__ http://www.informatimago.com/

"Indentation! -- I will show you how to indent when I indent your skull!"


Avatar
Antoine Leca
Bruno Desthuilliers écrivit:

Comme il s'agit d'une définition


S'il n'y a pas eu de déclaration préalable, il s'agit aussi d'une
déclaration, non ?


Certes, mais ici on s'en moque. Une déclaration n'a importance que pour
l'utilisation d'un nom, et le programme n'utilise pas le nom main.


Antoine


1 2 3 4 5