简介:在使用C语言时,您是否对花时间调试指针和内存泄漏问题感到厌倦?如果是这样,那么本文就适合您。您将了解可能导致内存破坏的指针操作类型,您还将研究一些场景,了解要在使用动态内存分配时考虑什么问题。
引言
对于任何使用C语言的人,如果问他们C语言最大烦恼是什么,其中许多人可能会回答说是 指针和内存泄漏。这些的确消耗了开发人员大多数调试时间的事项。指针和内存泄漏对于某些开发人员来说似乎令人畏惧,但是一旦您了解了指针及其关联内存操作的基础,他们就是您在C语言中拥有的最强大的工具。
本文将与您分享开发人员在开始使用指针来编程前应该知道的秘密。本文内容包括:
1、导致内存破坏的指针操作类型
2、在使用动态内存分配时必须考虑的检查点
3、导致内存泄漏的场景
如果您预先知道什么地方可能出错,那么您就能够小心避免陷阱,并消除大多数与指针和内存相关的问题。
什么地方可能出错?
有几种问题场景可能会出现,从而可能在完成生成后导致问题。在处理指针时,您可以使用本文中的信息来避免许多问题。
未初始化的内存
在本例中,p已经被分配了10个字节。这10个i皆可能包含垃圾数据,如图1所示。
char *p = malloc ( 10 ); |
char *p = malloc (10);
memset(p,’\0’,10); |
char *name = (char *) malloc(11);
// Assign some value to name
memcpy ( p,name,11); // Problem begins here
char *ptr = (char *)malloc(10);
char name[20] ;
memcpy ( name,ptr,20); // Problem begins here
char *memoryArea = malloc(10);
char *newArea = malloc(10);
memoryArea = newArea; |
free(memoryArea) |
如果通过调用 free 来释放了 memoryArea
,则 newArea
指针也会因此而变得无效。newArea
以前所指向的内存位置无法释放,因为已经没有指向该位置的指针。换句话说,newArea
所指向的内存位置变为了孤立的,从而导致了内存泄漏。
每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,应首先遍历子内存位置(在此例中为newArea
),并从那里开始释放,然后再遍历回父节点。
这里的正确实现应该为:
free( memoryArea->newArea);
free(memoryArea); |
有时,某些函数会返回对动态分配的内存的引用。跟踪该内存位置并正确地处理它就成为了 calling
函数的职责。
char *func ( )
{
return malloc(20); // make sure to memset this location to ‘\0’…
}
void callingFunc ( )
{
func ( ); // Problem lies here
} |
在上面的示例中,callingFunc()
函数中对 func()
函数的调用未处理该内存位置的返回地址。结果,func()
函数所分配的 20 个字节的块就丢失了,并导致了内存泄漏。
在开发组件时,可能存在大量的动态内存分配。您可能会忘了跟踪所有指针(指向这些内存位置),并且某些内存段没有释放,还保持分配给该程序。
始终要跟踪所有内存分配,并在任何适当的时候释放它们。事实上,可以开发某种机制来跟踪这些分配,比如在链表节点本身中保留一个计数器(但您还必须考虑该机制的额外开销)。
memset
和 malloc,或始终使用 calloc
。
malloc
都要有一个对应的 free。