在C中交换指针(char,int)

时间:2011-12-06 16:36:22

标签: c pointers

我一直在努力理解在C中交换指针时的不同行为。 如果我想交换两个int指针,那么我可以做

void intSwap (int *pa, int *pb){
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}

但是,如果我想交换两个char指针,我需要做一些像

这样的事情
void charSwap(char** a, char** b){
    char *temp = *a;
    *a = *b;
    *b = temp;
}

因为如果我这样做

void charSwap(char* a, char* b){
    char temp = *a;
    *a = *b;
    *b = temp;
}

编译器抱怨表达式* a = * b,因为它无法更改值。 如果我想交换两个strings(即char* s1= "Hello"; char* s2="Bye";),那会怎么做呢?

你可以给我一些帮助吗?我想真正了解它是如何工作的,所以在获得正确答案之前我不需要经历反复试验。 我希望它对很多其他人有用。

6 个答案:

答案 0 :(得分:97)

您需要了解的第一件事是,当您将某些内容传递给函数时,会将某些内容复制到函数的参数中。

假设您有以下内容:

void swap1(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    assert(a == 17);
    assert(b == 42);
    // they're swapped!
}

int x = 42;
int y = 17;
swap1(x, y);
assert(x == 42);
assert(y == 17);
// no, they're not swapped!

原始变量不会被交换,因为它们的值被复制到函数的参数中。然后函数继续交换这些参数的值,然后返回。原始值不会更改,因为该功能仅交换其自己的私有副本。

现在我们如何解决这个问题?该函数需要一种方法来引用原始变量,而不是它们的值的副本。我们如何在C中引用其他变量?使用指针。

如果我们将指向变量的指针传递给函数,该函数可以交换我们的变量中的值,而不是它自己的参数副本。

void swap2(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    assert(*a == 17);
    assert(*b == 42);
    // they're swapped!
}

int x = 42;
int y = 17;
swap2(&x, &y); // give the function pointers to our variables
assert(x == 17);
assert(y == 42);
// yes, they're swapped!

注意函数内部我们没有分配指针,而是指定它们指向的内容。指针指向我们的变量xy。该函数通过我们给出的指针直接更改存储在我们的变量中的值。而这正是我们所需要的。

现在如果我们有两个指针变量并希望交换指针本身(而不是它们指向的值)会发生什么?如果我们传递指针,指针将被简单地复制(而不是它们指向的值)到参数。

void swap3(int* a, int* b) {
    int* temp = a;
    a = b;
    b = temp;
    assert(*a == 17);
    assert(*b == 42);
    // they're swapped!
}
void swap4(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    assert(*a == 17);
    assert(*b == 42);
    // they're swapped!
}

int x = 42;
int y = 17;
int* xp = &x;
int* yp = &y;
swap3(xp, yp);
assert(xp == &x);
assert(yp == &y);
assert(x == 42);
assert(y == 17);
// Didn't swap anything!
swap4(xp, yp);
assert(xp == &x);
assert(yp == &y);
assert(x == 17);
assert(y == 42);
// Swapped the stored values instead!

函数swap3仅交换它在参数中得到的指针的私有副本。这与swap1的问题相同。并且swap4正在改变我们的变量指向的值,而不是指针!我们为函数提供了引用变量xy的方法,但我们希望它们引用xpyp

我们如何做到这一点?我们把它们的地址传递给它!

void swap5(int** a, int** b) {
    int* temp = *a;
    *a = *b;
    *b = temp;
    assert(**a == 17);
    assert(**b == 42);
    // they're swapped!
}


int x = 42;
int y = 17;
int* xp = &x;
int* yp = &y;
swap5(&xp, &yp);
assert(xp == &y);
assert(yp == &x);
assert(x == 42);
assert(y == 17);
// swapped only the pointers variables

这样它会交换我们的指针变量(注意xp现在指向y的方式),但不是它们指向的值。我们给它一个方法来引用我们的指针变量,所以它可以改变它们!

到现在为止,应该很容易理解如何以char*变量的形式交换两个字符串。交换函数需要接收指向char*的指针。

void swapStrings(char** a, char** b){
    char *temp = *a;
    *a = *b;
    *b = temp;
    assert(strcmp(*a, "world") == 0);
    assert(strcmp(*b, "Hello") == 0);
}

char* x = "Hello";
char* y = "world";
swapStrings(&x, &y);
assert(strcmp(x, "world") == 0);
assert(strcmp(y, "Hello") == 0);

答案 1 :(得分:5)

void intSwap (int *pa, int *pb){
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}

您需要了解以下内容 -

int a = 5; // an integer, contains value
int *p; // an integer pointer, contains address
p = &a; // &a means address of a
a = *p; // *p means value stored in that address, here 5

void charSwap(char* a, char* b){
    char temp = *a;
    *a = *b;
    *b = temp;
}

所以,当你这样交换时。只交换值。因此,对于char*,只有他们的第一个char会互换。

现在,如果你清楚地理解char *(字符串),那么你应该知道,你只需要交换指针。如果您认为它是array而不是字符串,那么理解起来会更容易。

void stringSwap(char** a, char** b){
    char *temp = *a;
    *a = *b;
    *b = temp;
}

所以,这里你传递的是双指针,因为array本身就是一个指针。

答案 2 :(得分:4)

在C中,如您所知,字符串是字符指针(char *)。如果要交换两个字符串,则需要交换两个char指针,即只有两个地址。为了在函数中进行任何交换,您需要为其提供要交换的两件事的地址。因此,在交换两个指针的情况下,您需要一个指针指针。非常喜欢交换int,你只需要一个指向int的指针。

您的上一个代码段不起作用的原因是因为您希望它交换两个char指针 - 它实际上是为了交换两个字符而写的!

编辑:在上面的示例中,您正在尝试错误地交换两个int指针,正如R. Martinho Fernandes所指出的那样。如果您有,那将换掉两个整数:

int a, b;
intSwap(&a, &b);

答案 3 :(得分:1)

您需要了解传递引用和传递值之间的差异。

基本上,C只支持按值传递。因此,在将变量传递给函数时,不能直接引用变量。如果要将变量更改为交换所执行的函数,则需要使用pass-by-reference。要在C中实现pass-by-reference,需要使用指针,它可以取消引用该值。

功能:

void intSwap(int* a, int* b)

它将两个指针值传递给intSwap,并在函数中交换a / b指向的值,但不交换指针本身。这就是为什么R. Martinho& Dan Fego说它交换了两个整数,而不是指针。

对于字符,我认为你的意思是字符串,更复杂。 C中的字符串实现为chars数组,由char *(一个指针)作为字符串值引用。如果你想通过引用传递char *,你需要使用char *的ponter,所以你得到char **。

下面的代码可能更清楚:

typedef char* str;
void strSwap(str* a, str* b);

语法swap(int& a,int& b)是C ++,它直接表示pass-by-reference。也许一些C编译器也会实现。

希望我能说得更清楚,而不是说好。

答案 4 :(得分:1)

如果您有幸使用C ++,请使用:

template<typename T>
void swapPrimitives(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

当然,在char*的情况下,它只会交换指针本身,而不是它们指向的数据,但在大多数情况下,这没关系,对吗?

答案 5 :(得分:1)

此示例不交换两个int指针。它交换papb所指向的整数的值。这是调用此示例时发生的情况的一个示例:

void Swap1 (int *pa, int *pb){
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}
int main()
{
    int a = 42;
    int b = 17;


    int *pa = &a;
    int *pb = &b;

    printf("--------Swap1---------\n");
    printf("a = %d\n b = %d\n", a, b);
    swap1(pa, pb);
    printf("a = %d\n = %d\n", a, a);
    printf("pb address =  %p\n", pa);
    printf("pa address =  %p\n", pb);
}

这里的输出是:

a = 42
b = 17
pa address =  0x7fffdf933228
pb address =  0x7fffdf93322c
--------Swap---------
pa = 17
pb = 42
a = 17
b = 42
pa address =  0x7fffdf933228
pb address =  0x7fffdf93322c

请注意,这些值已交换,但指针的地址未交换!

为了交换地址,我们需要这样做:

void swap2 (int **pa, int **pb){
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}

并在主调用中使用swap2(&pa, &pb);

之类的函数

现在将交换地址以及指针的值。 ab具有与用初始化的相同的值。整数a和b没有交换,因为它们swap2交换了指针所指向的地址!:

a = 42
b = 17
pa address =  0x7fffddaa9c98
pb address =  0x7fffddaa9c9c
--------Swap---------
pa = 17
pb = 42
a = 42
b = 17
pa address =  0x7fffddaa9c9c
pb address =  0x7fffddaa9c98

由于C中的字符串是char指针,并且您想交换String,因此实际上是在交换char指针。与带有int的示例一样,您需要一个双指针来交换地址。

即使地址不是整数,也可以交换整数值,但是根据定义,字符串是字符指针。 您可以使用单个指针作为参数交换一个字符,但是字符指针必须是双指针才能交换字符串。