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

Другие вопросы по тегам