9

我读过很多程序员在用 C/C++ 编程时说和写作,有很多与内存相关的问题。我打算学习用 C/C++ 编程。我有 C/C++ 的初学者知识,我想看一些简短的示例,为什么 C/C++ 会出现内存管理问题。请提供一些样品。

4

9 回答 9

17

在 C 或 C++ 中有很多方法可以破坏或泄漏内存。这些错误是最难诊断的,因为它们通常不容易重现。

例如,很容易无法释放已分配的内存。例如,这将执行“双重释放”,尝试释放a两次但未能释放b

char *a = malloc(128*sizeof(char));
char *b = malloc(128*sizeof(char));
b = a;
free(a);
free(b); // will not free the pointer to the original allocated memory.

下面是一个示例缓冲区溢出,它会破坏任意内存。这是缓冲区溢出,因为您不知道多长时间str。如果它长于 256 个字节,那么它会将这些字节写入内存中的某个位置,可能会覆盖您的代码,也可能不会。

void somefunc(char *str) {
    char buff[256];
    strcpy(buff, str);
}
于 2010-06-05T06:32:42.560 回答
7

基本上,在这些语言中,您必须手动请求不是在编译时已知的局部变量的每一位内存,并且您必须在不再需要它时手动释放它。这些库(所谓的智能指针)可以在一定程度上自动化这个过程,但它们并不适用于任何地方。此外,对于如何(尝试)通过指针算法访问内存绝对没有限制。

手动内存管理可能会导致许多错误:

  • 如果你忘记释放一些内存,你就有内存泄漏
  • 如果您使用的内存比给定指针的请求多,则缓冲区溢出。
  • 如果您释放内存并继续使用“悬空指针”指向它,您将有未定义的行为(通常是程序崩溃)
  • 如果您错误计算指针算法,则会出现崩溃或数据损坏

而且其中许多问题都很难诊断和调试。

于 2010-06-05T06:31:39.583 回答
5

我打算学习用 C/C++ 编程

你到底是什么意思?你想学习用 C 编程,还是想学习用 C++ 编程?我不建议同时学习两种语言。

从用户的角度来看,C++ 中的内存管理比 C 中的要容易得多,因为其中大部分是由类封装的,例如std::vector<T>. 从概念的角度来看,C 的内存管理可以说要简单得多。基本上,只有mallocfree:)

于 2010-06-05T07:00:06.843 回答
5

老实说,在使用 C++ 编程时,我对内存分配没有任何“问题”。我上一次发生内存泄漏是在 10 多年前,那是由于我的盲目愚蠢。如果您使用 RAII、标准库容器和一点常识编写代码,那么问题确实不存在。

于 2010-06-05T08:14:35.253 回答
4

C 和 C++ 中常见的内存管理问题之一与缺乏对数组的边界检查有关。与 Java(例如)不同,C 和 C++ 不检查以确保数组索引落入实际数组范围内。因此,很容易意外覆盖内存。例如(C++):

char *a = new char[10];
a[12] = 'x';

不会有与上述代码相关的编译或运行时错误,只是您的代码会覆盖不应该出现的内存。

于 2010-06-05T06:25:18.223 回答
3

这在 C/C++ 中通常被称为不同之处的原因是许多现代语言执行内存管理和垃圾收集。在 C/C++ 中,情况并非如此(无论好坏)。您需要手动分配和取消分配内存,如果不正确执行此操作会导致内存泄漏,这在为您执行内存管理的语言中是不可能的。

于 2010-06-05T06:21:37.770 回答
2

很明显,您必须释放不再使用或将来不再使用的内存,但是您必须在程序开始时确定内存需求是静态的还是执行时变化的。如果它是动态的,那么您的程序工作需要足够的内存,那么您的程序可能会消耗额外的内存。

因此,您必须释放未使用的内存并在需要时创建该时间。就像

struct student
{
 char name[20];
 int roll;
 float marks;
}s[100];

在这里,我假设班上有 100 名学生。学生可能超过 100 或少于 100。如果超过 100 则您的程序将丢失信息或少于 100 则程序将运行但浪费内存,它可能很大。

所以我们通常是在执行的时候动态创建一条记录。就像

struct student *s;

s=(struct student *)malloc(sizeof(struct student));

scanf("%s %d %f",s->name,s->roll,s->marks);

如果不使用,则将其从内存空间中删除。

free(s);

这是编程的好方法,如果你不从内存中删除,那么它可能会一次填满你的内存堆栈并且它可能会挂起。

于 2010-06-09T03:42:37.660 回答
2

当 new 用于获得一块内存时,操作系统保留的大小可能大于您的请求,但绝不会小于您的请求。由于这一点以及 delete 不会立即将内存返回给操作系统的事实,当您检查程序正在使用的整个内存时,您可能会认为您的应用程序存在严重的内存泄漏。因此,检查整个程序正在使用的字节数不应用作检测内存错误的方法。只有当内存管理器指示使用的内存大量且持续增长时,您才应该怀疑内存泄漏。

于 2010-06-05T07:25:14.373 回答
1

到目前为止没有提到的一件事是性能以及为什么要手动管理内存。很难准确地管理内存,尤其是当程序变得更加复杂时(尤其是当您使用线程以及内存块的生命周期变得复杂时(即当它变得难以准确判断何时不需要一块内存时)信息))即使使用强大的现代编程工具,如 valgrind。

那么为什么要手动管理内存,有几个原因:--要了解它是如何工作的/要--要实现垃圾收集/自动内存管理,您需要手动--使用一些较低级别的东西,例如您需要的内核内存的手动控制可以提供的灵活性。--最重要的是,如果您正确地进行手动内存管理,您可以获得很大的加速/更低的内存开销(更好的性能),这是与垃圾收集相关的问题(尽管它会随着更好的垃圾收集器(例如热点 jvm 的编写)而变得更好)是你不能控制内存管理,所以很难用实时的东西做东西(保证某些目标的最后期限,比如汽车刹车和起搏器,

许多“现代 C++”(据说 C++ 可以被认为是多种语言,具体取决于您如何使用它)而不是带有类的 c(或 x 和 y C++ 特性)通过经常使用简单的可选来使用折衷方案gc/自动内存管理(请注意,可选的 gc 在内存管理方面可能比强制的更糟糕,因为当它强制时它是一个更简单的系统)功能和一些手动内存管理。根据您的操作方式,使用 gc 和进行手动内存管理可能有一些优点和缺点。一些 C 库也提供可选的 GC,但它在 c 和 c++ 中不太常见。

于 2010-06-05T10:46:58.087 回答