循环内变量范围

问题描述:

这也许是我遇到过的最奇怪的事情之一。我不用C编程太多,但从我知道的是真实的,再加上在线检查不同的来源,变量宏名称宏体只在while循环的范围内定义。所以每次循环运行,我期待marcoName宏体获得新的地址,并成为完全新的变量。但是,这不是事实。循环内变量范围

我发现,即使循环再次运行,两个变量共享相同的地址,这导致我严重头痛的链表,我需要检查元素的唯一性。我不知道这是为什么。不应该宏名称macroBody每次while循环运行时都会得到全新的地址?

我知道这是问题,因为我打印的地址和他们是一样的。

while(fgets(line, sizeof(line), fp) != NULL) // Get new line 
{ 
    char macroName[MAXLINE]; 
    char macroBody[MAXLINE]; 

    // ... more code 

    switch (command_type) 
    { 
     case hake_macro_definition: 
      // ... more code 

      printf("**********%p | %p\n", &macroName, &macroBody); 
      break; 

     // .... more cases 
    } 
} 

代码是我的链接列表代码的一部分。

struct macro { 
    struct macro *next; 
    struct macro *previous; 
    char *name; 
    char *body; 
};  

检查元素是否已存在于链接列表中的函数。但由于*名称具有相同的地址,因此我总是在if条件内结束。

static struct macro *macro_lookup(char *name) 
{ 
    struct macro *temp = macro_list_head; 

    while (temp != NULL) 
    { 
     if (are_strings_equal(name, temp->name)) 
     { 
      break; 
     }  

     temp = temp->next; 
    } 

    return temp; 
} 
+0

如果您的期望是获得两个变量的唯一地址,为什么不定义一个指针,为循环的每次运行分配和释放内存。另外,你对这个问题的评论很有意思。你提到你根据地址的唯一性做出决定,在这种情况下,这是一个栈变量/存储器指针。 – Ganesh 2013-03-10 03:12:16

+0

是的,我可能会做这样的事情。谢谢! – ThePedestrian 2013-03-10 03:24:31

这些数组在栈中分配:

char macroName[MAXLINE]; 
char macroBody[MAXLINE]; 

编译器已预分配给你,你的功能开始存在空间。换句话说,从计算机的角度来看,这些数组的位置与您在函数体顶部的循环体之外定义它们的位置相同。

C中的范围仅指示标识符可见的位置。因此,编译器(但不是计算机)强制执行在循环体之前或之后不能引用macroNamemacroBody的语义。但是从计算机的角度来看,这些数组的实际数据在函数启动后就存在,并且只有在函数结束时才会消失。

如果您要查看代码的程序集转储,您可能会发现机器的帧指针减少了足够大的数量,以使函数的所有局部变量具有空间,包括这些变量阵列。

+0

所以我只在函数结束时得到“新”变量,是否正确? – ThePedestrian 2013-03-10 03:15:47

+2

@ThePedestrian这样的事情。你可以通过动态内存分配获得“新”空间,即通过'malloc()'。顺便说一下,如果你有兴趣更多地了解这些东西的工作原理,这整个研究领域被称为*计算机组织*。 – chrisaycock 2013-03-10 03:18:00

+0

我现在实际参加了计算机组织课。你如何解释事情很有意义。我从来没有新的情况。我假设使用了“新”内存/寄存器,但为什么变量只能存在一次才有意义。 – ThePedestrian 2013-03-10 03:20:08

我需要什么,除了chrisaycock的回答说:你不应该使用指针外函数的局部变量,这些变量定义考虑这个例子:

int * f() 
{ 
    int local_var = 0; 
    return &local_var; 
} 
int g(int x) 
{ 
    return (x > 0) ? x : 0; 
} 
int main() 
{ 
    int * from_f = f(); // 
    *from_f = 100; //Undefined behavior 
    g(15); //some function call to change stack 
    printf("%d", *from_f); //Will print some random value 
    return 0; 
} 

一样的,实际上,适用于块。从技术上讲,块结束后可以清除块本地变量。因此,在循环的每次迭代中,旧地址可能无效。这不会是真的,因为C编译器的确因为性能原因将这些变量放到相同的地址,但是你不能依赖它。

你需要了解的是如何分配内存。如果你想实现一个列表,它是一个增长的结构。记忆从哪里来?您不能从堆栈分配太多内存,并且一旦从函数返回,内存就会失效。所以,你需要从堆中分配它(使用malloc)。

+0

感谢您提到这一点。我遇到了另一个问题,它来自于你描述的场景。谢谢! – ThePedestrian 2013-03-10 20:03:33