Понимание указателей с помощью программы подкачки на C
Я пытаюсь лучше понять указатели и ссылки в C, и мой курс предоставил следующую программу в качестве примера.
#include <stdio.h>
void swap(int* a, int* b);
int main(void)
{
int x = 1;
int y = 2;
swap(&x, &y);
printf("x is %i\n", x);
printf("y is %i\n", y);
}
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
Я собрал воедино следующее, чтобы понять, поможет ли это мне лучше понять, что происходит, в основном в отношении необходимости использовать & против *(разыменование). По сути, синтаксис объявления указателя на тип int (int* a) вместо использования звездочки для "разыменования" (*a = *b) меня довольно смущает, и я надеялся, что кто-то сможет меня просветить. Вот еще одна версия выше, которая, как я думал, поможет прояснить ситуацию, но на самом деле это не так:
#include <stdio.h>
void swap(int* a, int* b);
int main(void)
{
int x = 1;
int y = 2;
int *a = &x;
int *b = &y;
swap(a, b);
printf("x is %i\n", x);
printf("y is %i\n", y);
}
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
Короче говоря, мой вопрос: есть ли функциональная разница между тем, что делают эти две программы? В чем разница между разыменованием (*a = *b
) по сравнению с использованием &
оператор (*a = &x
)".
4 ответа
Вы путаете декларацию и назначение.
*a = *b
называется назначением. Обратите внимание, что оно не включает имя типа.
int *a = &x
с другой стороны называется декларацией. Обратите внимание, что вы инициализируете указатель с адресом x. Вы не разыменовываете указатель, но объявляете его как указатель на int.
Посмотри на это:
int main() {
int a = 5;
int b = 2;
int *c = &a; // c when dereferenced equals 5; **Declaration**
int *d = &b; // d when dereferenced equals 2; **Declaration**
int tmp = *c; // tmp equals 5
*c = *d; // c when dereferenced now equals 2 **Assignment**
*d = tmp; // d when dereferenced now equals 5 **Assignment**
return 0;
}
Наконец, когда вы объявляете и инициализируете указатель в том же операторе, вы назначаете указателю адрес того, на что вы хотите указывать. Когда вы хотите изменить значение, на которое указывает объект, вы разыменовываете его, используя *
, С другой стороны, если вы хотите изменить то, на что оно указывает, вы не разыменовываете его.
&x
возвращает адрес х. х имеет тип целое число и a
имеет указатель типа на целое число. В этом случае (*a = &x) вы присваиваете адрес x переменной типа "указатель на целое число", которая a
, (*a = *b) - операция присваивания между двумя переменными одного типа, которая является целочисленной. Я сказал целое число, потому что хотя a
а также b
являются "указателями на целые числа", в этой операции они разыменовываются и, следовательно, читается целочисленное значение, на которое они указывают.
Я думаю, что у вас возникла путаница, потому что (*a = &x) имеет смысл только во время инициализации указателя.
Если вы установите *a = *b
поскольку a
а также b
переменные указателя, *
Оператор извлечет значение ячейки в памяти, которая b
указывает на это и помещает его в клетку, которая a
указывает на это.
За *a = &x
оператор & находит адрес ячейки, выделенной для x
переменная, и помещает его в ячейку, которая указывает на него.
Короче говоря, мой вопрос: есть ли функциональная разница между тем, что делают эти две программы?
Нет, функциональный эффект точно такой же. В
int *a = &x;
int *b = &y;
swap(a, b);
// swap(&a, &b)
Тип a
это то же самое из &a
а именно int*
(указатель на int
). Единственное отличие состоит в том, что вы используете другие переменные для хранения того, что на самом деле не нужно логически, но иметь его совершенно нормально, особенно если это поможет вам понять синтаксис.
В чем разница между разыменованием (*a = *b) и использованием & (*a = &x).
*a = *b
присваивает значение, на которое указывает b
(получено с *b
) в тех, на которые указывает a
, Чтобы увидеть это более четко,
int tmp = *b;
*a = tmp;
&(*a = &x)
не является допустимым выражением, потому что вы не можете сохранить адрес в int
(на самом деле вы можете, но это не главное).