一个简单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; } 我可以清楚地

我有以下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;
}
我可以清楚地调试它,并看到行
*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!!感谢您的回答,现在我明白了!这是一个非常好的耐心解决方案。虽然静态变量仅在名称查找的意义上是局部的。从技术上讲,它更接近全局变量。