交换而不用担心数据类型

时间:2018-02-12 12:53:45

标签: c pointers

该实现是否有效且安全地交换两个数组或变量而不必担心其数据类型?或者我应该使用函数指针?。

这种类型的代码专注于使用void指针的良好实现进行交换,而不必担心数据类型。

#include <stdio.h>
#include <string.h>

void swap(void *, void *, int);

int main(void) {

  char a[] = "home";
  char b[] = "door";

  printf("%s %s\n", a, b);
  swap(&a, &b, sizeof(a));
  printf("%s %s \n", a, b);

  return 0;
}

void swap( void *a, void *b, int siz){
  char buff[siz]; // I voluntarily omitted dynamic allocation.
  memcpy(buff,a,siz);
  memcpy(a,b,siz);
  memcpy(b,buff,siz);
}

5 个答案:

答案 0 :(得分:4)

在C中,这种方法通常是可以的(并且它被标准函数使用,例如qsort())。指示您无法使用此功能的禁忌症是指有任何指向您的对象或其成员的指针。另外,请注意多线程代码。

请注意,在C ++中,我们有std::swap(),它将尊重用户定义的复制/移动构造函数;通过简单地复制其内存来复制C ++对象(通常)不是有效的。

答案 1 :(得分:1)

swap()函数与它使用的memcpy()一样好/坏。

  • 如果数据结构只是一些数据结构(intfloat等),它就像魅力一样。

  • 如果你将两个指针传递给不同的结构,那么一切都会破裂。违规代码:

    Foo* myFoo = ...;
    Bar* myBar = ...;
    swap(myFoo, myBar, sizeof(*myFoo));
    

    请注意,您的编译器不会对此抱怨,因为两种指针类型都可以隐式转换为void*期望的swap()。但汇编的结果将是胡说八道。

  • 如果您复制的结构包含指向自身的指针,则该指针将指向swap()之后的另一个对象。以下struct将成为其中的罪犯:

    typedef struct {
        char* data;
        size_t length, allocatedLength;
        char shortStringBuffer[32];
    } myString;
    

    这背后的想法是,短字符串将存储在shortStringBuffer中,data将指向shortStringBuffer。超过31个字符的字符串将存储在动态分配的内存中,并且可以通过data成员再次访问。作为练习,读者可以弄清楚,当您尝试使用memcpy()复制此内容时会发生什么。

你必须明白的是,memcpy()实际上只复制字节,而某些数据并不是存储它的位置。因此,memcpy()的每次使用都必须附有证据证明它在这种特殊情况下做了正确的事情。好吧,应该。我出于某种原因从未在评论中看到过这样的证据......

答案 2 :(得分:0)

您只需交换其地址而无需进一步操作即可交换两个变量/数组。我试过这个并且它有效:

#include <stdio.h>

int main(void) {
    char *a = "home";
    char *b = "root";
    char *c = a, *d = b;
    printf("%s %s\n", a, b);
    a = d;
    b = c;
    printf("%s %s \n", a, b);
    return 0;
}

输出:

home root
root home 

https://ideone.com/MMCOpf

答案 3 :(得分:0)

使用通用指针进行交换是安全的,但是你必须确保正确的尺寸,并且不要溢出任何数组或对象:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int swap(void *a, void *b,
    size_t a_size, size_t b_size);

int main(void) {

    char a[] = "home";
    char b[] = "door";

    printf("%s %s\n", a, b);

    int ret = swap(a, b, sizeof(a), sizeof(b));
    if(ret) {
        printf("%s %s \n", a, b);
    }
    return ret;
}

int swap(void *a, void *b,
    size_t a_size, size_t b_size)
{
    if (b_size != a_size ) {
        return 0;
    }
    void *tmp = malloc(a_size);
    if(!tmp) {
        return 0;
    }
    memcpy(tmp, a, a_size);
    memcpy(a, b, b_size);
    memcpy(b, tmp, a_size);
    free(tmp); // tmp no longer needed.
    return 1;
}

答案 4 :(得分:-1)

我用C代码解决了这个问题。

当两个较大的uint8_t变量加在一起时,必须使用 uint16_t 来保留进位位。

int main(){
    uint8_t tmp[9] = {0x0};
    for (int i=9-1; i>=0 ; i--) *(tmp+i) = 0xff-i;
    uint16_t tmp2[9];
    for (int i=0; i<9; i++) tmp2[i] = tmp[i];
    byte_swap_uint8_data(tmp2, 9);
}

void byte_swap_uint8_data(uint16_t* data, int w) {
    if (w < 2) return;
    for (int i=0; i<w/2; i++) {
        data[i] += data[w-1-i];
        data[w-1-i] = data[i] - data[w-1-i];
        data[i] = data[i] - data[w-1-i];
     }
}