C 函数,用于在每次调用时创建具有新内存地址的变量

C 函数,用于在每次调用时创建具有新内存地址的变量,c,C,假设有一个函数f,它的主体中包含一个新变量b的声明。 我注意到,每次调用f时,变量b(应该在每次创建和销毁时创建和销毁)(EDIT:不在动态情况下,正如所指出的那样)总是具有相同的内存地址 以下非常简单的代码向您展示了一个示例: #include <stdio.h> #include <stdlib.h> void f ( void ){ int b; printf ("%p\n", &b); } int main (){ int i =

假设有一个函数f,它的主体中包含一个新变量b的声明。 我注意到,每次调用f时,变量b(应该在每次创建和销毁时创建和销毁)(EDIT:不在动态情况下,正如所指出的那样)总是具有相同的内存地址

以下非常简单的代码向您展示了一个示例:

#include <stdio.h>
#include <stdlib.h>

void f ( void ){
   int b;
   printf ("%p\n", &b);
}

int main (){
    int i = 0;
    while (++i <= 10)
        f();
return 0;
}
#包括
#包括
无效f(无效){
int b;
printf(“%p\n”、&b);
}
int main(){
int i=0;

而(++i自动变量的地址取决于函数项上堆栈指针的值,它将是一个固定的偏移量。如果在这样的循环中调用函数:

while (...) {
    ...
    f(...);
    ...
}
#include <stdio.h>
#include <stdlib.h>

void f (void){
   int *b = malloc (sizeof(int));
   printf ("%p\n", b);
}

int main (){
   int i = 0;

   while (++i <= 10)
      f();
   return 0;
}
编译器生成代码的方式很可能是
f
的自动变量始终具有相同的地址。这是您无法轻易更改的


如果我们不使用自动变量,我们可以很容易地得到想要的结果。每次只需在
f
中分配一个新变量。当然,这会泄漏大量内存,但没有更好的方法,因为
f
必须记住已用于
b
的地址,如果您希望
b
驻留在不同的位置每次使用的地址和以前使用的地址都不可用(因此被浪费)。

也许您正在寻找的是动态内存分配?您可能需要阅读
malloc
calloc
realloc
free
的文档(原型为

从技术上讲,每个对象都有一个相关的存储类。对于像
f
这样的自动变量,这是自动的,通常在堆栈上分配(但也有无堆栈的机器)。对于动态分配的对象,存储类是动态的,通常从堆中分配(但也有无堆机器)


本质上,您不应该依赖具有特定模式或值的地址。

您观察到的行为是创建和回收堆栈帧的结果。当在while循环中重复调用
f()
时,会发生四种情况:

  • 内存管理单元在堆栈上为其获取一块内存,以保存其参数、局部变量和返回值

  • 局部变量
    b
    在此堆栈帧中声明,由于未初始化,它包含“垃圾数据”(本例中为
    0xDEADBEEF

  • f()
    返回,通过移动“堆栈顶部”指针将其堆栈帧循环上移到
    main()
    堆栈帧。请注意,
    f()
    的堆栈帧的内容永远不会被清除或归零。

  • 函数
    f()
    会立即被再次调用,因此会提取一个内存块。这与第一次调用
    f()
    时提取的内存块完全相同(继续并通过打印
    b
    的地址进行检查)。由于
    b
    未初始化,因此它包含“垃圾数据”,但它是相同的“垃圾数据”(
    0xDEADBEEF
    )在
    f()
    的第一次调用中,此后该位置尚未写入

  • 但是,使用
    malloc
    在堆上分配存储可能无法解决此问题!调用
    malloc()
    ,然后调用
    free()
    ,然后再调用
    malloc()
    将再次为您提供堆上相同的地址,如此测试程序所示:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char const *argv[])
    {
        char *ptr1 = malloc(sizeof(char));
        printf("Allocated memory at %p\n", ptr1);
    
        free(ptr1);
        printf("Freed memory at %p\n", ptr1);
    
        char *ptr2 = malloc(sizeof(char));
        printf("Allocated memory at %p\n", ptr2);
    
        free(ptr2);
        printf("Freed memory at %p\n", ptr2);
    
        if (ptr1 == ptr2) {
            printf("Pointers were the same!\n");
        }
    
        return 0;
    }
    
    非常接近您所拥有的,但由于
    b
    是一个地址,您可以只打印
    b
    ,而不是
    &b


    编辑:图像贷记到

    我可以问一下你为什么需要它吗?将
    &b
    (类型为
    int*
    )传递到
    %p
    格式(调用
    void*
    )是未定义的行为。在你的问题中,我看不到任何与程序输出类似的东西,而且
    f
    需要修改什么?@MikeCAT从技术上讲是,但这是o这是我不同意该标准的少数几种情况之一。这在所有指针具有相同表示形式的平台(即,您将看到的几乎所有平台)上都有效,而且将来也会有效。您的编辑就快到了,只需在printf中省去
    &b
    。我真的很感谢完整的详细解释-它帮了我很多。最后的“&”…谢谢,我打赌我会花几个小时。祝您愉快!
    #include <stdio.h>
    #include <stdlib.h>
    
    void f (void){
       int *b = malloc (sizeof(int));
       printf ("%p\n", b);
    }
    
    int main (){
       int i = 0;
    
       while (++i <= 10)
          f();
       return 0;
    }