gpt4 book ai didi

c - C中的通用数组元素交换

转载 作者:太空宇宙 更新时间:2023-11-04 01:18:29 24 4
gpt4 key购买 nike

我现在意识到,在我的许多代码中,我会有 2 或 3 个这样的函数:

void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}

每个都有自己的指针类型。我想知道的是,是否有一种方法可以交换数组的两个元素,例如,无论数组类型如何?

最佳答案

是的,但是你必须告诉 swap 代码元素有多大:

void generic_swap(void *v1, void *v2, size_t size)
{
char temp[size];
memmove(temp, v1, size);
memmove(v1, v2, size);
memmove(v2, temp, size);
}

这使用 VLA(可变长度数组——C99 的一个特性和 C11 的一个可选特性)作为临时空间。本地数组 temp 的大小在运行时由函数参数 size 控制。如果您不相信您的用户不会请求交换数兆字节的数据,您可以改用动态内存分配,或者仅在大小大于 1 KB 时才使用动态内存分配。

或者:

void generic_swap(void *v1, void *v2, size_t size)
{
size_t chunk = (size > 1024) ? 1024 : size;
size_t offset = 0;
char *s1 = v1;
char *s2 = v2;
char temp[chunk];
while (size > 0)
{
size_t length = (size > chunk) ? chunk : size;
memmove(temp, s1 + offset, length);
memmove(s1 + offset, s2 + offset, length);
memmove(s2 + offset, temp, length);
size -= length;
offset += length;
}
}

或者:

void generic_swap(void *v1, void *v2, size_t size)
{
void *v3 = malloc(size);
if (v3 != 0)
{
memmove(v3, v1, size);
memmove(v1, v2, size);
memmove(v2, v3, size);
free(v3);
}
}

循环版本避免了动态内存分配的开销,并且不会比在三个操作中全部复制慢多少。有多种方法可用于调整循环代码——另请参阅 commentsrici,了解如果您发现交换代码是瓶颈时可以优化它的其他方法。您可以自由选择小于 1024 字节的大小; 64 或 128 也可能是可行的,并且您不一定需要函数中的 VLA。

交换两个整数:

int i = 37;
int j = 99;

swap_generic(&i, &j, sizeof(i));

交换两个 char 数组:

char data[80] = "A tabloid writer's nightmare on steroids";
char info[80] = "Obsequiousness will get you nowhere fast";

swap_generic(data, info, sizeof(data));

等等。请注意,数组的大小必须相同——或者更准确地说,您指定的大小必须是较小的数组的大小,以确保安全。

如果您乐于过危险的生活,您可以使用 memcpy() 而不是 memmove() — 尽管危险在这种情况下是有限的。 (如果你将一个对象与其自身交换,你会调用未定义的行为。否则,它是安全的。)使用 memmove() 总是有效;使用 memcpy() 通常有效。我更喜欢“总是”而不是“大部分”。


三种算法的测试工具

编译,例如:

gcc -O3 -g -std=c11 -Wall -Wextra -Werror -DUSE_GENSWAP_3 swap89.c -o swap89

当使用 Valgrind 运行时,代码得到了一个干净的健康证明。

代码:

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

#if !defined(USE_GENSWAP_1) && !defined(USE_GENSWAP_2) && !defined(USE_GENSWAP_3)
#define USE_GENSWAP_1
#endif

extern void generic_swap(void *v1, void *v2, size_t size);

#ifdef USE_GENSWAP_1
void generic_swap(void *v1, void *v2, size_t size)
{
char temp[size];
memmove(temp, v1, size);
memmove(v1, v2, size);
memmove(v2, temp, size);
}
#endif

#ifdef USE_GENSWAP_2
void generic_swap(void *v1, void *v2, size_t size)
{
size_t chunk = (size > 1024) ? 1024 : size;
size_t offset = 0;
char *s1 = v1;
char *s2 = v2;
char temp[chunk];
while (size > 0)
{
size_t length = (size > chunk) ? chunk : size;
memmove(temp, s1 + offset, length);
memmove(s1 + offset, s2 + offset, length);
memmove(s2 + offset, temp, length);
size -= length;
offset += length;
}
}
#endif

#ifdef USE_GENSWAP_3
void generic_swap(void *v1, void *v2, size_t size)
{
void *v3 = malloc(size);
if (v3 != 0)
{
memmove(v3, v1, size);
memmove(v1, v2, size);
memmove(v2, v3, size);
free(v3);
}
}
#endif

static size_t min_len(size_t x, size_t y) { return (x < y) ? x : y; }

static void dump_long_buffer(const char *tag, size_t length, char buffer[length])
{
int maxpadlen = strlen(tag) + sizeof(" = ") - 1;
printf("%s = ", tag);
size_t offset = 0;
int padlen = 0;
while (length > 0)
{
int linelen = min_len(length, 80 - maxpadlen - sizeof("[]\n"));
printf("%*s[%.*s]\n", padlen, "", linelen, buffer + offset);
offset += linelen;
length -= linelen;
padlen = maxpadlen;
}
}

int main(void)
{
int i = 37;
int j = 99;

printf("i = %d; j = %d\n", i, j);
generic_swap(&i, &j, sizeof(i));
printf("i = %d; j = %d\n", i, j);

char data[80] = "A tabloid writer's nightmare on steroids";
char info[80] = "Obsequiousness will get you nowhere fast";

printf("data = [%s]\ninfo = [%s]\n", data, info);
generic_swap(data, info, sizeof(data));
printf("data = [%s]\ninfo = [%s]\n", data, info);

char maxibuff1[2560];
char maxibuff2[2560];

for (size_t k = 0; k < sizeof(maxibuff1); k++)
{
maxibuff1[k] = k % 64 + '!';
maxibuff2[k] = 'z' - k % 64;
}

/* The aligned output is mostly the result of serendipity */
dump_long_buffer("maxibuff1", sizeof(maxibuff1), maxibuff1);
dump_long_buffer("maxibuff2", sizeof(maxibuff2), maxibuff2);
generic_swap(maxibuff1, maxibuff2, sizeof(maxibuff1));
dump_long_buffer("maxibuff1", sizeof(maxibuff1), maxibuff1);
dump_long_buffer("maxibuff2", sizeof(maxibuff2), maxibuff2);

return 0;
}

示例输出(每个算法的结果相同):

i = 37; j = 99
i = 99; j = 37
data = [A tabloid writer's nightmare on steroids]
info = [Obsequiousness will get you nowhere fast]
data = [Obsequiousness will get you nowhere fast]
info = [A tabloid writer's nightmare on steroids]
maxibuff1 = [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
[!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]

[!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
maxibuff2 = [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
[zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]

[zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
maxibuff1 = [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
[zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]

[zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
maxibuff2 = [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
[!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]

[!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]

关于c - C中的通用数组元素交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50559106/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com