【问题标题】:Generic type swap c function泛型交换 c 函数
【发布时间】:2020-03-26 11:40:08
【问题描述】:

我正在尝试编写一个简单的函数来交换任何两个相同类型的变量。

void swap(void* a, void* b, int size);

void swap(void* a, void* b, int size){
    void* temp = malloc(size);
    
    memcpy(temp, a,size);
    
    memcpy(a, b, size);
    
    memcpy(b, temp,size);

    free(temp);
}

int main(int argc, char* argv[])
{
    char name[] = "name";
    char greet[] = "greet";

    swap(name, greet, 30);

    printf("%s\n", name);
    printf("%s\n", greet);
    
    return 0;
}

但是上面的代码打印的是:

`
name

memcpy(b, temp, size) 之后,a (in swap) 指向的值变为`,我不确定为什么?

【问题讨论】:

  • 您不能交换namegreet,因为它们的大小不同。而且你当然不能使用 30 的大小来交换它们,因为这比它们中的任何一个都大!
  • 越界将总是导致未定义的行为。
  • 我在两个相同大小的字符串上测试了您的代码(将该大小作为第三个参数传递给swap),并且成功了。所以你的swap 函数看起来没问题。
  • 在重新排列字符串时,使用指针并重新排列它们通常更容易、更有效,而不是复制整个字符串。
  • 我应该如何更改我的函数以具有相同的定义并适用于所有类型(字符串、char、float、double、int 等)?

标签: c debugging heap-memory


【解决方案1】:

当您调用memcpy(b, temp,size); 时,大小等于30,b 指向的字符串的实际大小为6,您基本上写入了您拥有的内存。

在您的情况下,您的程序实际上会损坏程序堆栈。如果在内存中b 出现在a 之前,那么额外的24 将有效地完全重写a 的内容。

您必须检查 size 是否小于或等于两个字符串的最小大小 + 1(以考虑空字符)。

【讨论】:

  • 我应该如何更改我的函数以具有相同的定义并适用于所有类型(字符串、char、float、double、int 等)?
  • 您的函数已经适用于所有类型。只是知道参数的大小不是函数的工作,而是要使用函数的程序员的工作。这是 C 语言中的一个通用主题,函数完全信任程序员。一个例子是memcpy 函数:它完全依赖于检查你写入的数据量不超过你实际可以写入的量目的地。相反,scanf 返回它解析的参数数量,因为即使在理论上,程序员也无法知道输入是否正确。
【解决方案2】:

存在一些错误,导致未定义的行为。 1. 您正在从一个长度为 5 个字节的数组中复制 30 个字节(“名称”是 4 个字符 + 1 个字节的尾随 0)。 2. 您将 30 个字节复制到数组,该数组长 6 个字节(“问候”是 5 个字符 + 1 个字节的尾随 0)。 这两个错误都可能导致问题,尤其是第二个错误:您试图在数组边界上使用 24 字节的内存 - 无法确定结果。

正如有人在 cmets 中所写,更好的方法是交换指针,也不交换指向的字节。

【讨论】:

  • 我应该如何更改我的函数以具有相同的定义并适用于所有类型(字符串、char、float、double、int 等)?
【解决方案3】:

正如 cmets 所指出的,您不能交换 greetname,因为它们的类型不匹配:char[6],与 char[5](包括终止 NUL),并且它们具有不同的大小。

不过swap可以用在char *对象上,因为char数组可以转换成char *,所以修改很简单。

int main(int argc, char* argv[])

    char name[] = "name";
    char greet[] = "greet";

    char *p1 = name ;
    char *p2 = greet ;

    swap(&p1, &p2, sizeof(p1)) ;

    printf("%s\n", p1);
    printf("%s\n", p2);
}

旁注:无需将malloc 用于临时空间,除非您希望移动非常大的对象。只需 char temp[size] ; 即可完成这项工作 - 而不是 malloc - 并且无需释放(以及较小的性能提升)。

【讨论】:

  • Swap 不仅仅适用于字符串,它适用于 int、float 等,因此我无法将 temp 设置为 char 数组。
  • 我应该如何更改我的函数以具有相同的定义并适用于所有类型(字符串、char、float、double、int 等)?
  • @MohamedMoustafa 我不明白为什么需要对“交换”进行任何更改,只要两个参数具有相同的类型。哪个罐头/类型不工作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 2016-10-31
  • 2020-03-14
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
相关资源
最近更新 更多