Intercambio de punteros en C (char, int)

He estado luchando por comprender el comportamiento diferente al intercambiar punteros en C. Si quiero intercambiar dos punteros int , entonces puedo hacer

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

Sin embargo, si quiero cambiar dos punteros de char , necesito hacer algo como

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

porque si lo hago

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

el comstackdor se queja de la expresión * a = * b porque no puede cambiar los valores. Si quiero cambiar dos strings (es decir, char* s1= "Hello"; char* s2="Bye"; ) ¿cómo lo haría?

¿Podría darme un poco de ayuda? Me gustaría aprender realmente cómo funciona, por lo que no necesitaré experimentar con prueba y error todo el tiempo hasta que obtenga la respuesta correcta. Espero que sea útil para muchas otras personas.

Lo primero que debe entender es que cuando transfiere algo a una función, ese algo se copia a los argumentos de la función.

Supongamos que tiene lo siguiente:

 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! 

Las variables originales no se intercambiarán, porque sus valores se copian en los argumentos de la función. La función luego procede a intercambiar los valores de esos argumentos, y luego regresa. Los valores originales no se modifican, porque la función solo intercambia sus propias copias privadas.

¿Ahora cómo trabajamos alrededor de esto? La función necesita una forma de referirse a las variables originales, no copias de sus valores. ¿Cómo podemos referirnos a otras variables en C? Usando punteros.

Si pasamos punteros a nuestras variables en la función, la función puede intercambiar los valores en nuestras variables, en lugar de sus propias copias de argumentos.

 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! 

Observe cómo dentro de la función no estamos asignando a los punteros, sino asignándoles lo que señalan. Y los indicadores apuntan a nuestras variables y . La función está cambiando directamente los valores almacenados en nuestras variables a través de los punteros que le damos. Y eso es exactamente lo que necesitábamos.

Ahora, ¿qué ocurre si tenemos dos variables de puntero y queremos intercambiar los punteros por sí mismos (a diferencia de los valores a los que apuntan)? Si aprobamos los punteros, los punteros simplemente se copiarán (no los valores a los que apuntan) a los argumentos.

 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 función swap3 solo intercambia sus propias copias privadas de nuestros punteros que obtiene en sus argumentos. Es el mismo problema que tuvimos con swap1 . ¡Y swap4 está cambiando los valores a los que apuntan nuestras variables, no los punteros! Estamos dando a la función un medio para referirse a las variables y pero queremos que se refieran a xp y yp .

¿Como hacemos eso? ¡Le pasamos sus direcciones!

 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 esta manera, intercambia nuestras variables de puntero (observe cómo xp ahora apunta a y ) pero no los valores a los que apuntan. Le dimos una forma de referirse a nuestras variables de puntero, ¡así que puede cambiarlas!

Por ahora, debería ser fácil entender cómo intercambiar dos cadenas en forma de variables char* . La función de intercambio necesita recibir punteros a char* .

 void swapStrings(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"; swapStrings(&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; } 

Necesitas saber lo siguiente:

 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; } 

Entonces, cuando cambias así Solo el valor será intercambiado. Entonces, para un char* solo cambiará su primer char .

Ahora, si comprende char * (cadena) claramente, entonces debe saber que solo necesita cambiar el puntero. Será más fácil de entender si lo piensas como una array lugar de una cadena.

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

Por lo tanto, aquí está pasando el puntero doble porque el inicio de una array sí es un puntero.

En C, una cadena, como saben, es un puntero de carácter (char *). Si quiere cambiar dos cadenas, está intercambiando dos punteros, es decir, dos direcciones. Para realizar un intercambio en una función, debe darle las direcciones de las dos cosas que está intercambiando. Entonces, en el caso de cambiar dos punteros, necesita un puntero a un puntero. Al igual que cambiar un int, solo necesitas un puntero a un int.

La razón por la que el último fragmento de código no funciona es porque esperas que intercambie dos punteros de caracteres: ¡está escrito para intercambiar dos caracteres!

Editar: en su ejemplo anterior, está tratando de intercambiar dos punteros int de forma incorrecta, como señala R. Martinho Fernandes. Eso cambiará los dos puntos, si tuvieras:

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

Debe comprender lo diferente entre pass-by-reference y pass-by-value.

Básicamente, C solo admite pass-by-value. Por lo tanto, no puede hacer referencia directamente a una variable cuando la pasa a una función. Si desea cambiar la variable de una función, que lo hace el intercambio, debe utilizar pass-by-reference. Para implementar pass-by-reference en C, necesita usar un puntero, que puede desreferenciar el valor.

La función:

 void intSwap(int* a, int* b) 

Pasa el valor de dos punteros a intSwap, y en la función, intercambia los valores a los que apuntaba a / b, pero no el puntero en sí. Es por eso que R. Martinho y Dan Fego dijeron que intercambia dos enteros, no apuntadores.

Para los caracteres, creo que te refieres a la cuerda, son más complicados. String in C se implementa como una matriz de caracteres, a la que hace referencia un carácter *, un puntero, como valor de cadena. Y si quiere pasar un char * por pass-by-reference, necesita usar el ponter de char *, para obtener char **.

Tal vez el código a continuación sea más claro:

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

El intercambio de syntax (int & a, int & b) es C ++, que significa pasar por referencia directamente. Tal vez algún comstackdor C implemente también.

Espero que lo haga más claro, no comfuse.

Si tiene el lujo de trabajar en C ++, use esto:

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

De acuerdo, en el caso de char* , solo intercambiaría los punteros, no los datos que señalan, pero en la mayoría de los casos, eso está bien, ¿no?