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