C 循环内的变量和分配

C 循环内的变量和分配,c,memory-management,compiler-construction,memory-leaks,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;

最近我偶然发现了源代码,其中程序员根据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);
}
#包括
内部主(空)
{
int i;

对于(i=0;i不打印指针的地址
ptr
(这是循环中的一个常量,因为
ptr
在当前调用帧中是一个局部变量),而是打印指针本身:

 printf ("buf[%d] == %d, ptr == %p\n", i, ptr[i], (void*) ptr);
(请记住,如果
a
是一个数组,您确实有
&a==a
并且它们的类型是兼容的,但是如果
p
是指针,您通常没有
&p==p
,并且它们的类型是不兼容的)

当然,如果您
malloc
循环中的某个指针,通常希望
释放循环体末端的该指针

您应该学习使用
gcc-Wall-g
(在Linux上,甚至可能还使用
-Wextra
)进行编译,并使用调试器
gdb
(在Linux上)


是Linux上用于捕获内存泄漏的有用工具。您可以使用它来“避免”内存泄漏(使用
GC\u malloc
而不是
malloc
,并且不必为
free
-ing显式占用内存而烦恼)。

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

 printf ("buf[%d] == %d, ptr == %p\n", i, ptr[i], (void*) ptr);
(请记住,如果
a
是一个数组,您确实有
&a==a
并且它们的类型是兼容的,但是如果
p
是指针,您通常没有
&p==p
,并且它们的类型是不兼容的)

当然,如果您
malloc
循环中的某个指针,通常希望
释放循环体末端的该指针

您应该学习使用
gcc-Wall-g
(在Linux上,甚至可能还使用
-Wextra
)进行编译,并使用调试器
gdb
(在Linux上)

是Linux上用于捕获内存泄漏的有用工具。您可以使用它来“避免”内存泄漏(使用
GC\u malloc
而不是
malloc
,并且不必为
释放内存而烦恼)

您可以发现ptr的值在每一行都会发生变化,但&ptr的值保持不变。 结论:ptr在每次“for”迭代时分配不同的内存,但ptr的地址不变

您可以发现ptr的值在每一行都会发生变化,但&ptr的值保持不变。

结论:ptr在每个“for”分配不同的内存迭代,但是PTR的地址没有改变。< /P> C++是不同于C的语言,你不知道吗?和<代码>返回<代码>不是一个函数…@安迪,请用英文写。如果他们想回答C问题,他们会订阅C标签。用不合适的标签来更多地关注你的问题被认为是粗鲁的。安迪:不。C和C++。是不同的语言。你不应该抛出MalCube()的返回值,你应该<代码> >包含C中的< /Cord> @安迪,你不必抛出,这是坏的风格。在C++中,你必须(但是无论如何都不应该使用<代码> MaloC < /COD>)不同的语言。非常不同。C++是不同于C的语言,你不知道吗?和<代码>返回<代码>不是一个函数…@安迪,请用英语写。如果他们想回答C问题,他们会订阅C标签。用不合适的标签来更多地关注你的问题被认为是粗鲁的。安迪:不,C和C++是不同的LA。你不应该投MalCube()的返回值,你应该<代码> >包含C中的< /Cord> @安迪,你不需要抛出,这是坏的风格。在C++中,你必须(但是无论如何都不应该使用<代码> MaloC < /COD>)。不同的语言。非常不同。老实说,它应该是
gcc-Wall-Wextra
,因为
-Wall
实际上是
-wnotall
(有时使用
-Werror
很方便).不管我是做&ptr还是ptr,这都无关紧要,因为这与我问的问题无关。为什么?因为即使我打印出ptr而不是&ptr,我仍然得到了相同的基址。我在问为什么每次迭代中用malloc显式分配内存时都是一样的。在这个例子中,释放也是毫无意义的(因为我想造成内存泄漏)。@Griwes
-Wall
包含了最常用的警告,但是,
-Wextra
启用的很多警告都是主观的,或者试图猜测最佳做法。@andy,编码
ptr
&ptr
不同,所以你说错了:“不管我是执行
&ptr
还是
ptr
”@delnan
-Wextra
的示例(从手册页):缺少
返回
语句(或多或少都是错误)、有符号/无符号比较(不一定是错误,但可以隐藏糟糕的错误)、缺少字段初始化器(几乎总是错误)。老实说,它应该是
gcc-Wall-Wextra
,因为
-Wall
实际上是
-wnotall
(有时使用
-Werror
很方便).不管我是做&ptr还是ptr,这都无关紧要,因为这与我问的问题无关。为什么?因为即使我打印出ptr而不是&ptr,我仍然得到了相同的基址。我在问为什么每次迭代中用malloc显式分配内存时都是一样的。在这个例子中,释放也是毫无意义的(因为我想造成内存泄漏)。@Griwes
-Wall
包含了最常用的警告,但是
-Wextra
启用的很多警告都是主观的,或者试图猜测最佳做法。@andy,coding

#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;
}
    ./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