为什么输出为1, 7
?
执行函数p1
和foo
后,为什么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);
}
答案 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
的第一个元素。这就是指针p1
和p2
现在都指向数组m
的第一个元素。
因此事实上这句话
*p1=*p2+1;
相当于
m[0] = m[0] + 1;
因为指针p1
现在指向数组的第一个元素,p2
指向arry的第一个元素。
结果,数组的第一个元素被更改,现在它等于5
。
考虑到在函数p2
内分配给指针p1
p1=p2;
main中与参数同名的原始指针未更改,因为该函数处理原始指针的副本。
当第二个函数被调用时
bar(&p1,&p2);
然后你传递指向指针p1
和p2
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;
将p2
从main
增加1
,将该位置的元素从5
增加到数组7
中的m
。
同时打印p1
点到n[0]
,1
和p2
点到m[1]
,即7
。< / p>