我正在尝试将对象替换为使用void指针交换对象的作业问题。我的职能宣言必须是:
void swap(void *a, void *b, size_t size);
我不是在寻找确切的代码如何做到这一点我可以自己解决,但我不确定我是否理解正确。我发现有一个问题是:
void *temp;
temp = a;
a = b;
b = temp;
只改变指针指向的内容。那是对的吗?如果它是正确的,为什么交换指针实际上不会改变* a和* b之间的内容。因为如果你的指针指向不同的东西,你不能取消引用它,现在对象会有所不同吗?
同样,只需切换值:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
也不正确,我不知道为什么。因为在我看来,内容也在切换。
交换对象是否意味着完全交换内存和指针指向的值?
所以我似乎必须使用malloc为我的交换分配足够的空间。如果我为一个对象分配足够的内存,假设它们的大小相同,我真的不知道它与上面的其他两种方法有什么不同。
void *temp = malloc(sizeof(pa));
// check for null pointer
temp = a;
// do something I'm not sure of since I don't quite get how allocating space is any
// different than the two above methods???
谢谢!
答案 0 :(得分:19)
交换指针不会更改指向的值。如果确实如此,那就像在信封上交换地址标签,让我进入你的房子,然后你进入我的房子。
你快到了那里:
void swap(void *a, void *b, size_t size) {
char temp[size]; // C99, use malloc otherwise
// char serves as the type for "generic" byte arrays
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
memcpy函数复制内存,它是C中对象的定义。(在C ++中称为POD或普通ol'数据,进行比较。)这样,memcpy就是你如何进行分配而不关心对象的类型,你甚至可以将其他作业写为memcpy:
int a = 42, b = 3, temp;
temp = b;
b = a;
a = temp;
// same as:
memcpy(&temp, &b, sizeof a);
memcpy(&b, &a, sizeof a);
memcpy(&a, &temp, sizeof a);
这正是上面函数所做的,因为当你不知道对象的类型时你不能使用赋值,而void是代表“unknown”的类型。 (当用作函数返回类型时,它也意味着“无”。)
作为好奇心,另一个版本在常见情况下避免使用malloc并且不使用C99的VLA:
void swap(void *a, void *b, size_t size) {
enum { threshold = 100 };
if (size <= threshold) {
char temp[threshold];
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
else {
void* temp = malloc(size);
assert(temp); // better error checking desired in non-example code
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
free(temp);
}
}
答案 1 :(得分:3)
要回答你的第一个问题,让我们填写一些值来看看发生了什么:
void* a = 0x00001000; // some memory address
void* b = 0x00002000; // another memory address
/* Now we'll put in your code */
void* temp; // temp is garbage
temp = a; // temp is now 0x00001000
a = b; // a is now 0x00002000
b = temp; // b is now 0x00001000
因此,在这些语句结束时,指针的值已被交换,即a
指向的任何值现在由b
指向,反之亦然。这些指针所指向的值是未经修改的,只是现在它们的内存地址由不同的指针保存。
要回答第二个问题,您无法取消引用void*
。原因是void
没有大小,因此尝试取消引用或分配给没有大小的东西是荒谬的。因此,void*
是一种保证您可以指向某事的方式,但是如果没有更多信息,您永远不会知道某事是什么(因此{{1}你的例程的参数)。
从那里,知道指针和指针指向的数据的大小,你可以使用像size
这样的例程将一个指针指向的数据移动到另一个指针所指向的位置。
答案 2 :(得分:2)
参数类似于局部变量,在函数开始执行之前将值复制到它们中。这个原型:
void swap(void *a, void *b, size_t size);
表示将两个地址复制到名为a
和b
的新变量中。因此,如果您更改a
和b
中存储的内容,则swap
返回后,您所做的任何操作都不会产生任何影响。
答案 3 :(得分:1)
首先,请注意,对函数内部指针的任何更改都不会传播到函数外部。所以你将不得不移动记忆。
最简单的方法是使用memcpy
- 在堆栈上分配一个缓冲区,memcpy
从a
到memcpy
的适当大小,b
来自{{1}从a
到memcpy
,最后b
到{{1}}。
答案 4 :(得分:1)
如果您正在编写一个函数来交换两个整数,给出指向它们的指针,那么交换指向的值的解决方案将起作用。但是,请考虑
的情况struct {
int a;
int b;
} a, b;
swap(&a, &b, sizeof(a));
你需要找到一种方法来交换传递的每个值的内容,而不知道它们实际包含的内容。
答案 5 :(得分:1)
你很亲密。
问题是:你只是“交换”指针 a 和 b 这些是函数中的局部变量。
我假设在函数之外你有一些变量,让我们称之为:
void *x = ...;
void *y = ...;
致电时:
swap(x, y, some_size);
a 和 b 分别指向与 x 和 y 相同的对象。现在,当您交换 a 和 b 点时, x 和 y 仍指向他们所在的位置指着之前。
要更改内存 x 和 y 点,您必须将指针传递给 x 变量,因此指向指针的指针:)
因为您无法更改功能声明,所以您只能交换 x (和 a )和 y 的内存内容(和 b )指向。一些解决方案在其他答案中:)通常memcpy
是你想要的。
答案 6 :(得分:0)
要更改内部指针并将其保持在外部,您必须通过引用或双指针传递指针。
如果您的功能必须如下:
void swap(void *a, void *b, size_t size);
我想你必须实现类似的东西:
void * temp;
temp = malloc(size);
memcpy(temp,a,size);
memcpy(a,b,size);
memcpy(b,temp,size);
free(temp);
答案 7 :(得分:0)
要产生任何实际效果,您需要执行与上述第二个块相同的操作:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
这里的问题是'void'没有大小,因此你无法分配'void'。您需要为temp
分配空间以指向,然后使用memcpy()
之类的内容复制值。
答案 8 :(得分:0)
我们不需要使用memcpy交换两个指针,代码运行良好(测试交换int *和char *字符串):
void swap(void **p, void **q)
{
void *t = *p;
*p = *q;
*q = t;
}