Ответ 1
Первое, что вам нужно понять, это то, что когда вы передаете что-то функции, это что-то копируется в аргументы функции.
Предположим, что у вас есть следующее:
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);