while循环内的变量范围

Posted

技术标签:

【中文标题】while循环内的变量范围【英文标题】:Variable scope inside while loop 【发布时间】:2013-02-25 10:30:12 【问题描述】:

这可能是我遇到过的最奇怪的事情之一。我在 C 语言中编程不多,但根据我所知道的情况以及在线检查不同的来源,变量 ma​​croNamema​​croBody 仅在 while 循环的范围内定义.因此,每次循环运行时,我都希望 ma​​rcoNamema​​croBody 获得新地址并成为全新的变量。然而事实并非如此。

我发现即使循环再次运行,两个变量共享相同的地址,这让我非常头疼需要检查元素唯一性的链表。我不知道这是为什么。 ma​​croNamema​​croBody 不应该在每次 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;
;    

检查元素是否已存在于链表中的函数。但是由于 *name 具有相同的地址,所以我总是在 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;

【问题讨论】:

如果您的期望是为两个变量获取一个唯一的地址,为什么不定义一个指针,为每次循环运行分配和释放内存。另外,您对问题的评论很有趣。您提到您根据地址的唯一性做出决定,在这种情况下,地址是堆栈变量/内存指针。 是的,我可能会做这样的事情。谢谢! 【参考方案1】:

这些数组是在栈上分配的:

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

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

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

如果您要查看代码的程序集转储,您可能会看到您的机器的帧指针减少了足够大的量,以使您的函数的 call stack 为所有局部变量留出空间,包括这些数组。

【讨论】:

所以我只在函数结束时得到“新”变量,对吗? @ThePedestrian 类似的东西。您也可以通过动态内存分配获得“新”空间,即通过malloc()。顺便说一句,如果您有兴趣了解更多关于这些东西如何工作的信息,那么整个研究领域被称为计算机组织 我现在实际上正在参加计算机组织课程。你如何解释事情很有意义。我只是从来没有过这种情况。我假设使用了“新”内存/寄存器,但为什么变量只存在一次是有道理的。 @ThePedestrian 啊,太棒了!在我年轻的时候,在汇编中手动编码是我做过的最具教育意义的事情之一。享受吧。 我自己非常喜欢组装。不幸的是,我们没有花太多时间。我们了解了基础,然后继续前进。不过组装很有趣。真的让你欣赏更高层次的语言。非常感谢!【参考方案2】:

除了 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)。

【讨论】:

感谢您提及这一点。我遇到了另一个问题,它是由您描述的场景引起的。谢谢!

以上是关于while循环内的变量范围的主要内容,如果未能解决你的问题,请参考以下文章

while循环内的表变量每次都没有初始化:SQL Server

C ++在while循环内更​​改变量

带有双条件和 || 的 While 循环Swift 中的逻辑运算符

如何从while循环内的if条件中断while循环?

循环不简单,简单聊聊常用的三个shell循环,for-while-until

带有MySql PDO的while循环内的while循环