我一直在努力理解在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";
),那会怎么做呢?
答案 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!
注意函数内部我们没有分配指针,而是指定它们指向的内容。指针指向我们的变量x
和y
。该函数通过我们给出的指针直接更改存储在我们的变量中的值。而这正是我们所需要的。
现在如果我们有两个指针变量并希望交换指针本身(而不是它们指向的值)会发生什么?如果我们传递指针,指针将被简单地复制(而不是它们指向的值)到参数。
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
正在改变我们的变量指向的值,而不是指针!我们为函数提供了引用变量x
和y
的方法,但我们希望它们引用xp
和yp
。
我们如何做到这一点?我们把它们的地址传递给它!
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指针。它交换pa
和pb
所指向的整数的值。这是调用此示例时发生的情况的一个示例:
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);
现在将交换地址以及指针的值。 a
和b
具有与用初始化的相同的值。整数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的示例一样,您需要一个双指针来交换地址。
即使地址不是整数,也可以交换整数值,但是根据定义,字符串是字符指针。 您可以使用单个指针作为参数交换一个字符,但是字符指针必须是双指针才能交换字符串。