Bonjour,
je me pose actuellement une question : lorsque l'on programme en C l'affectation d'un tableau t1=T2 se fait par ou une recopie ?
merci
Bonjour,
je me pose actuellement une question : lorsque l'on programme en C l'affectation d'un tableau t1=T2 se fait par ou une recopie ?
merci
La recopie case à case est impossible en C et sera rejetée par le compilateur. Il faut utiliser memcpy pour recopier case à case (ou une boucle pour parcourir le tableau).
Maintenant, si le compilateur autorise l'affectation, c'est que c'est une copie de pointeur qui a été faite.
La règle est très simple, un tableau est toujours passé par adresse à une fonction
Raymond
Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi
CafuroCafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
e-verbeUn logiciel de conjugaison des verbes de la langue française.
Ma page personnelle sur DVP.
Pour compléter la réponse de ram-0000 :
La question des tableaux est relativement simple bien qu'étant une exception dans le traitement des objets en C :
1- Dans tous les cas excepté lorsqu'il est associé aux opérateurs unaires & (adresse de) et sizeof, l'identificateur d'un tableau est une valeur représentant l'adresse du premier élément du tableau. Son type est donc "adresse d'un élément du tableau" et elle peut être affectée à un objet pointeur du type adéquat : "pointeur = tableau".
Comme l'adresse d'un objet n'est pas modifiable et a été fixée à sa création, cette valeur (représentée par l'identificateur du tableau) n'est pas modifiable et on n'a jamais le droit d'écrire "tableau = .......".
2- La question
ne se pose pas : il est interdit d'écrire ce code (si t1 est un tableau). Il faut que t1 soit un pointeur.lorsque l'on programme en C l'affectation d'un tableau t1=T2 se fait par une recopie de pointeur ou une recopie case a case?
3-
En C, les paramètres des fonctions sont sans exception aucune passés par valeur.De plus je voudrais savoir comment son réalisésles passages de paramètres par valeur et par adresse d'un tableau?
Si dans le cas de l'identificateur d'un tableau, c'est l'adresse de son premier élément qui est passé en argument, c'est en vertu de ce qui est exposé en (1)
Les "cases", c'est toi qui les a fixées.
Tu passe en paramètres un tableaux de type SHORT tu peut très bien faire le tour du tableau avec un pointeur de type CHAR, sauf que tu parcourra ton tableau deux fois moins vite.
Chaque "cases" équivaut à la taille du type du tableau (ou plutôt du TYPE qu'il est sensé contenir).
On connait l'adresse du premier élément : tab
On connait la taille en byte d'un élément du tableau puisque on connait le type T des éléments du tableau
On sait que les éléments d'un tableau sont consécutifs en mémoire
Il est donc facile de calculer l'adresse du nieme élément du tableau.
D'un point de vue du C, si T est le type des éléments du tableau tab, le type de tab (hors & et sizeof) est T*. C'est une adresse et l'arithmétique associée à tab est l'arithmétique des adresses. Par conséquent, l'adresse de l'élément d'indice n est tab+n. L'élément lui-même est donc *(tab+n). En fait, lorsque tu écris tab[n], le compilateur l'interprète comme *(tab+n) et la notation [] est là pour nous donner un simplification syntaxique (très avantageuse surtout dans les tableaux à plusieurs dimensions).
merci pour vos reponses. Une autre question me trotte dans la tête. D'un
Que veux-tu dire ici par "pile" ?
Ceci est plutôt le genre de chose qui se fait avec les registres. Ici, au minimum, deux registres sont nécessaires:
Code pseudocode : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 R1 := y; R2 := x; R1 := *R1; R1 *= R2; R2 := R1; R1 := y; *R1 := R2;
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
J'ai une derniere question a laquelle je souhaiterais bien pourvoir repondre...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 int y; void h(int d, int *r) { int y;
merci
La variable locale y dans g() masque la variable globale y dans la fonction, celle-ci n'y accède donc pas en tant que telle.
Ici, seules les fonctions f() et main() accèdent directement à y. Par contre, g() reçoit un pointeur vers y, et la modifie donc indirectement.
Voici un code avec les variables renommées:
Au moins, je peux te décrire le déroulement (= signifie ici équivalence, j'utilise := pour l'affectation):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 int glob_y; void g(int const gd, int * const gr) { int gy; gy = *gr; *gr = gd+1; } void f(int const fd, int * const fr) { int fx; fx = fd+1; glob_y = 1; *fr = fx; g(*fr, fr); } int main() { int mx; mx = 3; f(mx, &glob_y); return 0; }
- appel de main() : glob_y non initialisé (ou initialisé à zéro, je ne sais plus)
- variable locale mx := 3
- appel de f(fd := mx = 3, fr := &glob_y)
- variable locale fx := fd + 1 = 4
- glob_y := 1
- *fr = glob_y := fx = 4
- appel de g(gd := *fr = glob_y = 4, gr := fr = &glob_y)
- variable locale gy := *gr = glob_y = 4
- *gr = glob_y := gd + 1 = 5
- retour de g à f
- retour de f à main
- Si je ne me suis pas trompé, glob_y vaut 5 ici.
- retour de 0
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
merci mais donc par rapport a un programme qui ne possede pas de variables globales ex :
quelle nouvelle information figure dans la pile quand les fonctions (du programme contenant la variable globale) f et g s'exécutent?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void f(int x, int *y) { if (x == 0) (*y) = 1; else { f(x-1,y); (*y) = (*y) * x; } } int main(void) { int x; x = 4; f(x,&x); return 0; }
merci d'avance
Là, c'est plus difficile, car il y a récursivité (et non-terminale, en plus).
Ce qui est sûr, c'est que le pointeur ne change pas, donc y pointe toujours sur la même variable: mx.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 void f(int const x, int * const y) { if (x == 0) { *y = 1; } else { f(x-1, y); (*y) *= x; } } int main(void) { int mx; mx = 4; f(mx, &mx); return 0; }
f() est rappelée avec à chaque fois une valeur inférieure (qui est une copie à chaque fois, donc ne modifie rien), jusqu'à ce qu'une fonction soit appelée avec x==0. Après, on initialise la variable pointée (ici, mx) à 1, puis au fur et à mesure qu'on remonte on multiplie par la valeur de x dans la fonction. Ceci est juste un exemple plus compliqué que la normale de calcul récursif d'une factorielle, un cas d'école sur la récursivité (mais inutile en soi, car un calcul itératif de la factorielle est plus simple et plus efficace).
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
En gros, sur la pile, si on mettait un breakpoint juste avant le *y = 1, on aurait ça:
- main()
- f(4, &mx)
- f(3, &mx)
- f(2, &mx)
- f(1, &mx)
- f(0, &mx)
Ce qui donne, avec convention d'appel C (en noir, les variables locales et registres sauvegardés; en rouge, les appels de fonction) :
- adresse de retour hors du programme
- registres sauvegardés par main()
- mx = 4
- adresse de mx
- 4
- adresse de retour dans main
- registres sauvegardés par f
- adresse de mx
- 3
- adresse de retour dans f
- registres sauvegardés par f
- adresse de mx
- 2
- adresse de retour dans f
- registres sauvegardés par f
- adresse de mx
- 1
- adresse de retour dans f
- registres sauvegardés par f
- adresse de mx
- 0
- adresse de retour dans f
- registres sauvegardés par f
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
donc en fait dans le programme contenant la variable globale lorsque f s'exécute il y a seulement l'adresse de la variable locale qui est stockée en plus que lorsque la fonction f s'execute dans l'autre programme?
C'est pareil pour g?
Redis-ça lentement, car je n'arrive pas à comprendre ce que tu penses avoir compris.
Un dessin peut aider.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Partager