C动态分配内存

在C中动态分配内存的基本步骤有:

  1. malloc类的函数分配内存;
  2. 用这些内存支持应用程序;
  3. free函数释放内存。

这个方法在具体操作上可能存在一些小变化,不过这里列出的是最常见的。在下例中,我们用malloc函数为整数分配内存。指针将分配的内存赋值为5,然后内存被free函数释放。

int *pi = (int*) malloc(sizeof(int));
*pi = 5;
printf("*pi: %d\n", *pi);
free(pi);

当这段代码执行时会打印数字5。图2-1说明了在free函数执行之前内存如何分配。为方便在本章说明问题,除非特别指出,我们假定示例代码出现在main函数中。

enter image description here

图2-1:整数的内存分配

malloc函数的参数指定要分配的字节数。如果成功,它会返回从堆上分配的内存的指针。如果失败则会返回空指针。测试所分配内存的指针是否有效在C malloc函数中讨论。sizeof操作符使应用程序更容易移植,还能确定在宿主系统中应该分配的正确的字节数。

在本例中,我们试图为整数分配足够多的内存。假定长度是4,我们可以这么写:

int *pi = (int*) malloc(4);

然而,依赖于系统所用的内存模型,整数的长度可能会发生变化。可移植的方法是使用sizeof操作符,这样不管程序在哪里运行都会返回正确的长度。

注意 涉及解引操作的常见错误见下面的代码:

int *pi;
*pi = (int*) malloc(sizeof(int));

问题出在赋值符号的左边。我们在解引指针,这样会把malloc函数返回的地址赋给pi中存放的地址所在的内存单元。如果这是第一次对指针进行赋值操作,那指针所包含的地址可能无效。正确的方法如下所示:

pi = (int*) malloc(sizeof(int));

这种情况下不应该用解引操作符。

稍后也会深入讨论free函数,它和malloc协同工作,不再需要内存时将其释放。

注意 每次调用malloc(或类似函数),程序结束时必须有对应的free函数调用,以防止内存泄漏。

一旦内存被释放,就不应该再访问它了。通常我们不会在释放内存后有意去访问,不过,就像迷途指针中所说的,这也有可能意外发生。在这种情况下系统的行为将依赖于实现。通常的做法是总是把被释放的指针赋值为NULLfree函数会讨论这一点。

分配内存时,堆管理器维护的数据结构中会保存额外的信息。这些信息包括块大小和其他一些东西,通常放在紧挨着分配块的位置。如果应用程序的写入操作超出了这块内存,数据结构可能会被破坏。这可能会造成程序奇怪的行为或者堆损坏,指针的使用问题会演示相关示例。

考虑如下代码段,我们为字符串分配内存,让它可以存放最多5个字符外加结尾的NUL字符。for循环在每个位置写入0,但是没有在写入6字节后停止。for语句的结束条件是写入8字节。写入的0是二进制0而不是ASCII字符0的值。

char *pc = (char*) malloc(6);
for(int i=0; i<8; i++) {
    pc[i] = 0;
}

在图2-2中,6字节的字符串后面还分配了额外的内存,这是堆管理器用来记录内存分配的。如果我们越过字符串的结尾边界写入,额外的内存中的数据会损坏。在本例中,额外的内存跟在字符串后面。不过,实际的位置和原始信息取决于编译器。

enter image description here

图2-2:堆管理器用到的额外内存

赞(2)

评论 抢沙发

评论前必须登录!

 

C指针