OVH Cloud OVH Cloud

Question honteuse

27 réponses
Avatar
Stephane Legras-Decussy
bonjour,

j'ai honte poser une question aussi basique
mais je ne dois pas avoir les yeux en face des trous
et je ne comprend pas ce qui ne va pas depuis plusieures heures :

#include <stdio.h>
#include<conio.h>
#include<stdlib.h>


typedef struct
{
int nbr;

}AA;

void init(AA *aa)
{ aa= (AA*)malloc(sizeof(AA));

}


int main(int argc, char *argv[])
{ AA *aa=NULL;

// init(aa); // (1)

aa= (AA*)malloc(sizeof(AA)); // (2)

aa->nbr=10; // (3)

printf("%d\n",aa->nbr);

getch();

free(aa);

return 0;
}


si j'écris la ligne (2), tout va bien, si je remplace par la ligne (1) alors
le prog crash en ligne (3).

pourquoi ??? ça m'énerve de pas trouver...

7 réponses

1 2 3
Avatar
Emmanuel Delahaye
cedric wrote on 25/03/05 :

Si on veut bien, au contraire de M. Bourguet, considérer que l'architecture
des ordis n'est pas une simple vue de l'esprit, le fait est que les
paramètres sont effectivement bien souvent semblables à des variables
automatiques, par construction. Merci aux inventeurs du C de ne pas avoir
tentés de faire croire le contraire !


Je suis d'accord.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"There are 10 types of people in the world today;
those that understand binary, and those that dont."

Avatar
gregg
Emmanuel Delahaye wrote:

Je ne dois pas être aussi intégriste ou dogmatique que certains le
prédentent, parce que je ne suis pas d'accord. La solution générale pour


Ces gens confondent peut-être "intégriste" et "puriste" ;-)


où l'utilisation du paramètre comme variable locale peut avoir un sens,
notammet pour gagner un peu de place en mémoire automatique sur de
petites fonctions simples et évoluant peu... (à l'occasion d'un
refactoring, par exemple)


Je croyais que les paramètres étaient placés sur la pile. Qui est
l'endroit de création des variables locales à une fonction.
Non ?

Auquel cas, créer une variable locale en lui affectant la valeur du
paramètre serait une perte d'espace et d'opérations.
(je dis "perte" au sens de "redondant").

A ne pas mettre entre les mains des débutants complets[1].
Personnellement, je suis passé par le BASIC (un désastre), le Pascal (la
Révélation), et quelques assembleurs (années 85/90...).


Pas d'Ada ?
Ca me paraît bien pour commencer, Ada.
Et si vraiment on ne veut pas continuer, le passage au C me paraît aisé.

++

Avatar
Emmanuel Delahaye
gregg wrote on 25/03/05 :
Pas d'Ada ?


Hélas non.

Ca me paraît bien pour commencer, Ada.
Et si vraiment on ne veut pas continuer, le passage au C me paraît aisé.


Je pense que j'aurais bien aimé ça... Le Pascal (Turbo Pascal, bien
sûr) a joué ce rôle de préparation à la rigueur.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"

Avatar
gregg
Horst Kraemer wrote:

on parle d'un "abus" de paramètre comme ceci

unsigned fac(unsigned n)
{
unsigned f=1;
while (n>1) f*=n--;
return f;
}


En quoi est-ce un abus dans la mesure où le paramètre de toutes les
façons garde sa valeur initiale (c'est à dire à l'entrée dans la
fonction), puisque passé par valeur ?

vous préconisez plutôt ça, alors:

unsigned fac (unsigned n) {
unsigned tmp = n, f=1;
while ( tmp > 1 ) f *= tmp--;
return f;
}


??

++

Avatar
cedric
Emmanuel Delahaye wrote:
Je suis d'accord.


Je m'y attendais.

Avatar
Bruno Jouhier
"Emmanuel Delahaye" a écrit dans le message de news:

Bruno Jouhier wrote on 25/03/05 :
on parle d'un "abus" de paramètre comme ceci

unsigned fac(unsigned n)
{
unsigned f=1;
while (n>1) f*=n--;
return f;
}


Tout à fait. Ca serait tellement plus propre si C faisait la distinction
entre paramètre et variable locale, et s'il interdisait de réassigner un
paramètre (si le paramètre est déclaré comme T* param, il devrait
interdire de réassigner param mais bien sûr permettre d'assigner
*param).. Ca serait cohérent avec la sémantique de passage d'argument, et
ça éviterait des erreurs stupides comme celle à l'origine de cette
discussion.


Je ne dois pas être aussi intégriste ou dogmatique que certains le
prédentent, parce que je ne suis pas d'accord. La solution générale pour
préserver la valeur des paramètres est de les qualifier avec 'const' comme
je l'ai déjà exposé. Mais il est des cas rares, mais qui existent où
l'utilisation du paramètre comme variable locale peut avoir un sens,
notammet pour gagner un peu de place en mémoire automatique sur de petites
fonctions simples et évoluant peu... (à l'occasion d'un refactoring, par
exemple)


Un bon compilateur doit être capable d'optimiser
void f(int i) { int tmp = i; faire_qque_chose_avec_tmp; }
en
void f(int i) { faire_qque_chose_avec_i; }

Le problème à l'origine de cette discussion vient **uniquement** du fait que
le C autorise à réassigner aa (voir l'exemple initial). Si le langage
interdisait de traiter les paramètres comme des variables (au sens litéral
du terme), le langage serait plus "naturel" et ce genre de confusion
n'arriverait pas.

D'une manière plus générale, ce n'est pas parce deux concepts sont
implémentés de la même manière (paramètres et variables locales sont tous
les 2 alloués sur la pile), qu'il ne faut pas les différencier. Il y a
souvent des raisons "sémantiques" qui justifient qu'on les différencie.

Une partie des défauts du C vient de ce genre de focalisation excessive sur
l'implémentation, au détriment de la sémantique. L'absence de type booléen
en est un autre bon exemple. Le raisonnement est en gros le suivant : les
tests booléens sont implémentés comme des tests à zéro, donc on peut
considérer que toute valeur non nulle est vraie, et donc on n'a pas besoin
d'un type booléen).

D'un point de vue sémantique, un paramètre passé par valeur n'est pas une
variable, et un pointeur non nul n'est pas la valeur booléenne true. Au
niveau de l'implémentation, ces différences s'estompent, mais elles ont
pourtant un intérêt car elles rendent le langage plus expressif et plus sûr.


La question n'est donc pas honteuse, ce sont les designers de langage qui
devraient avoir honte!


Non. Le C reste un modèle d'efficacité et de compacité. Mais comme je le
rappelle souvent:


Ici, ma critique visait surtout Java et C#. Le C et le C++ doivent maintenir
des compatibilités "historiques" et ça serait difficile à changer (mais on
pourrait avoir une option de compilation pour contrôler ça). Les designers
de Java et C# auraient pu faire un effort et corriger ce problème de
sémantique des paramètres (heureusement, ils ont quand même pensé à
introduire un type booléen).

D'un autre côté, je ne devrais pas me plaindre, il m'est arrivé de gagner
une bouteille de champagne en pariant avec un programmeur Java (pas vraiment
débutant mais qui devait avoir l'esprit embrumé) qu'une réaffectation de
paramètre était sans effet sur le code appelant ;-)

Bruno.


"C is a sharp tool"

A ne pas mettre entre les mains des débutants complets[1].
Personnellement, je suis passé par le BASIC (un désastre), le Pascal (la
Révélation), et quelques assembleurs (années 85/90...).

-------------
[1] Je précise pour les ânes qui ne savent pas lire...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.





Avatar
Horst Kraemer
gregg wrote:

Horst Kraemer wrote:

on parle d'un "abus" de paramètre comme ceci

unsigned fac(unsigned n)
{
unsigned f=1;
while (n>1) f*=n--;
return f;
}


En quoi est-ce un abus dans la mesure où le paramètre de toutes les
façons garde sa valeur initiale (c'est à dire à l'entrée dans la
fonction), puisque passé par valeur ?

vous préconisez plutôt ça, alors:

unsigned fac (unsigned n) {
unsigned tmp = n, f=1;
while ( tmp > 1 ) f *= tmp--;
return f;
}


??


Si vous savez garder un secret: non. ;-)

--
Horst


1 2 3