数据管理二级 知道密码,《数据管理技术》
空指针
与MS-DOS不同,但与新版本的Windows相似,现代Linux系统将仔细处理空指针所指地址的读写,尽管实际行为取决于实现。
实验访问空指针
让我们试试当我们在memory5a.c程序中访问一个空指针时会发生什么:
#包括unistd.h
#包含stdlib.h
#包含stdio.h
int main()
{
char * some _ memory=(char *)0;
printf("从空%s/n读取",some _ memory);
sprintf(some_memory,“一次写入null/n”);
退出(EXIT _ SUCCESS);
}
其输出如下:
$ ./memory5a
从空值(null)读取
分段故障(核心转储)
操作原理
第一个printf试图打印出由空指针获得的字符串;然后,Sprintf试图向空指针写入一个字符串。在这种情况下,Linux(在GNU C库的帮助下)忽略这里的读取,简单地返回给我们一个包含(null)/0字符的神奇字符串。但是他没有忽略写操作,并且结束了程序。这对于跟踪程序错误非常有用。
如果我们再试一次,但是这次我们不使用GNU C库,我们会发现从地址0读取是不允许的。见以下记忆5b.c:
#包括unistd.h
#包含stdlib.h
#包含stdio.h
int main()
{
char z=*(const char *)0;
printf("我从位置零/n开始读取");
退出(EXIT _ SUCCESS);
}
其输出如下:
$ ./memory5b
分段故障(核心转储)
操作原理
这一次,我们尝试直接从地址0读取。但是这次我们和内核之间没有GNU libc库,只是我们的程序被终止了。我们应该注意,某些版本的UNIX允许从地址0读取,但是Linux不允许。
释放内存
直到现在,我们只是简单地分配内存,然后希望当程序结束时,我们使用的内存不会丢失。幸运的是,Linux内存管理系统有可靠的能力来确保一个程序使用的内存会在它结束时归还给系统。然而,大多数程序并不只是想简单地分配一块内存,使用一段时间,然后退出。更常见的用法是在需要时动态使用它。
使用动态内存的程序应该总是使用free调用来释放未使用的内存,从而将它返回给malloc内存管理器。这将导致单独的内存被重新合并,并使malloc库管理内存,而不是让程序管理内存。如果一个正在运行的程序(进程)使用了内存,然后释放了内存,那么释放的内存将保持分配给该进程。但是,如果不再使用它,Linux内存管理器可以将它换出物理内存并保存在交换空间中,这对资源的使用有一些小的影响。
#包含stdlib.h
void free(void *ptr_to内存);
只能使用通过malloc、calloc或realloc调用获得的内存指针来调用free调用。我们很快就会见到calloc和realloc。
免测试存储器
这里程序的名字是memory6.c:
#包含stdlib.h
#定义一个_K (1024)
int main()
{
char * some _ memory
int退出代码=退出失败;
some _ memory=(char *)malloc(ONE _ K);
如果(某_内存!=NULL) {
free(一些_内存);
退出代码=退出成功;
}
exit(exit _ code);
}
工作数量
这个程序简单的演示了如何使用前面分配的内存的指针来调用free函数。
记住一旦我们在某个内存块上调用了free函数,就不再归于这个进程了。他不再受马洛克图书馆的管理。调用free函数后,不要试图在这个内存块上读写。
的其他内存分配功能
还有两个比malloc和free更少使用的内存分配函数:calloc和realloc。其功能原型如下:
#包含stdlib.h
void * calloc(size _ t number _ of _ elements,size _ t element _ size);
void * realloc(void * existing _ memory,size _ t new _ size);
calloc分配的内存虽然可以使用free函数调用进行翻译,但是它有一些不同的参数:它为一个结构数据分配内存,需要元素的个数和每个元素的大小作为它的参数。的分配内存将被0填充,如果calloc函数调用成功,将返回指向第一个元素的指针。类似于malloc函数,后续调用并不返回连续的空间,所以简单的再次调用calloc函数,期望第二次调用返回的内存加到第一次调用的末尾,是无法扩展calloc分配的内存空间的。
Realloc改变最后分配的内存块的大小。当这个函数被调用时,它会传递一个指向malloc、calloc或realloc函数分配的内存的指针,并根据需要调整其大小。为此,Realloc可能需要能够移动数据,因此确保一旦内存被重新分配,我们必须使用新的指针,而不是试图通过使用realloc调用的前一个指针来访问内存,这一点很重要。
另一个问题是,如果realloc不能调整内存,它将返回一个空指针。这意味着在一些程序中,我们应该避免编写如下代码:
my _ ptr=malloc(BLOCK _ SIZE);
.
my_ptr=realloc(my_ptr,BLOCK _ SIZE * 10);
如果realloc函数调用失败,将返回空指针;My_ptr将指向null那么malloc分配的原始内存就不能被my_ptr访问。很可能我们需要做的就是先访问malloc分配的新内存,然后在翻译旧内存块之前,使用memcpy函数将旧内存块的数据复制到新内存块中。一旦出现错误,这可以使程序重新访问存储在原始内存块中的数据,也许是在程序被清理的时候。