指针传递给函数的指针

时间:2016-01-26 12:06:54

标签: c pointers

为什么输出为1, 7

执行函数p1foo后,为什么bar没有变化?在我看来,p1指向与n相同的位置,根据行

int *p1=n; 

然后功能:foo()bar()似乎会改变p1指向p2的位置,不是吗?

#include <stdio.h>

void foo(int *p1,int *p2){
    p1=p2;
    *p1=*p2+1;

}
void bar(int**p1, int **p2)
{
    p1=p2;
    *p1=*p2+1;
    **p1=**p2+2;
}

int main() {
    int n[]={1,2,3};
    int m[]={4,5,6};
    int *p1=n;
    int *p2=m;
    foo(p1,p2);
    bar(&p1,&p2);
    printf("%d %d\n", *p1,*p2);        
}

3 个答案:

答案 0 :(得分:1)

这就是发生的事情:

int n[]={1,2,3};
int m[]={4,5,6};
int *p1=n; //p1 -> n = 1, 2, 3
int *p2=m; //p2 -> m = 4, 5, 6
foo(p1,p2); //

//in foo, 
//important note: &p1 inside and &p1 outside foo are different. But p1 inside and p1 outside foo are the same
//at first both p1 inside and p1 outside still points to n
//but changes will take place soon
p1=p2; //p1 & p2 points to the same item (m) p1 -> m = 4, 5, 6; p2 -> m = 4, 5, 6. Important: p1 no longer points to n here!
*p1=*p2+1; //p1 -> m = 5, 5, 6; p2 -> m = 5, 5, 6 (add the first pointed element by 1)
//out foo

//now p1 and p2 point back to original assignment! That is &p1 and &p2 are back! So does what these p1 and p2 originally pointed to
//p1 -> n = 1, 2, 3; p2 -> m = 5, 5, 6 //note that p1 points to n again

bar(&p1,&p2);

//in bar &p1 is casted to **p1, so happen for &p2
//important note: p1 inside and p1 outside foo are the same, but &p1 inside and &p1 outside are again different
//note also that the type for p1 inside (**int) and p1 (*int) outside are different
//yet the point to the same item (p1 (outside) -> n, p1 (inside) -> n)
//then the changes immediately take place
p1=p2; //p1 & p2 points to the same item: p1 -> m = 5, 5, 6, p2 -> m = 5, 5, 6. Important: p1 no longer points to n here!
*p1=*p2+1; //pointing shift!! Pointed value of p1 (& also p2) added by 1! p1 -> &m[1] = 5, 6 p2 -> &m[1] = 5, 6
**p1=**p2+2; //the first value in the pointed value added by 2 -> p1 -> &m[1] = 7[+2 happen here], 6; p2 -> &m[1] = 7[+2 happen here], 6
//out bar

//now p1 and p2 point back to original assignment!
//p1 -> n = 1, 2, 3; p2 -> 5, 7, 6

printf("%d %d\n", *p1,*p2); //1, 7

像这样调试它,事情就会很清楚:

#include <stdio.h>

void foo(int *p1,int *p2){
    printf("foo: &p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);
    p1=p2;
    printf("foo: &p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);
    *p1=*p2+1;
    printf("foo: &p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);

}
void bar(int**p1, int **p2)
{
    printf("bar: p1=%x *p1=%x **p1=%d p2=%x *p2=%x **p2=%d\n", p1, *p1, **p1, p2, *p2, **p2);
    p1=p2;
    printf("bar: p1=%x *p1=%x **p1=%d p2=%x *p2=%x **p2=%d\n", p1, *p1, **p1, p2, *p2, **p2);
    *p1=*p2+1;
    printf("bar: p1=%x *p1=%x **p1=%d p2=%x *p2=%x **p2=%d\n", p1, *p1, **p1, p2, *p2, **p2);
    **p1=**p2+2;
    printf("bar: p1=%x *p1=%x **p1=%d p2=%x *p2=%x **p2=%d\n", p1, *p1, **p1, p2, *p2, **p2);
}

int main() {
    int n[]={1,2,3};
    int m[]={4,5,6};
    int *p1=n;
    int *p2=m;
    int **addp1 = &p1;
    int **addp2 = &p2;
    printf("&p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);
    foo(p1,p2);
    printf("&p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);
    bar(&p1,&p2);
    printf("&p1=%x p1=%x *p1=%d &p2=%x p2=%x *p2=%d\n", &p1, p1, *p1, &p2, p2, *p2);
    printf("%d %d\n", *p1,*p2);
}

结果:

&p1=29fedc p1=29feec *p1=1 &p2=29fed8 p2=29fee0 *p2=4

foo: &p1=29feb0 p1=29feec *p1=1 &p2=29feb4 p2=29fee0 *p2=4
foo: &p1=29feb0 p1=29fee0 *p1=4 &p2=29feb4 p2=29fee0 *p2=4
foo: &p1=29feb0 p1=29fee0 *p1=5 &p2=29feb4 p2=29fee0 *p2=5

&p1=29fedc p1=29feec *p1=1 &p2=29fed8 p2=29fee0 *p2=5

bar: p1=29fedc *p1=29feec **p1=1 p2=29fed8 *p2=29fee0 **p2=5
bar: p1=29fed8 *p1=29fee0 **p1=5 p2=29fed8 *p2=29fee0 **p2=5
bar: p1=29fed8 *p1=29fee4 **p1=5 p2=29fed8 *p2=29fee4 **p2=5
bar: p1=29fed8 *p1=29fee4 **p1=7 p2=29fed8 *p2=29fee4 **p2=7

&p1=29fedc p1=29feec *p1=1 &p2=29fed8 p2=29fee4 *p2=7
1 7

Process returned 4 (0x4)   execution time : 0.008 s
Press any key to continue.

答案 1 :(得分:1)

让我们考虑这两个功能。

在调用后的第一个函数中

foo(p1,p2);

指针p1指向数组n

的第一个元素
int *p1=n;

而指针p2指向数组m

的第一个元素
int *p2=m;

这些指针的副本作为参数传递给函数。

功能内部

void foo(int *p1,int *p2){
    p1=p2;
    *p1=*p2+1;

}
分配后

p1=p2;

指针p1现在指向数组m的第一个元素。这就是指针p1p2现在都指向数组m的第一个元素。

因此事实上这句话

*p1=*p2+1;

相当于

m[0] = m[0] + 1;

因为指针p1现在指向数组的第一个元素,p2指向arry的第一个元素。

结果,数组的第一个元素被更改,现在它等于5

考虑到在函数p2内分配给指针p1

p1=p2;

main中与参数同名的原始指针未更改,因为该函数处理原始指针的副本。

当第二个函数被调用时

bar(&p1,&p2);

然后你传递指向指针p1p2

的指针
void bar(int**p1, int **p2)
{
    p1=p2;
    *p1=*p2+1;
    **p1=**p2+2;
}

在声明中的这个函数

    p1=p2;

指向原始指针p2的指针被分配给变量p1

现在两个变量都包含main中原始指针p2的地址。

在本声明中

*p1=*p2+1;

例如,表达式*p是存储在main中的原始指针p2中的值。此值是数组m的第一个元素的地址。 因此,表达式*p2 + 1是数组m

的第二个元素的地址

结果现在main中的原始指针p2包含数组m的第二个元素的地址。

在此声明之后

**p1=**p2+2;

数组的第二个元素增加了2,现在等于7

因此调用该函数的效果是双重的。它改变了原始指针p2。现在它指向数组m的第二个元素。第二个元素改变了。

答案 2 :(得分:0)

C中的参数是传递的值,也就是说,应用于参数的任何修改都不会对传递的外部参数产生影响。

foo p2 的副本分配给 p1的副本。因此,*p1 == *p2

*p1 = *p2 + 1;

相当于

++*p2;

在数组4中将5递增到m

bar同样失败。它相当于

++*p2;
**p2 += 2;

p2main增加1,将该位置的元素从5增加到数组7中的m

同时打印p1点到n[0]1p2点到m[1],即7。< / p>