循环内的变量和分配

时间:2012-06-24 15:33:41

标签: c memory-management compiler-construction memory-leaks

最近我偶然发现源代码,程序员根据 if / else 条件在一个无限循环内声明变量。我发现奇怪的是代码运行并且它没有暗示任何内存泄漏。首先,我认为这可能是特定于体系结构的东西(代码是针对ARM的)但我运行了一些测试,我发现在使用GCC编译的IA32上的二进制文件也以相同的方式运行。

我的方法是这样的:我创建了两个小程序foo.c和bar.c

foo.c的:

#include <stdio.h>

int main(void)
{
   int i;

   for(i=0; i<10; i++) {
      char buf[10];
      buf[i] = 0;
      printf("buf[%d] (@ %#x) == %d\n", i, &buf, buf[i]);
   }

   return(0);
}

Bar.c:

#include <stdio.h>

int main(void)
{
   int i;

   for(i=0; i<10; i++) {
      char *ptr;
      ptr = (char *) malloc(10);
      ptr[i] = 0;
      printf("buf[%d] (@ %#x) == %d\n", i, &ptr, ptr[i]);
   }

   return(0);
}

Foo.c 中声明数组和在 Bar.c 中分配内存之间明确区分的原因是我首先认为编译器可能会自动检测到它是相同的变量,只是在初始 for 迭代后忽略声明,当然不应该是 Bar.c 的情况,因为我明确地分配了内存。

对我来说真的很奇怪,在两个例子中,在初始 for 迭代之后,数组和已分配内存的地址保持不变。

我不完全理解这一点,而且我没有 K&amp; R 的副本,所以我会感谢您的解释。 (如果我在推理中犯了任何错误,我会很高兴指出它。)

2 个答案:

答案 0 :(得分:2)

不要打印指针ptr的地址(这是循环中的常量,因为ptr是本地变量,在当前调用框中),但打印指针本身:

 printf ("buf[%d] == %d, ptr == %p\n", i, ptr[i], (void*) ptr);

(请记住,如果a是一个数组,那么你有&a == a并且它们的类型兼容,但如果p是一个指针,你通常没有{{1} },并且它们的类型不兼容)

当然,如果你在循环中&p == p指针,你通常希望malloc指针位于循环体的末尾。

您应该学会使用free(在Linux上,甚至也可以使用gcc -Wall -g)进行编译,并使用调试器-Wextra(在Linux上)。

valgrind是Linux上用于捕获内存泄漏的有用工具。您可以使用Boehm's conservative garbage collector来“避免”它们(使用gdb代替GC_malloc,而不是为malloc显式内存而烦恼。

答案 1 :(得分:1)

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int i;
    for(i=0; i<10; i++) {
    char *ptr;
    ptr = malloc(10);
    ptr[i] = 0;
    printf("buf[%d] ptr is %#x, &ptr is %#x, ptr[i] is %d\n", i, ptr, &ptr, ptr[i]);
    }
    return 0;
}

我将ptr添加到bar.c的输出中。现在你可以找到答案了。这是新的源代码bar.c.我修复了其他人提到的所有错误。您可以通过“gcc -o bar bar.c”编译它并运行“./bar”。

输出结果为:

    ./bar
    buf[0] ptr is 0x820a008, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[1] ptr is 0x820a018, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[2] ptr is 0x820a028, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[3] ptr is 0x820a038, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[4] ptr is 0x820a048, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[5] ptr is 0x820a058, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[6] ptr is 0x820a068, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[7] ptr is 0x820a078, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[8] ptr is 0x820a088, &ptr is 0xbfb9dc48, ptr[i] is 0
    buf[9] ptr is 0x820a098, &ptr is 0xbfb9dc48, ptr[i] is 0

您可以在每一行找到ptr更改的值,但&amp; ptr的值保持相同的值。 结论:ptr在每次“for”迭代时分配不同的内存,但是ptr的地址不会改变。