【问题标题】:c while loop treats local variable in loop as global, why?c while循环将循环中的局部变量视为全局变量,为什么?
【发布时间】:2012-02-21 21:53:06
【问题描述】:

下面是一个小的 C 应用程序。它会要求您输入一个单词。它停止询问何时获得了四个独特的单词。但在下面显示的表单中,除非您取消注释相关行,否则它不会正常运行。

#include <stdio.h>
#include <string.h>

#define WORDS_COUNT 4

int main()
{
    char* words[WORDS_COUNT];

    int words_added = 0;
    while (words_added<WORDS_COUNT)
    {

        puts ("\n-------enter a word-------");

        char response[250];

        scanf("%s", response);

        int i;
        int duplicate_flag = 0;
        for (i=0; i < words_added; i++)
        {
            if (strcmp(words[i], response) == 0)
            {
                duplicate_flag = 1;
                break;
            };
        };

        if (duplicate_flag == 0)
        {
            //char tmp[250];
            //strcpy(tmp, response);
            words[words_added] = response; //words[words_added] = tmp;
            puts("that's new!");
            words_added ++;
        } else {
            puts("you've said that already...");
        };

    };
    return 0;
};

如您所见,主要区别在于words[words_added] = response 和words[words_added] = tmp。

为什么tmp 变量可以工作,而response 却不行?

我猜response 每次迭代都会有完全相同的地址,tmp 每次迭代都会得到一个新地址。但为什么?然而它们都在同一个while循环中声明???

【问题讨论】:

标签: c memory while-loop


【解决方案1】:

当您分配words[words_added] = response 时,您将response 的地址(而不是内容)复制到数组中。因此,在原始形式中,您的代码应该将第二个单词和每个后续单词视为重复项。当您使用tmp 时,代码会将每个新的response 与存储在words[](的每个位置)中的先前tmp 进行比较,然后将其复制到tmp(如果不是重复的)。

所以我怀疑您的代码会检测到 立即 跟在原始代码之后的重复项,但不会检测到 2 个或更多单词之后出现的重复项。

words 数组包含 4 个指针,但没有为这些指针分配内存。 您需要为words 数组的每个元素分配内存,然后将每个字符串复制到其中:

if (duplicate_flag == 0)
{
  words[words_added++] = strdup(response); // allocates mem and copies the string
  puts("that's new!");
} else {
  ...
}

那么一定要free你程序最后的内存:

for (i = 0; i < words_added; ++i) {
  free(words[i]);
}

【讨论】:

  • “tmp 变量每次通过 for 循环在堆栈上分配,而响应在程序的生命周期中持续存在”是的,但为什么分配 tmp 而不是 response?
  • 你说的完全正确——很好!我已经修改了我的答案,并且我认为我已经更准确地解释了这种行为。您是否介意测试我的怀疑,即只会捕获立即重复的内容?如果您能确认这一点,我相信我们了解正在发生的事情。
  • 确认!我可以明白你的意思,没有“重新分配”,而是我的代码只是将response 与复制到 temp! 中的最后一个“不同”response 进行比较。为什么我总是假设重新分配发生在循环中? SMH。谢谢!
  • 由于这些变量是在堆栈上分配的,如果它们在每次迭代期间被释放和重新分配,我不会感到惊讶,但它们最终可能会位于相同的内存位置。此外,它们可能在迭代之间保持不变——但只是“意外”,因为代码不会碰巧在迭代之间覆盖内存。如果您认真对待与内存相关的错误,您可以在释放它们之前将memset 变量清零(或无效的、易于识别的值,如0xAA),以强制错误更快地显现出来。
【解决方案2】:

你做错了 - 你指向一个指针数组 - words[words_added] - 指向一个每次迭代都会改变的变量 - response

您需要在每次迭代中为 words[words_added] 分配存储空间,然后再进行 strcpy:
strcpy(words[words_added], response);

附:右大括号后不要加分号}

【讨论】:

  • tmp 和 response 属于同一类型。那么 tmp 不是每次迭代都会改变吗?
  • 没关系 - 它可能有效 - 但这是一个异常 - 进行适当的内存分配 malloc(完成后不要忘记释放 free)
  • 在实际程序中这正是我所做的,但我真的很想了解为什么编译器会给予response 特殊处理。 while 循环中的所有其他局部变量总是被重新分配,从未见过像response 那样的变量行为。我真的很想知道为什么。
  • @codeshogan 见this post 并接受你不应该做这样的事情。
  • @codeshogan 那你为什么不使用char words[NUM_WORDS][MAX_WORD_LENGTH];呢?
猜你喜欢
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 2016-05-14
  • 2011-06-05
  • 1970-01-01
  • 2019-11-07
相关资源
最近更新 更多