Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).

#1 09-03-2014 09:58:36

Hypathie
Membre
Lieu : Chambéry _ Montréal
Distrib. : Jessie
Noyau : Linux debian 3.16.0-4-586
(G)UI : Cinnamon Mate Xfce
Inscription : 28-12-2013

[résolu]comment analyser l'appel d'une fonction dans le main en c ?

Bon j'aurais besoin d'un aide pour comprendre ce qu'il se passe du point de vue "de la machine lorsqu'on appelle une fonction dans un main.

Je suis partie d'un programme qui a pour but d'inverser les deux valeurs d'un main, ainsi :


#include<stdio.h>
int main(void){
 int a=1;
 int b=2;
printf("a:%d\nb:%d\n",a,b);
 int c;
 c=a;
 a=b;
 b=c;
printf("a:%d\nb:%d\n",a,b);
}
 



Puis l'idée est d'obtenir le même résultat


a:1
b:2
a:1
b:2
 



mais en utilisant une fonction.

J'ai d'abord voulu faire ceci qui ne fonctionne pas :


#include<stdio.h>
void inverser(int x, int y){
 int c;
 c=x;
 x=y;
 y=c;
}
int main(void){
 int a=1;
 int b=2;
printf("a:%d\nb:%d\n",a,b);
 inverser(x,y);
printf("x:%d\ny:%d\n",x,y);
}
 



essai.c: In function ‘main’:
essai.c:12:11: error: ‘x’ undeclared (first use in this function)
essai.c:12:11: note: each undeclared identifier is reported only once for each function it appears in
essai.c:12:13: error: ‘y’ undeclared (first use in this function)
a:1
b:2
a:1
b:2
 



Puis par tâtonnement, j'ai trouvé ceci qui fonctionne mieux :


#include<stdio.h>
void inverser(int x, int y){
 int c;
 c=x;
 x=y;
 y=c;
printf("a:%d\nb:%d\n",a,b);
}
int main(void){
 int a=1;
 int b=2;
printf("a:%d\nb:%d\n",a,b);
 inverser(a,b);
}
 



Voilà l'explication que je me fais :

il commence par le main et exécute le premier printf;
puis il lit "fonction 'inverser'" à appliquer sur a et b;
puis il écrit (deuxième printf) c'est-à-dire, les valeurs de a et de b, affectées à x et y, que le programme a conservé lors de sa "lecture de la fonction ;

Pour expliquer cette inversion des valeurs de a et b, est-ce que je peux me dire ceci :

à ce niveau :


c=x;
x=y;
y=c;
 



c=x c'est-à-dire, x est affecté de la valeur du "int a" du main qui est 1
et
x=y c'est-à-dire, x est affecté de la valeur de y qui celle de b, qui a lui-même la valeur de "int b" du main, c'est-à-dire 2
et
y=c c'est-à-dire, y est affecté de la valeur de c qui est celle conservée par c=x qui est 1

C'est que ce qui est ( ) dans la fonction conserve les valeurs affectées au variables du "main", sans que les variables de la fonction doivent s'appeler du même nom que ceux donnés dans le main.

Sinon, comment l'appel de la fonction dans ce cas fonctionnerait-il ?

Merci d'avance.

Dernière modification par Hypathie (09-03-2014 14:29:45)

Hors ligne

#2 09-03-2014 11:20:22

captnfab
Admin-Girafe
Lieu : /dev/random
Distrib. : Debian Stretch/Sid/Rc-Buggy
Noyau : Linux (≥ 4.3)
(G)UI : i3-wm (≥ 4.11)
Inscription : 07-07-2008
Site Web

Re : [résolu]comment analyser l'appel d'une fonction dans le main en c ?

Hypathie a écrit :

Bon j'aurais besoin d'un aide pour comprendre ce qu'il se passe du point de vue "de la machine lorsqu'on appelle une fonction dans un main.


L'explication que je vais donner est aussi valide pour l'appel d'une fonction depuis n'importe quelle fonction.

Appelons ton premier programme « Inversion en ligne » :

#include<stdio.h>
int main(void)
{
  int a=1;
  int b=2;
  printf("a:%d\nb:%d\n",a,b);
  int c;
  c=a;
  a=b;
  b=c;
  printf("a:%d\nb:%d\n",a,b);
}
 



Voici le déroulement en mémoire :
Trois cases sont créées contenant les valeurs de a, b et c :

[1] [2] [?]

Puis tu fais les affectations entre ces cases :
[1] [2] [1] (c?a)
[2] [2] [1] (a?b)
[2] [1] [1] (b?c)

Appelons ce second programme « Inversion dans la fonction » :

#include<stdio.h>
void inverser(int x, int y)
{
  int c;
  c=x;
  x=y;
  y=c;
}

int main(void)
{
  int a=1;
  int b=2;
  printf("a:%d\nb:%d\n",a,b);
  inverser(a,b);
  printf("a:%d\nb:%d\n",a,b);
}



Ça commence pareil avec deux cases mémoire :
[1] [2]

Puis ça appelle la fonction inverser. À ce moment, tous les arguments sont copiés, donc on a en mémoire :
[1] [2] | [1] [2]
Ou les deux premières cases correspondent aux a et b de main et les deux suivantes à x et y.
Note que si tu avais appelé les deux variables de inverser a et b au lieu de x et y, ça n'aurait absolument rien changé. Les noms de variables sont locaux à une fonction, et c'est très bien comme ça (i.e. utiliser des variables globales est quasi tout le temps la pire solution).

Ensuite, tu fais l'inversion via une case supplémentaire stockant c :
[1] [2] | [1] [2] [?]
[1] [2] | [1] [2] [1] (c?x)
[1] [2] | [2] [2] [1] (x?y)
[1] [2] | [2] [1] [1] (y?c)

Puis la fonction se termine et avec elle est détruite toute la zone mémoire la concernant, on se retrouve donc avec :
[1] [2]

Toi, tu voudrais modifier la valeur des premières cases. Pour ce faire, il ne faut pas que tu transmettes leurs valeurs à la fonction inverser, mais leur adresse.
Appelons ce troisième programme « Inversion par la fonction » :

#include<stdio.h>
void inverser(int* x, int* y)
{
  int c;
  c=*x;
  *x=*y;
  *y=c;
}

int main(void)
{
  int a=1;
  int b=2;
  printf("a:%d\nb:%d\n",a,b);
  inverser(&a,&b);
  printf("a:%d\nb:%d\n",a,b);
}



Cette fois-ci, que se passe-t-il ?
Ça commence de la même manière :
[1] [2]

Puis tu passes deux arguments qui sont les adresses :
[1] [2] | [&a@main] [&b@main]

Tu fais l'échange via une variable c qui va piocher à l'adresse (c'est le fait de la petite étoile) :
[1] [2] | [&a@main] [&b@main] [?]
[1] [2] | [&a@main] [&b@main] [1] (c?*x =a@main = 1)
[2] [2] | [&a@main] [&b@main] [1] (*x = a@main ? *y = b@main)
[2] [1] | [&a@main] [&b@main] [1] (*y = b@main ? c)
[2] [1]

Et hop smile

Note que l'écriture a@main / &a@main n'est que pour clarifier la chose, ça n'est pas du C, n'écris pas ça dans ton code smile


captnfab,
Association Debian-Facile, bépo.
TheDoctor: Your wish is my command… But be careful what you wish for.

Hors ligne

#3 09-03-2014 12:43:30

Hypathie
Membre
Lieu : Chambéry _ Montréal
Distrib. : Jessie
Noyau : Linux debian 3.16.0-4-586
(G)UI : Cinnamon Mate Xfce
Inscription : 28-12-2013

Re : [résolu]comment analyser l'appel d'une fonction dans le main en c ?

smile merci beaucoup, c'est sûr que c'est plus 'facile' avec les pointeurs, et surtout merci pour le vocabulaire.

Mais avant d'utiliser un pointeur, je ne comprends pas quelque chose au niveau simplement de l'appelle d'une fonction.
D'ailleurs j'ai fait une grosse confusion entre utilisation de l'appel d'une fonction sans utiliser de pointeur dans mon #1, avec l'utilisation avec pointeurs big_smile

hypathie a écrit :



#include<stdio.h>
void inverser(int x, int y){
 int c;
 c=x;
 x=y;
 y=c;
printf("a:%d\nb:%d\n",a,b);
}
int main(void){
 int a=1;
 int b=2;
printf("a:%d\nb:%d\n",a,b);
 inverser(a,b);
}
 



C'est à moitié faux, il renvoie en fait :

essai.c: In function ‘inverser’:
essai.c:7:23: error: ‘a’ undeclared (first use in this function)
essai.c:7:23: note: each undeclared identifier is reported only once for each function it appears in
essai.c:7:25: error: ‘b’ undeclared (first use in this function)
a:1
b:2
a:2
b:1
 



ce qui fonctionne c'est :


#include<stdio.h>
void inverser(int a, int b){
 int c;
 c=a;
 a=b;
 b=c;
printf("a:%d\nb:%d\n",a,b);
}
int main(void){
 int a=1;
 int b=2;
printf("a:%d\nb:%d\n",a,b);
 inverser(a,b);
}
 



Pourquoi faut-il nommer les variables de la fonction a et b comme les variables du main, puisque c'est (en tout cas selon ce que j'en comprends) la valeur qui est appelée ; surtout s'il ne s'agit plus du même a et du même b dans la fonction et le main, puisque tout est effacé de la mémoire ?

Ce qui est ( ) dans la fonction, correspond bien au valeur des variables du main ?
Moi je m'expliquais les choses en me disant : le premier int (ligne deux dans la fonction) correspond au premier int du main (ligne 10) ; et le deuxième int de la fonction (même parenthèse, ligne deux) correspond à celui de la ligne 11).
Dans cette idée, on devrait bien appeler les variables de la fonction comme on veut, puisque niveau mémoire ce n'est plus les mêmes, mais qu'il y a dans la fonction des correspondances avec les valeurs des variables a et b du main ? Eh bien on dirait que  non, et je ne comprends pas pourquoi big_smile

Comment lirais-tu le code ci-dessus s'il te plaît ?

Hors ligne

#4 09-03-2014 12:46:41

captnfab
Admin-Girafe
Lieu : /dev/random
Distrib. : Debian Stretch/Sid/Rc-Buggy
Noyau : Linux (≥ 4.3)
(G)UI : i3-wm (≥ 4.11)
Inscription : 07-07-2008
Site Web

Re : [résolu]comment analyser l'appel d'une fonction dans le main en c ?

C'est ton printf dans inverser. Il fait référence à a et b alors que dans la fonction inverser tu n'as que x et y.

captnfab,
Association Debian-Facile, bépo.
TheDoctor: Your wish is my command… But be careful what you wish for.

Hors ligne

#5 09-03-2014 12:49:08

captnfab
Admin-Girafe
Lieu : /dev/random
Distrib. : Debian Stretch/Sid/Rc-Buggy
Noyau : Linux (≥ 4.3)
(G)UI : i3-wm (≥ 4.11)
Inscription : 07-07-2008
Site Web

Re : [résolu]comment analyser l'appel d'une fonction dans le main en c ?

#include<stdio.h>
void inverser(int a, int b)
{
  int c;
  c=a;
  a=b;
  b=c;
  printf("a:%d\nb:%d\n",a,b);
}
int main(void)
{
  int a=1;
  int b=2;
  printf("a:%d\nb:%d\n",a,b);
  inverser(a,b);
}
 



[1] [2]
> affichage de « a: 1 b: 2 »
[1] [2] | [1] [2]
[1] [2] | [1] [2] [?]
[1] [2] | [1] [2] [1]
[1] [2] | [2] [2] [1]
[1] [2] | [2] [1] [1]
> affichage de « a: 2 b: 1 »
[1] [2]


captnfab,
Association Debian-Facile, bépo.
TheDoctor: Your wish is my command… But be careful what you wish for.

Hors ligne

#6 09-03-2014 14:29:23

Hypathie
Membre
Lieu : Chambéry _ Montréal
Distrib. : Jessie
Noyau : Linux debian 3.16.0-4-586
(G)UI : Cinnamon Mate Xfce
Inscription : 28-12-2013

Re : [résolu]comment analyser l'appel d'une fonction dans le main en c ?

Merci captnfab

smile

Hors ligne

Pied de page des forums