Intercambio de punteros en C (char, int)

8 minutos de lectura

avatar de usuario
Manolete

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

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

Sin embargo, si quiero intercambiar dos char punteros que necesito para 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 compilador se queja de la expresión *a = *b ya que no puede cambiar los valores. Si quiero cambiar dos strings (es decir char* s1= "Hello"; char* s2="Bye"; ) ¿cómo se haría?

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

  • El primer ejemplo no intercambia dos punteros int. Creo que esa es la fuente de tu confusión.

    – R. Martinho Fernández

    6 de diciembre de 2011 a las 16:39


  • @R.MartinhoFernandes Creo que tienes razón

    – Manolete

    6 de diciembre de 2011 a las 16:48

avatar de usuario
R. Martinho Fernández

Lo primero que debe comprender es que cuando pasa algo a una función, ese algo se copia en 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. Luego, la función 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 solucionamos 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? Uso de punteros.

Si pasamos punteros a nuestras variables en la función, la función puede intercambiar los valores en nuestro 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 a lo que apuntan. Y los punteros apuntan a nuestras variables. x y y. La función está cambiando directamente los valores almacenados en nuestro variables a través de los punteros que le damos. Y eso es exactamente lo que necesitábamos.

Ahora, ¿qué sucede si tenemos dos variables de puntero y queremos intercambiar el punteros mismos (a diferencia de los valores a los que apuntan)? Si pasamos punteros, los punteros simplemente se copiarán (no los valores a los que apuntan) en 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! Le estamos dando a la función un medio para referirse a las variables. x y 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 (observa 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, para que pueda cambiarlas!

A estas alturas, debería ser fácil entender cómo intercambiar dos cadenas en forma de char* variables La función de intercambio necesita recibir punteros para 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);

  • podría ser bueno dejar que la respuesta se centre en una sola cosa, pero para ser correcto en este ejemplo, necesitamos swapStrings(const char** a, const char** b)

    – u0b34a0f6ae

    7 de diciembre de 2011 a las 10:15

  • @kaizer.se ¡gracias por notarlo! eliminé el consts de la respuesta para evitar confusiones.

    – R. Martinho Fernández

    7 de diciembre de 2011 a las 10:26


avatar de usuario
Rifat

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 se intercambiará el valor. Entonces, para un char* solo su primera char intercambiará

Ahora, si entiende char* (cadena) claramente, entonces debe saber que solo necesita intercambiar el puntero. Será más fácil de entender si lo piensas como un array en lugar de cuerda.

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

Entonces, aquí está pasando doble puntero porque el inicio de un array en sí mismo es un puntero.

  • @R.MartinhoFernandes Gracias, lo arreglé 🙂

    – Rifat

    6 de diciembre de 2011 a las 17:47

avatar de usuario
dan fego

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

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

Editar: En su ejemplo anterior, está tratando de intercambiar dos punteros int incorrectamente, como señala R. Martinho Fernandes. Eso intercambiará los dos enteros, si tuvieras:

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

avatar de usuario
geoff zoref

Este ejemplo no intercambia dos punteros int. Intercambia el valor de los enteros que pa y pb están apuntando. Aquí hay un ejemplo de lo que sucede cuando llamas a esto:

void Swap1 (int *pa, int *pb){
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}
int main()
{
    int a = 42;
    int b = 17;


    int *pa = &a;
    int *pb = &b;

    printf("--------Swap1---------\n");
    printf("a = %d\n b = %d\n", a, b);
    swap1(pa, pb);
    printf("a = %d\n = %d\n", a, a);
    printf("pb address =  %p\n", pa);
    printf("pa address =  %p\n", pb);
}

La salida aquí es:

a = 42
b = 17
pa address =  0x7fffdf933228
pb address =  0x7fffdf93322c
--------Swap---------
pa = 17
pb = 42
a = 17
b = 42
pa address =  0x7fffdf933228
pb address =  0x7fffdf93322c

Tenga en cuenta que los valores se intercambiaron, ¡pero las direcciones del puntero no se intercambiaron!

Para intercambiar direcciones necesitamos hacer esto:

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

y en la llamada principal la función como swap2(&pa, &pb);

Ahora se intercambian las direcciones, así como los valores de los punteros. a y b tienen los mismos valores con los que se inicializaron Los enteros a y b no se intercambiaron porque swap2 ¡intercambia las direcciones a las que apuntan los punteros!:

a = 42
b = 17
pa address =  0x7fffddaa9c98
pb address =  0x7fffddaa9c9c
--------Swap---------
pa = 17
pb = 42
a = 42
b = 17
pa address =  0x7fffddaa9c9c
pb address =  0x7fffddaa9c98

Dado que las cadenas en C son punteros de caracteres y desea intercambiar cadenas, en realidad está intercambiando un puntero de caracteres. Como en los ejemplos con un int, necesita un puntero doble para intercambiar direcciones.

Los valores de los enteros se pueden intercambiar incluso si la dirección no lo es, pero las cadenas son, por definición, un puntero de carácter. Podrías intercambiar un carácter con punteros simples como parámetro, pero un puntero de carácter debe ser un puntero doble para intercambiar las cadenas.

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

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

Concedido, en el caso de char*solo intercambiaría los punteros, no los datos a los que apuntan, pero en la mayoría de los casos, está bien, ¿no?

  • Si tiene el lujo de trabajar en C++, tiene estándar::intercambio que hace esto por ti!

    – Qqwy

    17 de febrero de 2018 a las 20:21

  • Si tiene el lujo de trabajar en C++, tiene estándar::intercambiar que hace esto por ti!

    – Qqwy

    17 de febrero de 2018 a las 20:21

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad