Échange de pointeurs en C (char, int)

J’ai eu du mal à comprendre les différents comportements lorsque j’échange des pointeurs en C. Si je veux échanger deux pointeurs int , je peux le faire.

 void intSwap (int *pa, int *pb){ int temp = *pa; *pa = *pb; *pb = temp; } 

Cependant, si je veux échanger deux pointeurs de caractère, je dois faire quelque chose comme:

 void charSwap(char** a, char** b){ char *temp = *a; *a = *b; *b = temp; } 

parce que si je le fais

 void charSwap(char* a, char* b){ char temp = *a; *a = *b; *b = temp; } 

le compilateur se plaint de l’expression * a = * b car il ne peut pas changer les valeurs. Si je veux échanger deux ssortingngs (c.-à-d char* s1= "Hello"; char* s2="Bye"; ) comment le ferait-on?

Pourriez-vous s’il vous plaît me donner un peu d’aide? J’aimerais vraiment savoir comment cela fonctionne afin de ne pas avoir à subir des essais et des erreurs tout le temps tant que je n’aurai pas obtenu la bonne réponse. J’espère que c’est utile pour beaucoup d’autres personnes.

La première chose que vous devez comprendre est que lorsque vous passez quelque chose à une fonction, quelque chose est copié dans les arguments de la fonction.

Supposons que vous ayez les éléments suivants:

 void swap1(int a, int b) { int temp = a; a = b; b = temp; assert(a == 17); assert(b == 42); // they're swapped! } int x = 42; int y = 17; swap1(x, y); assert(x == 42); assert(y == 17); // no, they're not swapped! 

Les variables d’origine ne seront pas échangées, car leurs valeurs sont copiées dans les arguments de la fonction. La fonction échange ensuite les valeurs de ces arguments, puis retourne. Les valeurs d’origine ne sont pas modifiées car la fonction échange uniquement ses propres copies privées.

Maintenant, comment travaillons-nous autour de cela? La fonction a besoin d’un moyen de faire référence aux variables d’origine, pas de copies de leurs valeurs. Comment pouvons-nous faire référence à d’autres variables en C? Utiliser des pointeurs.

Si nous transmettons des pointeurs vers nos variables dans la fonction, celle-ci peut échanger les valeurs de nos variables au lieu de ses propres copies d’argument.

 void swap2(int* a, int* b) { int temp = *a; *a = *b; *b = temp; assert(*a == 17); assert(*b == 42); // they're swapped! } int x = 42; int y = 17; swap2(&x, &y); // give the function pointers to our variables assert(x == 17); assert(y == 42); // yes, they're swapped! 

Remarquez comment, à l’intérieur de la fonction, nous n’affectons pas les pointeurs, mais assignons ce à quoi ils pointent. Et les pointeurs pointent vers nos variables x et y . La fonction change directement les valeurs stockées dans nos variables grâce aux pointeurs que nous lui donnons. Et c’est exactement ce dont nous avions besoin.

Maintenant que se passe-t-il si nous avons deux variables de pointeur et que nous voulons échanger les pointeurs eux-mêmes (par opposition aux valeurs auxquelles ils pointent)? Si nous passons des pointeurs, ceux-ci seront simplement copiés (et non les valeurs qu’ils pointent) vers les arguments.

 void swap3(int* a, int* b) { int* temp = a; a = b; b = temp; assert(*a == 17); assert(*b == 42); // they're swapped! } void swap4(int* a, int* b) { int temp = *a; *a = *b; *b = temp; assert(*a == 17); assert(*b == 42); // they're swapped! } int x = 42; int y = 17; int* xp = &x; int* yp = &y; swap3(xp, yp); assert(xp == &x); assert(yp == &y); assert(x == 42); assert(y == 17); // Didn't swap anything! swap4(xp, yp); assert(xp == &x); assert(yp == &y); assert(x == 17); assert(y == 42); // Swapped the stored values instead! 

La fonction swap3 échange uniquement ses propres copies privées de nos pointeurs qu’elle récupère dans ses arguments. C’est le même problème que nous avons eu avec swap1 . Et swap4 modifie les valeurs swap4 nos variables, pas les pointeurs! Nous donnons à la fonction un moyen de faire référence aux variables x et y mais nous voulons qu’elles se réfèrent à xp et yp .

Comment fait-on cela? Nous leur passons leurs adresses!

 void swap5(int** a, int** b) { int* temp = *a; *a = *b; *b = temp; assert(**a == 17); assert(**b == 42); // they're swapped! } int x = 42; int y = 17; int* xp = &x; int* yp = &y; swap5(&xp, &yp); assert(xp == &y); assert(yp == &x); assert(x == 42); assert(y == 17); // swapped only the pointers variables 

De cette façon, il permute nos variables de pointeur (notez comment xp pointe maintenant sur y ) mais pas les valeurs auxquelles elles pointent. Nous lui avons donné un moyen de faire référence à nos variables de pointeur, afin qu’il puisse les changer!

Il devrait maintenant être facile de comprendre comment échanger deux chaînes sous la forme de variables char* . La fonction swap doit recevoir des pointeurs sur char* .

 void swapSsortingngs(char** a, char** b){ char *temp = *a; *a = *b; *b = temp; assert(strcmp(*a, "world") == 0); assert(strcmp(*b, "Hello") == 0); } char* x = "Hello"; char* y = "world"; swapSsortingngs(&x, &y); assert(strcmp(x, "world") == 0); assert(strcmp(y, "Hello") == 0); 
 void intSwap (int *pa, int *pb){ int temp = *pa; *pa = *pb; *pb = temp; } 

Vous devez savoir ce qui suit –

 int a = 5; // an integer, contains value int *p; // an integer pointer, contains address p = &a; // &a means address of a a = *p; // *p means value stored in that address, here 5 

 void charSwap(char* a, char* b){ char temp = *a; *a = *b; *b = temp; } 

Alors, quand vous échangez comme ça. Seule la valeur sera échangée. Ainsi, pour un personnage char* seul leur premier caractère sera échangé.

Maintenant, si vous comprenez bien char * (chaîne), sachez que vous devez simplement échanger le pointeur. Ce sera plus facile à comprendre si vous le considérez comme un array plutôt que comme une chaîne.

 void ssortingngSwap(char** a, char** b){ char *temp = *a; *a = *b; *b = temp; } 

Donc, vous passez un double pointeur car le démarrage d’un array est un pointeur.

En C, une chaîne, comme vous le savez, est un pointeur de caractère (char *). Si vous voulez échanger deux chaînes, vous devez échanger deux pointeurs de caractère, c’est-à-dire deux adresses seulement. Pour effectuer un échange dans une fonction, vous devez lui donner les adresses des deux choses que vous échangez. Ainsi, dans le cas de l’échange de deux pointeurs, vous avez besoin d’un pointeur vers un pointeur. Un peu comme pour échanger un int, vous avez juste besoin d’un pointeur sur un int.

La raison pour laquelle votre dernier extrait de code ne fonctionne pas, c’est parce que vous vous attendez à ce qu’il permute deux pointeurs de caractères – il est en fait écrit pour échanger deux caractères!

Edit: Dans votre exemple ci-dessus, vous essayez de permuter deux pointeurs int incorrectement, comme le souligne R. Martinho Fernandes. Cela échangera les deux ints, si vous aviez:

 int a, b; intSwap(&a, &b); 

Vous devez comprendre la différence entre passer-par-référence et passer-par-valeur.

Fondamentalement, C ne supporte que la valeur de passage. Vous ne pouvez donc pas référencer directement une variable lorsque vous la passez à une fonction. Si vous souhaitez modifier la variable en dehors d’une fonction, comme le swap le fait, vous devez utiliser la méthode de référence par référence. Pour implémenter le passage par référence en C, vous devez utiliser le pointeur, qui peut déréférencer la valeur.

La fonction:

 void intSwap(int* a, int* b) 

Il passe deux pointeurs à intSwap, et dans la fonction, vous permutez les valeurs pointées par a / b, mais pas le pointeur lui-même. C’est pourquoi R. Martinho et Dan Fego ont déclaré qu’il échangeait deux entiers et non des pointeurs.

Pour les caractères, je pense que vous voulez dire ssortingng, sont plus compliqués. La chaîne en C est implémentée en tant que tableau de caractères, qui est référencé par un caractère *, un pointeur, en tant que valeur de chaîne. Et si vous voulez passer un caractère * par référence, vous devez utiliser le ponter de caractère *, afin que vous obteniez caractère **.

Peut-être que le code ci-dessous plus clairement:

 typedef char* str; void strSwap(str* a, str* b); 

La permutation syntaxique (int & a, int & b) est en C ++, ce qui signifie directement un passage par référence. Peut-être qu’un compilateur C implémente aussi.

J’espère que je le fais plus clairement, pas confortable.

Si vous avez le luxe de travailler en C ++, utilisez ceci:

 template void swapPrimitives(T& a, T& b) { T c = a; a = b; b = c; } 

Certes, dans le cas de char* , il ne ferait que permuter les pointeurs eux-mêmes, pas les données qu’ils pointent, mais dans la plupart des cas, c’est correct, non?