关于右值的范围和内存泄漏
About rvalues' scope and memory leaks
如果你留在同一个块中,右值会发生什么变化"forever"?
假设我有以下代码:
char buff[999];
time_t timer;
while(true){
...
time(&timer);
strcpy(buff, ctime(&timer));
...
}
在每次迭代中,右值 char *
将从 ctime
中 return,但它会在迭代结束时被释放,还是仅在块完成时被释放?
如果只是在块完成时,那么在几百万次迭代之后,内存可以用完成的右值填充char*
对吗?
(我用 c
和 c++
标记了这个,因为我也想知道这两者之间是否有区别)
由于历史原因,C 库中的函数 return 不同 class 内存:
- 不需要释放的静态分配内存。该库通常在其代码中将其声明为静态数组,并将在每次函数调用时重新使用相同的内存区域。
ctime
和 localtime
就是这方面的例子。 不要 释放此内存。 (可能值得一提的是,这些函数被认为已被弃用,并且由于它们不适合多线程操作而逐渐消失)
- 调用者需要 释放的动态分配内存。该内存由库函数动态分配,该库函数使用
malloc()
分配该内存,将指针返回给您,并希望您在完成后 free()
该内存。 strdup()
将是这种形式的一个很好的例子。
您只需需要知道您正在使用的特定库调用class是什么return,以便了解您是否需要free()
那个记忆与否。请查阅相应调用的手册页。
在 ctime()
的情况下,循环中的迭代绝对无关紧要。由于库 returns 每次迭代的缓冲区地址,它被写入堆栈帧中的相同位置没有内存泄漏这样的事情。如果您在循环中调用 strdup()
,则会造成内存泄漏。
(我在这里谈论的是 C,对于 C++,这要复杂得多)
局部变量比如你的
char buff[999];
time_t timer;
...通常在输入函数时一起分配。这些变量要么在堆栈帧中分配 space(在 buff 的情况下),要么直接在硬件寄存器上分配(在定时器的情况下可能)。
所有这些分配都是在一条机器指令中一起完成的,只需将指针移动到栈顶即可。每个函数调用的每个局部变量只有一个实例,因此 没有内存填满的危险,因为您在循环中使用它们。此外,对于内存区域可以增长的大小(大约 10 兆字节),全球限制相对较低。
所有局部变量在函数退出时通过销毁栈帧自动释放。同样,这只需再次将堆栈指针移回即可完成。这与静态函数变量(它们只是具有有限可达性的全局变量)和必须显式分配或释放的动态分配(堆)变量形成对比。
堆栈帧有点太复杂,无法在此处完整介绍,但我建议您仔细阅读它们,因为了解函数调用的工作原理确实有助于全面了解 C 编程。
如果您对变量存储有任何更具体的问题,我相信您可以在这里找到有关堆栈溢出的帮助,因为我们大多数 C 程序员都喜欢谈论这类事情:)
由 ctime
编辑的指针 return 在 C 和 C++ 中都称为 value。它不是一个对象,因此它没有生命周期或存储持续时间。
你的问题就像在问:在代码for(;;) { 10 + 10; }
中,内存会被20
填满吗? (答案是:否)。
(不要与 C++ 中的 temporaries 混淆,它们是对象并且有生命周期)。
在 C 中,可以访问函数的 return 值直到当前语句结束(即在您的情况下为下一个 ;
),尽管对于标量类型来说这是不相关,因为没有语法可以表达这种访问。此条款指的是类似 printf("%d\n", foo().x);
的内容,其中 foo()
return 是一个值结构。
代码 printf("%d %d %d %d %d %d %d %d %d %d\n, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x);
确实需要编译器实现 10 个 return 值对象,但它们都死于 ;
。
注意。你的问题包含一个固有的误解。当达到 }
时,块结束,即使还有另一次迭代。下一次迭代是一个新块,块内声明的变量在概念上被销毁并在每次迭代时重新创建。
如果你留在同一个块中,右值会发生什么变化"forever"?
假设我有以下代码:
char buff[999];
time_t timer;
while(true){
...
time(&timer);
strcpy(buff, ctime(&timer));
...
}
在每次迭代中,右值 char *
将从 ctime
中 return,但它会在迭代结束时被释放,还是仅在块完成时被释放?
如果只是在块完成时,那么在几百万次迭代之后,内存可以用完成的右值填充char*
对吗?
(我用 c
和 c++
标记了这个,因为我也想知道这两者之间是否有区别)
由于历史原因,C 库中的函数 return 不同 class 内存:
- 不需要释放的静态分配内存。该库通常在其代码中将其声明为静态数组,并将在每次函数调用时重新使用相同的内存区域。
ctime
和localtime
就是这方面的例子。 不要 释放此内存。 (可能值得一提的是,这些函数被认为已被弃用,并且由于它们不适合多线程操作而逐渐消失) - 调用者需要 释放的动态分配内存。该内存由库函数动态分配,该库函数使用
malloc()
分配该内存,将指针返回给您,并希望您在完成后free()
该内存。strdup()
将是这种形式的一个很好的例子。
您只需需要知道您正在使用的特定库调用class是什么return,以便了解您是否需要free()
那个记忆与否。请查阅相应调用的手册页。
在 ctime()
的情况下,循环中的迭代绝对无关紧要。由于库 returns 每次迭代的缓冲区地址,它被写入堆栈帧中的相同位置没有内存泄漏这样的事情。如果您在循环中调用 strdup()
,则会造成内存泄漏。
(我在这里谈论的是 C,对于 C++,这要复杂得多)
局部变量比如你的
char buff[999];
time_t timer;
...通常在输入函数时一起分配。这些变量要么在堆栈帧中分配 space(在 buff 的情况下),要么直接在硬件寄存器上分配(在定时器的情况下可能)。
所有这些分配都是在一条机器指令中一起完成的,只需将指针移动到栈顶即可。每个函数调用的每个局部变量只有一个实例,因此 没有内存填满的危险,因为您在循环中使用它们。此外,对于内存区域可以增长的大小(大约 10 兆字节),全球限制相对较低。
所有局部变量在函数退出时通过销毁栈帧自动释放。同样,这只需再次将堆栈指针移回即可完成。这与静态函数变量(它们只是具有有限可达性的全局变量)和必须显式分配或释放的动态分配(堆)变量形成对比。
堆栈帧有点太复杂,无法在此处完整介绍,但我建议您仔细阅读它们,因为了解函数调用的工作原理确实有助于全面了解 C 编程。
如果您对变量存储有任何更具体的问题,我相信您可以在这里找到有关堆栈溢出的帮助,因为我们大多数 C 程序员都喜欢谈论这类事情:)
由 ctime
编辑的指针 return 在 C 和 C++ 中都称为 value。它不是一个对象,因此它没有生命周期或存储持续时间。
你的问题就像在问:在代码for(;;) { 10 + 10; }
中,内存会被20
填满吗? (答案是:否)。
(不要与 C++ 中的 temporaries 混淆,它们是对象并且有生命周期)。
在 C 中,可以访问函数的 return 值直到当前语句结束(即在您的情况下为下一个 ;
),尽管对于标量类型来说这是不相关,因为没有语法可以表达这种访问。此条款指的是类似 printf("%d\n", foo().x);
的内容,其中 foo()
return 是一个值结构。
代码 printf("%d %d %d %d %d %d %d %d %d %d\n, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x);
确实需要编译器实现 10 个 return 值对象,但它们都死于 ;
。
注意。你的问题包含一个固有的误解。当达到 }
时,块结束,即使还有另一次迭代。下一次迭代是一个新块,块内声明的变量在概念上被销毁并在每次迭代时重新创建。