Путаница с указателем: метод обмена в c - PullRequest
0 голосов
/ 03 апреля 2020
#include<stdio.h>
void swap(int *a,int *b){
    int p=*b;
    *b=*a;
    *a=p;

    /*int *p=b;
    b=a;
    a=p;
    */
}

int main(){
    int a,b;
    scanf("%d %d",&a,&b);
    swap(&a,&b);
    printf("%d %d",a,b);
}

Выше приведен код.

Если я поставлю 3 5 в качестве входа, то он должен поменять его значения, а 5 3 должен появиться в качестве выхода. Я получил ответ, попробовав int p = * b thing

Однако я также попробовал прокомментированную часть, но она не сработала.

Итак, я проверил их адрес в swap и в main.

В swap int * a и int * b их адрес изменился

Однако, когда я вернулся на main, адреса a и b не изменились ...

Итак, сначала я подумал: не изменилось ли оно в main, потому что параметр int * a, int * b является локальной переменной?

Но я также узнал, что когда указатели и аргументы используются в качестве аргументов, их значение может изменяться в отличие от других переменные ...

Мне действительно интересно, почему второй метод (закомментированная часть) не меняет местами значения ...

Ответы [ 4 ]

1 голос
/ 03 апреля 2020

Предполагая, что вы имели в виду

void swap(int *a,int *b){
int *p=b;
b=a;
a=p;
}

Этот код просто меняет значение указателей в функции swap(). Это не поменяет местами адреса в main(), потому что, как вы сказали, «параметр int * a, int * b является локальной переменной».

Когда вы вызываете функцию swap() следующим образом

swap(&a,&b);

адреса из a и b передаются и становятся локальными переменными в функции swap(). Вы не можете изменить адрес a или b - они имеют место в памяти.

В работающем коде

void swap(int *a,int *b){
int p=*b;
*b=*a;
*a=p;
}

вы не меняете значение из указателей вы изменяете значения в памяти, на которую указывают указатели, поэтому это работает.

Хотя C является передачей по значению, если вы передаете адрес чего-либо в качестве значения a Функция может изменить что-то вне ее области видимости, потому что вы сообщили функции, где находится эта переменная.

0 голосов
/ 03 апреля 2020

Если вы хотите изменить исходные объекты функции, вы должны передать их функции по ссылке.

В C передача объектов по ссылке означает косвенную передачу их через указатели, указывающие на исходный объект. .

В противном случае, если вы передадите сами исходные объекты в функцию, функция будет иметь дело с копиями объектов. Очевидно, что изменение копий не влияет на исходные объекты.

Это именно то, что происходит в этой функции

void swap(int *a,int *b){
    int *p=b;
    b=a;
    a=p;
}

Функция имеет дело с копиями указателей, переданных функции в качестве аргумента в этом вызове

swap(&a,&b);

То есть функция действительно поменяла местами значения двух указателей, которые объявлены как ее параметры. Но они не являются оригинальными указателями, переданными функции. Они являются копиями указателей. Значения исходных указателей не изменились

Функция подкачки в общем случае может выглядеть следующим образом

void swap( T *a, T *b )
{
    T tmp = *a;
    *a = *b;
    *b = tmp;
}  

, где T - это тот же спецификатор типа.

Так что если вы хотите поменять местами объекты типа int, то в приведенной выше функции T будет int и функция будет выглядеть как

void swap( int *a, int *b )
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}  

Если вы хотите поменять местами значения указателей введите int *, тогда T будет int *, а функция будет выглядеть так:

void swap( int **a, int **b )
{
    int *tmp = *a;
    *a = *b;
    *b = tmp;
}  

Вот демонстрационная программа.

#include <stdio.h>

void swap1( int *pa, int *pb )
{
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

void swap2( int **ppa, int **ppb )
{
    int *tmp = *ppa;
    *ppa = *ppb;
    *ppb = tmp;
}

int main(void) 
{
    int a = 3, b = 5;

    swap1( &a, &b );

    printf( "a = %d b = %d\n", a, b );

    //  reset again the values of the variables
    a = 3; b = 5;

    int *pa = &a, *pb = &b;

    swap2( &pa, &pb );

    printf( "*pa = %d *pb = %d\n", *pa, *pb );

    return 0;
}

Ее вывод

a = 5 b = 3
*pa = 5 *pb = 3

То есть сначала в программе меняются два объекта типа int, поэтому воображаемый спецификатор типа T равен int.

Затем два указателя, которые указывают на объекты a и b меняются местами. Таким образом, воображаемый спецификатор типа T int *.

После смены указателей указатель pa теперь указывает на объект b, а указатель pb теперь указывает на объект a.

0 голосов
/ 03 апреля 2020

В C все переменные, объявленные в функции, являются локальными для этой указанной c функции. Итак, вы написали что-то в функции swap

int * p = b;

То, что приведенный выше код будет делать, это скопирует значение из b в p. Таким образом, когда функция swap возвращает результат, ее локальные переменные p, b и a исчезают.

0 голосов
/ 03 апреля 2020

Во втором методе вы используете локальную переменную, которая ограничена областью действия функции swap. Таким образом, переменная a или b в основной функции отличается от переменной a или b, которая определена как аргумент в функции swap.

Когда вы используете указатель, функция swap изменит значение, на которое указывает указатель (это означает, что функция изменит значение по адресу a и b, объявленным в функции main).

...