variable valores valor usar una tres tercera los intercambio intercambiar enteros cómo con cambio cambiar aux apuntadores c

valores - intercambio de tres variables



¿Hay una forma integrada de intercambiar dos variables en C (10)

En C esto se hace a menudo usando una macro,
Hay ejemplos muy simplistas, por ejemplo:
#define SWAP(type,a,b) {type _tmp=a;a=b;b=_tmp;}
... pero no recomendaría usarlos porque tienen algunas fallas no obvias.

Esta es una macro escrita para evitar errores accidentales.

#define SWAP(type, a_, b_) / do { / struct { type *a; type *b; type t; } SWAP; / SWAP.a = &(a_); / SWAP.b = &(b_); / SWAP.t = *SWAP.a; / *SWAP.a = *SWAP.b; / *SWAP.b = SWAP.t; / } while (0)

  • Cada argumento es instanciado solo una vez,
    por lo que SWAP(a[i++], b[j++]) no produce efectos secundarios problemáticos.
  • El nombre de la variable temporal también es SWAP , a fin de no causar errores si ocurre que un nombre diferente choca con el nombre codificado.
  • No llama a memcpy (que de hecho terminó haciendo llamadas a funciones reales en mis pruebas, aunque un compilador puede optimizarlas).
  • Su tipo de verificación
    (comparando como punteros, el compilador avisa si no coinciden).

Sé cómo intercambiar 2 variables en c ++, es decir, usas std::swap(a,b) .

pregunta:

¿La biblioteca estándar de C tiene una función similar a C ++ std::swap() o tengo que definirla yo mismo?


En caso de valores numéricos (al menos):

Sé que esta no es una respuesta real o completa, pero hasta ahora todos han estado utilizando variables temporales, por lo que pensé que el blog de Chris Taylors podría ser relevante para mencionar, sin duda elimina la necesidad de tipografía (), etc.

a = a ^ b; b = a ^ b; a = a ^ b;

o

a = a + b; b = a - b; a = a - b;

En teoría supongo que estas técnicas podrían aplicarse también a cuerdas y otros tipos ...

Aún quedan solo tres operaciones.


Esto funciona rápidamente en Clang y gcc (pero no en icc, que no reconoce esta función de intercambio, sin embargo, se compilará en cualquier compilador C99 estándar), siempre que las optimizaciones realmente reconozcan el intercambio (lo hacen en niveles suficientemente altos de optimización) .

#include <string.h> #define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b))) static inline void swap_internal(void *a, void *b, size_t size) { char tmp[size]; memcpy(tmp, a, size); memmove(a, b, size); memcpy(b, tmp, size); }

Ahora por explicar cómo funciona. Primero, la línea SWAP() es relativamente extraña, pero en realidad es relativamente simple. &(a) es a argumento pasado como un puntero. De manera similar, &(b) es un argumento b pasado como un puntero.

El código más interesante es sizeof *(1 ? &(a) : &(b)) . Esto es en realidad una pieza de error relativamente inteligente. Si el informe de errores no fuera necesario, podría ser simplemente sizeof(a) . El operador ternario requiere que sus operaciones tengan tipos compatibles. En este caso, verifico dos argumentos diferentes para su compatibilidad de tipo al convertirlos en puntero (de lo contrario, int y double serían compatibles). Como int * y double * no son compatibles, la compilación fallaría ... siempre que sea el compilador C estándar. Lamentablemente, muchos compiladores asumen el tipo void * en este caso, por lo que falla, pero al menos con una advertencia (que está habilitada de forma predeterminada). Para garantizar el tamaño correcto del resultado, el valor se elimina de referencia y se aplica a sizeof , por lo que no hay efectos secundarios.

~/c/swap $ gcc swap.c swap.c: In function ‘main’: swap.c:5:64: warning: pointer type mismatch in conditional expression [enabled by default] #define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b))) ^ swap.c:16:5: note: in expansion of macro ‘SWAP’ SWAP(cat, dog); ^ ~/c/swap $ clang swap.c swap.c:16:5: warning: pointer type mismatch (''int *'' and ''double *'') [-Wpointer-type-mismatch] SWAP(cat, dog); ^~~~~~~~~~~~~~ swap.c:5:57: note: expanded from macro ''SWAP'' #define SWAP(a, b) swap_internal(&(a), &(b), sizeof *(1 ? &(a) : &(b))) ^ ~~~~ ~~~~ 1 warning generated. ~/c/swap $ icc swap.c swap.c(16): warning #42: operand types are incompatible ("int *" and "double *") SWAP(cat, dog); ^

Esta macro evalúa todo exactamente una vez ( sizeof es especial, ya que no evalúa sus argumentos). Esto proporciona seguridad contra argumentos como array[something()] . La única limitación que se me ocurre es que no funciona en register variables de register porque depende de los punteros, pero aparte de eso, es genérico, incluso puede usarlo para matrices de longitud variable. Incluso puede manejar el intercambio de variables idénticas, no es que quieras hacerlo.


No hay equivalente en C, de hecho no puede haberlo, ya que C no tiene funciones de plantilla. Tendrá que escribir funciones separadas para todos los tipos que desee intercambiar.


Otra macro que no se menciona aquí: no es necesario que especifique el tipo si, en su lugar, asigna la variable temporal. Además, el operador de coma es útil aquí para evitar el truco do-while (0). Pero por lo general no me importa y simplemente escribo los tres comandos. Por otro lado, una macro temporal es útil si ayb son más complejos.

#define SWAP(a,b,t) ((t)=(a), (a)=(b), (b)=(t)) void mix_the_array (....) { int tmp; ..... SWAP(pointer->array[counter+17], pointer->array[counter+20], tmp); ..... } #undef SWAP


Puedes hacer algo similar con una macro si no te importa usar una extensión gcc para el lenguaje C, typeof :

#include <stdio.h> #define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0) int main(void) { int a = 4, b = 5; float x = 4.0f, y = 5.0f; char *p1 = "Hello"; char *p2 = "World"; SWAP(a, b); // swap two ints, a and b SWAP(x, y); // swap two floats, x and y SWAP(p1, p2); // swap two char * pointers, p1 and p2 printf("a = %d, b = %d/n", a, b); printf("x = %g, y = %g/n", x, y); printf("p1 = %s, p2 = %s/n", p1, p2); return 0; }


Puedes hacer algo similar con una macro sin usar una variable temporal.

#include <stdio.h> #define SWAP(a, b) {a=a+b;b=a-b;a=a-b;} //swap macro int main(void) { int a = 4, b = 5; float x = 4.0f, y = 5.0f; char *p1 = "Hello"; char *p2 = "World"; a = 4, b = 5,x = 4.0f, y = 5.0f,*p1 = "Hello",*p2="world"; SWAP(a, b); // swap two ints, a and b SWAP(x, y); // swap two floats, x and y SWAP1p1, p2); // swap two char * pointers, p1 and p2 printf("a = %d, b = %d/n", a, b); printf("x = %g, y = %g/n", x, y); printf("p1 = %s, p2 = %s/n", p1, p2); return 0; }


Revise la documentación de su compilador. El compilador puede tener una función swapb para intercambiar bytes y proporcionar otras funciones similares.

En el peor de los casos, desperdicie un día y escriba algunas funciones de intercambio genéricas. No consumirá una cantidad significativa de la programación de su proyecto.


Sí, necesitas definirlo tú mismo.

  1. C no tiene plantillas.
  2. Si tal función existe, se vería como void swap(void* a, void* b, size_t length) , pero a diferencia de std::swap , no es de tipo seguro.
  3. Y no hay indicios de que dicha función pueda estar en línea, lo cual es importante si el intercambio es frecuente (en C99 hay una palabra clave en inline ).
  4. También podríamos definir una macro como

    #define SWAP(a,b,type) {type ttttttttt=a;a=b;b=ttttttttt;}

    pero sombrea la variable ttttttttt , y necesita repetir el tipo de a . (En gcc hay typeof(a) para resolver esto, pero aún no puedes SWAP(ttttttttt,anything_else); )

  5. Y escribir un intercambio en su lugar tampoco es tan difícil, ¡son solo 3 líneas de código simples!


en esencia, la función de intercambio es intercambiar dos bloques de memoria. Con dos direcciones y el tamaño de bloque en bytes, podemos intercambiar punteros, enteros, dobles, matrices, estructuras, ...

un puntero tiene tres partes, por ejemplo, podemos dividir short* p en tres pedazos

  1. dirección: void * p
  2. tamaño: leyendo dos bytes en void*p , obtenemos un entero corto.
  3. uso: por ejemplo, imprimir un entero corto con %hu

Usando las dos primeras partes, podremos construir una función de intercambio genérica:

#include<stdint.h> #ifdef _WIN32 #define alloca _alloca #else #include <alloca.h> #endif void gswap(void * const a, void * const b, int const sz) { // for most case, 8 bytes will be sufficient. int64_t tmp; // equivalent to char tmp[8]; void * p; bool needfree = false; if (sz > sizeof(int64_t)) { // if sz exceed 8 bytes, we allocate memory in stack with little cost. p = alloca(sz); if (p == NULL) { // if sz is too large to fit in stack, we fall back to use heap. p = malloc(sz); //assert(p != NULL, "not enough memory"); needfree = true; } } else { p = &tmp; } memcpy(p, b, sz); memcpy(b, a, sz); memcpy(a, p, sz); if (needfree) { free(p); } }

p.ej:

{// swap int int a = 3; int b = 4; printf("%d,%d/n", a, b);//3,4 gswap(&a, &b, sizeof(int)); printf("%d,%d/n", a, b);//4,3 } {// swap int64 int64_t a = 3; int64_t b = 4; printf("%lld,%lld/n", a, b);//3,4 gswap(&a, &b, sizeof(int64_t)); printf("%lld,%lld/n", a, b);//4,3 } {// swap arrays int64_t a[2] = { 3,4 }; int64_t b[2] = { 5,6 }; printf("%lld,%lld,%lld,%lld/n", a[0], a[1], b[0], b[1]);//3,4,5,6 gswap(&a, &b, sizeof(a)); printf("%lld,%lld,%lld,%lld/n", a[0], a[1], b[0], b[1]);//5,6,3,4 } {// swap arrays double a[2] = { 3.,4. }; double b[2] = { 5.,6. }; printf("%lf,%lf,%lf,%lf/n", a[0], a[1], b[0], b[1]);//3.000000, 4.000000, 5.000000, 6.000000 arrswap(&a, &b, sizeof(a)); printf("%lf,%lf,%lf,%lf/n", a[0], a[1], b[0], b[1]);//5.000000, 6.000000, 3.000000, 4.000000 }