6

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

我发现即使循环再次运行,两个变量共享相同的地址,这让我对需要检查元素唯一性的链表感到非常头疼。我不知道这是为什么。每次while循环运行时macroNamemacroBody不应该获得全新的地址吗?

我知道这是问题所在,因为我正在打印地址并且它们是相同的。

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;
}
4

2 回答 2

5

这些数组在堆栈上分配:

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

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

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

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

于 2013-03-10T03:11:57.243 回答
3

除了 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 编译器出于性能原因确实将这些 var 放在同一个地址,但你不能依赖它。

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

于 2013-03-10T09:03:28.600 回答