一个简单C程序的奇怪输出
我有以下C语言版本:一个简单C程序的奇怪输出,c,C,我有以下C语言版本: int x = 0; int *a = &x; void foo(int *a) { static int x = 0; x++; *a += x; a = &x; *a = x + 10; } int _tmain(int argc, _TCHAR* argv[]) { foo(a); foo(a); printf("%d\n", *a); return 0; } 我可以清楚地
int x = 0;
int *a = &x;
void foo(int *a)
{
static int x = 0;
x++;
*a += x;
a = &x;
*a = x + 10;
}
int _tmain(int argc, _TCHAR* argv[])
{
foo(a);
foo(a);
printf("%d\n", *a);
return 0;
}
我可以清楚地调试它,并看到行*a+=x
没有任何作用,而且我可以看到在函数退出前一秒x的值是22
,并且它打印出13
当我在脑子里做这件事的时候,我已经34岁了,就我所知,这应该是正确的答案。
有人能解释一下我哪里可能错了吗?很简单。棘手的部分是识别函数中
x
的不同副本以及a
的范围
void foo(int *a)
{
static int x = 0;
x++;
*a += x;
a = &x; //<==== this doesn't change the a outside you see, a now points to static x
*a = x + 10;
}
void foo(int*a)
{
静态int x=0;
x++;
*a+=x;
a=&x;//这样更容易查看
int x = 0;
int *a = &x;
void foo(int *a)
{
static int y = 0;
y++;
*a += y;
a = &y; // a doesn't point to x anymore!!!
*a = y + 10;
}
int _tmain(int argc, _TCHAR* argv[])
{
foo(a);
foo(a); // Now 'a' again points to the global 'x' (once more)
printf("%d\n", *a);
return 0;
}
让我们一步一步地做吧
第一轮:
int x = 0; // global "x"
static int x = 0; // local "x" = 0
x++; // local "x" = 1
*a += x; // global "x" += local "x" results in global "x" = 1
a = &x; // local "a" points to local "x"
*a = x + 10; // local "x" = local "x" + 10 results in local "x" = 11
第二轮:
int x = 0; // global "x" = 1 now
static int x = 0; // local "x" = 11 now
x++; // local "x" = 12
*a += x; // global "x" += local "x" results in global "x" = 13
a = &x; // local "a" points to local "x"
*a = x + 10; // local "x" = local "x" + 10 results in local "x" = 22
printf("%d\n", *a); // prints global "x", 13
由于C使用静态作用域,当有两个同名的变量时,将首先使用当前块中声明的变量,然后再查看外部块。因此,静态int x会隐藏全局变量x。另外,您应该注意的是,在C中,参数是按值传递的,因此,如果指定值的副本,则不要影响原始值
假设全局变量x的地址为0x8000,静态变量x的地址为0x9000。这是第一次调用时发生的情况:
void foo(int *a) // a= 0x8000 , global int x=0
{
static int x = 0;
x++; // static int x=1
*a += x; // global int x=1
a = &x; // a=0x9000 (only a copy of a is assigned, so the global a will remain 0x8000)
*a = x + 10; // static int x= 11
}
这就是第二次通话中发生的情况:
void foo(int *a) // a= 0x8000 , global int x=1, static int x=11
{
static int x = 0;
x++; // static int x=12
*a += x; // global int x= 13
a = &x; // a=0x9000
*a = x + 10; // static int x= 22
}
您的foo
函数中有一个全局变量x
,然后是一个局部变量。它们之间存在冲突。请更改其中一个变量的名称。我知道冲突,我想知道此特定程序的输出。这是一个面试问题。这完全符合它的工作原理。问题出在哪里?您正在修改的值>堆栈上的a
…如果您想修改全局指针a,您应该将a
**a作为函数参数…请记住,在第一次调用函数时,“a”从指向全局“x”变为指向静态“x”:DIf它是11,为什么它打印13?另外,在调试时,我看到全局xNGE太多了!上次我检查的时候是22。@Vadiklk在第一次迭代后,全局x是1,静态x是11。如果你明白了,第二次执行的foo
是类似的,你可以理解结果。-1因为局部a…局部a不再指向x…全局a仍然指向x。这里:foo(int*a)->/*这a
是本地的*/@neagogegab你基本上是说注释在错误的位置吗?@M.Alem你也可以将参数a
重命名为b
,以便更清楚。不,注释在正确的位置。这是第二次调用foo()a仍然会在条目处指向全局“x”,直到它到达commnet.Spot on!!感谢您的回答,现在我明白了!这是一个非常好的耐心解决方案。虽然静态变量仅在名称查找的意义上是局部的。从技术上讲,它更接近全局变量。