OVH Cloud OVH Cloud

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

2 3 4 5 6
Avatar
Antoine Leca
Harpo wrote:
Antoine Leca wrote:

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.


Il peut vouloir appeler main recursivement.


Oui. Et auquel cas il serait bien d'avoir un prototype (ce que n'est
/jamais/ la définition "int main(){", même après la définition de main).

Mais ce n'était pas le cas *ici*.


Antoine


Avatar
Pierre Maurette
Antoine Leca wrote:

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.


Il peut vouloir appeler main recursivement.


Il peut vouloir, mais il ne peut pas le faire, il me semble.

--
Pierre Maurette


Avatar
Antoine Leca
Pierre Maurette wrote:
Antoine Leca wrote:

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.


Il peut vouloir appeler main recursivement.


Il peut vouloir, mais il ne peut pas le faire, il me semble.


Pourquoi pas?
En fait, il peut même le faire sans déclarer de prototype, et ce que main()
soit déclaré avec 0 ou 2 paramètres.

/* exemple1.c */
int main() {
if(getchar()!='s') {
puts("Taper s pour sortir!");
main();
}
return 0;
}


/* exemple2.c */
#include <stdio.h> /* pour printf() */
int main(argc, argv) char*argv[];
int argc; /* pour satisfaire la norme C99; était inutile avant */
{
if (argc--) {
printf("%s ", *argv++);
main(argc, argv);
} else {
putchar('n');
}
return 0;
}


Mélanger (appeler main(c,v) dans le premier exemple) doit être indéfini, et
de toute manière cépabô.


Antoine



Avatar
Pierre Maurette
Pierre Maurette wrote:
Antoine Leca wrote:

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.


Il peut vouloir appeler main recursivement.


Il peut vouloir, mais il ne peut pas le faire, il me semble.


Pourquoi pas?


Me suis gourré. Je ne sais pas ce qui m'a mis ça dans la tête, ce n'est
pas la première fois que je me trompe là-dessus. Ce doit être interdit
en C++.

--
Pierre Maurette




Avatar
Bruno Desthuilliers
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 bien oui, dans une promo de 80, il y en a toujours 2 qui
comprennent du premier coup.


je ne fais partie d'aucune promo, étant essentiellement autodidacte, et
je suis loin (très loin) d'avoir compris "du premier coup". C'est
justement quand j'ai trouvé des explications similaires à celles que je
donnais à l'OP que j'ai commencé à comprendre... Je sais que tant que
j'ai eu des explications telles que les tiennes, en tous cas, ça ne
tiltait pas pour moi.

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 ?


On leur explique le fonctionnement de la machine ?


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.


Tu peux le voir comme ça. Tu peux aussi prendre mon intervention comme
une autre façon d'expliquer le concept. Avec un peu de chance, l'une ou
l'autre (ou la combinaison des deux...) permettra à l'OP (ou à un autre
lecteur) de comprendre le sujet - ce qui est l'essentiel, non ?





Avatar
espie
C'est effectivement interdit en C++, mais autorise en C.

Ceci-dit, je ne ferais pas confiance a toutes les implementations sur
ce point de detail... Si j'ai envie d'appeler main() recursivement,
je vais plutot definir une fonction recursive et l'appeler directement
a partir du main.

Et bon, souvent, l'appel recursif a main n'est qu'une bonne idee en
apparence. Souvent, on se retrouve lors d'une evolution ulterieure a
revenir des choses plus standard, parce que l'appel initial a main()
a du nettoyage en plus a faire, ce qui n'est pas le cas des appels
ulterieurs...
Avatar
Marc Boyer
Bruno Desthuilliers a écrit :
Bruno Desthuilliers

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.


je ne fais partie d'aucune promo, étant essentiellement autodidacte,


Et moi, je ne parle pas de mon expérience d'apprenant (car vu que j'ai
commencé vers 12-13 ans, je n'ai aucun souvenir du moment ou j'ai
compris les pointeurs), mais de ce que je vois des cours que je donne.
Et je vois bien que les explications à base d'adresse ne passent
pas, hormis pour une minorité.

et
je suis loin (très loin) d'avoir compris "du premier coup". C'est
justement quand j'ai trouvé des explications similaires à celles que je
donnais à l'OP que j'ai commencé à comprendre... Je sais que tant que
j'ai eu des explications telles que les tiennes, en tous cas, ça ne
tiltait pas pour moi.


Je ne suis pas contre la diversité des explications, loin de là.
Et je me sers aussi des notions d'adresse et d'accès mémoire. Mais
je ne commence pas avec ça.
En fait, je parle aussi de poignée de casserole, de numéro de
téléphone portable, etc.

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 ?


On leur explique le fonctionnement de la machine ?


Et on rajoute 6h de cours et 6h de TD d'archi des ordis à l'emplois
du temps parce que le prof qui enseigne le C en a besoin pour illustrer
la notion de pointeur ? Ben non, on a pas assez d'heures à l'emploi
du temps pour jouer à ça.

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.


Tu peux le voir comme ça. Tu peux aussi prendre mon intervention comme
une autre façon d'expliquer le concept. Avec un peu de chance, l'une ou
l'autre (ou la combinaison des deux...) permettra à l'OP (ou à un autre
lecteur) de comprendre le sujet - ce qui est l'essentiel, non ?


Si j'avais pris cela comme une *autre* façon, je n'aurais rien dit.
C'est parce que ton s/../../ ressemblait à un remplacement, une
correction, que j'ai réagit.
Ce que tu as présenté, c'est l'implantation naturelle.

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
espie
In article ,
prat wrote:
bonjour,

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

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

/*allocation dynamique */
pr1=malloc(sizeof(float));
pr2=malloc(sizeof(float));
pr3=malloc(sizeof(float));
Mes questions sont:
-les pointeurs ont été déclaré initialement à la première
instruction,pourquoi en plus une allocation dynamique avec malloc( ) et
free( )?Est-elle nécessaire?


Erreur tres classique de debutant: un pointeur pointe quelque part, mais
il *faut* lui donner quelque chose sur quoi pointer. Pour un type T, si tu
declares T *p, tout ce que tu as, c'est un pointeur qui peut pointer sur
un objet de type T.

A la limite, pedagogiquement, je te conseillerais bien d'ecrire plutot

T *p = 0;

comme ca, tu auras la garantie d'avoir un pointeur nul. Et ca te rappelera
qu'il faut aussi lui donner un objet sur lequel pointer.

-aurai-je pu utiliser l'allocation dynamique sans avoir au préalable
déclaré mes pointeurs comme à la première instruction?


Et tu ferais comment ? il faut bien stocker le resultat de malloc quelque
part.

En C99, tu peux declarer tes pointeurs ou tu veux, donc
float *ptr1 = malloc(sizeof *ptr1);
fonctionne tres bien. Encore faut-il verifier que malloc a trouve de la
place, et donc que ptr1 != 0, mais ca d'autres l'ont deja dit.

En fait, cet exemple est relativement mal choisi, car il melange allocation
dynamique et pointeurs de facon purement gratuite. Dans ce cas precis, on
n'a besoin, ni d'allocation dynamique, ni de variables pointeurs.

On peut betement se contenter de declarer trois float:
float f1, f2, f3;

et de passer leur adresse a scanf: scanf("%f", &f1);

Un pointeur se doit d'etre soit nul, soit pointant vers un objet du bon type.
Que l'objet soit sur la pile, global au programme, ou alloue dynamiquement
ne change rien a l'affaire (enfin bon, il faudra eventuellement se preoccuper
de la duree de vie de l'objet pointe).

Enfin ca, c'est si on veut des resultats previsibles. Un pointeur juste
alloue par
float *p;
ne pointe `sur rien' et le dereferencer peut provoquer n'importe quoi
(stricto-sensu, juste regarder sa valeur peut provoquer n'importe quoi).

C'est pourquoi j'aurais tendance a recommander de ne jamais mettre de
declaration sans la valeur initiale qui va avec, quitte a ne declarer les
variables que quand on sait quoi mettre dedans, ce que permet C99...

Avatar
Pascal Bourguignon
(Marc Espie) writes:


C'est pourquoi j'aurais tendance a recommander de ne jamais mettre de
declaration sans la valeur initiale qui va avec, quitte a ne declarer les
variables que quand on sait quoi mettre dedans, ce que permet C99...


Et même le vieux K&R C, avec les accolades:

int f(int x){
int y=x+1;
g(y);
{
int z=y+1;
h(z);
{
int w=z-4;
i(w);
}}}


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

"Specifications are for the weak and timid!"

Avatar
espie
In article ,
Pascal Bourguignon wrote:
(Marc Espie) writes:


C'est pourquoi j'aurais tendance a recommander de ne jamais mettre de
declaration sans la valeur initiale qui va avec, quitte a ne declarer les
variables que quand on sait quoi mettre dedans, ce que permet C99...


Et même le vieux K&R C, avec les accolades:

int f(int x){
int y=x+1;
g(y);
{
int z=y+1;
h(z);
{
int w=z-4;
i(w);
}}}


Deja, ce que tu ecris, c'est pas du C K&R. Rien que la presence d'un
prototype te plombe.

Ensuite, tu as des contraintes tres fortes sur ce que tu as le droit
de mettre dans une expression d'initialisation en C traditionnel, contraintes
qui ont ete levees en C99.


2 3 4 5 6