使用指针交换对象

时间:2010-02-09 21:36:10

标签: c pointers

我正在尝试将对象替换为使用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???

谢谢!

9 个答案:

答案 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);

表示将两个地址复制到名为ab的新变量中。因此,如果您更改ab中存储的内容,则swap返回后,您所做的任何操作都不会产生任何影响。

答案 3 :(得分:1)

首先,请注意,对函数内部指针的任何更改都不会传播到函数外部。所以你将不得不移动记忆。

最简单的方法是使用memcpy - 在堆栈上分配一个缓冲区,memcpyamemcpy的适当大小,b来自{{1}从amemcpy,最后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;
}