程序猿虎牙参上|这些陷阱一定要避开!,解密C语言中的指针和内存泄漏( 二 )


char*p=malloc(10);
memset(p,’0’,10);
现在 , 即使同一个代码段尝试在对p赋值前访问它 , 该代码段也能正确处理Null值(在理想情况下应具有的值) , 然后将具有正确的行为 。
内存覆盖
由于p已被分配了10个字节 , 如果某个代码片段尝试向p写入一个11字节的值 , 则该操作将在不告诉您的情况下自动从其他某个位置“吃掉”一个字节 。 让我们假设指针q表示该内存 。
原始q内容
覆盖后的q内容
结果 , 指针q将具有从未预料到的内容 。 即使您的模块编码得足够好 , 也可能由于某个共存模块执行某些内存操作而具有不正确的行为 。 下面的示例代码片段也可以说明这种场景 。
char*name=(char*)malloc(11);
//Assignsomevaluetoname
memcpy(p,name,11);//Problembeginshere
在本例中 , memcpy操作尝试将11个字节写到p , 而后者仅被分配了10个字节 。
作为良好的实践 , 每当向指针写入值时 , 都要确保对可用字节数和所写入的字节数进行交叉核对 。 一般情况下 , memcpy函数将是用于此目的的检查点 。
内存读取越界
内存读取越界(overread)是指所读取的字节数多于它们应有的字节数 。 这个问题并不太严重 , 在此就不再详述了 。 下面的代码提供了一个示例 。
char*ptr=(char*)malloc(10);charname[20];memcpy(name,ptr,20);//Problembeginshere
在本例中 , memcpy操作尝试从ptr读取20个字节 , 但是后者仅被分配了10个字节 。 这还会导致不希望的输出 。
内存泄漏
内存泄漏可能真正令人讨厌 。 下面的列表描述了一些导致内存泄漏的场景 。
重新赋值
我将使用一个示例来说明重新赋值问题 。
char*memoryArea=malloc(10);
char*newArea=malloc(10);
这向如下面的图所示的内存位置赋值 。
程序猿虎牙参上|这些陷阱一定要避开!,解密C语言中的指针和内存泄漏
文章图片
内存位置
memoryArea和newArea分别被分配了10个字节 , 它们各自的内容如图4所示 。 如果某人执行如下所示的语句(指针重新赋值)……
memoryArea=newArea;
【程序猿虎牙参上|这些陷阱一定要避开!,解密C语言中的指针和内存泄漏】则它肯定会在该模块开发的后续阶段给您带来麻烦 。
在上面的代码语句中 , 开发人员将memoryArea指针赋值给newArea指针 。 结果 , memoryArea以前所指向的内存位置变成了孤立的;
如下面的图所示 。 它无法释放 , 因为没有指向该位置的引用 。 这会导致10个字节的内存泄漏 。
程序猿虎牙参上|这些陷阱一定要避开!,解密C语言中的指针和内存泄漏
文章图片
内存泄漏
在对指针赋值前 , 请确保内存位置不会变为孤立的 。
首先释放父块
假设有一个指针memoryArea , 它指向一个10字节的内存位置 。 该内存位置的第三个字节又指向某个动态分配的10字节的内存位置 , 如图6所示 。
程序猿虎牙参上|这些陷阱一定要避开!,解密C语言中的指针和内存泄漏
文章图片
动态分配的内存
free(memoryArea)
如果通过调用free来释放了memoryArea , 则newArea指针也会因此而变得无效 。 newArea以前所指向的内存位置无法释放 , 因为已经没有指向该位置的指针 。
换句话说 , newArea所指向的内存位置变为了孤立的 , 从而导致了内存泄漏 。
每当释放结构化的元素 , 而该元素又包含指向动态分配的内存位置的指针时 , 应首先遍历子内存位置(在此例中为newArea) , 并从那里开始释放 , 然后再遍历回父节点 。
这里的正确实现应该为:
free(memoryArea->newArea);
free(memoryArea);
返回值的不正确处理