hello,everyone!
承接上次的动态内存的分享,我想想还是把具体的易错点分享一下,再跟大家分享四道非常经典的笔试题,以后找工作会发现,很多题就是这四道题的原型。
话不多说开始
1. 内存泄漏
程序分配了内存但没有释放,导致内存被持续占用,最终可能导致系统内存耗尽。
原因: 忘记调用 free或 delete释放内存。
忘记释放不再使用的动态开辟的空间会造成内存泄漏。 切记: 动态开辟的空间一定要释放,并且正确释放 。
void memoryLeak() {int *ptr = (int*)malloc(sizeof(int));// 忘记释放内存
}
2. 野指针
描指针指向的内存已经被释放,但指针仍然被使用。
原因: 在释放内存后继续使用指针,或返回局部变量的指针。
int* danglingPointer() {int *ptr = (int*)malloc(sizeof(int));free(ptr);return ptr; // ptr 现在是野指针
}
3. 双重释放
对同一块内存多次调用 free 或 delete。
原因: 释放已经释放过的内存。
void doubleFree() {int *ptr = (int*)malloc(sizeof(int));free(ptr);free(ptr); // 双重释放
}
4. 内存越界
访问了分配内存之外的区域,可能导致数据损坏或程序崩溃。
原因: 数组越界、指针操作超出分配的内存范围。
void bufferOverflow() {int *ptr = (int*)malloc(5 * sizeof(int));ptr[5] = 10; // 越界访问
}
5. 无效指针解引用
解引用无效的指针(如空指针或未分配内存的指针)。
原因: 指针未正确初始化或已被释放。
void invalidDereference() {int *ptr = NULL;*ptr = 10; // 解引用空指针
}
6.忘记检查分配是否成功
未检查内存分配是否成功,可能导致后续操作出错。
原因: 假设 malloc 或 new 总是成功。
void noCheckAllocation() {int *ptr = (int*)malloc(1000000000 * sizeof(int));*ptr = 10; // 如果分配失败,ptr 为 NULL
}
好了,我们接下来就来看一下这四道题。看一下这些代码错误在哪里,运行能得到什么结果
test1
void GetMemory(char *p)
{p = (char *)malloc(100);
}
void Test(void)
{char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}
这个代码严谨一点的话有三个问题:
1.函数参数传递2.内存泄漏3.未检查内存分配是否成功。
先来看第一个GetMemory 函数的参数 p 是一个指针,但它是按值传递的。即使 p 在函数内部被修改为指向新分配的内存,调用方的 str 并不会被更新,仍然为 NULL。
因此,Test 函数中的 str 仍然是 NULL,导致 strcpy 和 printf 操作是未定义行为。GetMemory 函数中分配的内存没有被释放,导致内存泄漏。另外malloc 可能会失败并返回 NULL,但代码没有检查分配是否成功。
那怎么改呢?
利用二级指针就可以。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>void GetMemory(char **p) {*p = (char *)malloc(100);if (*p == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(1);}
}void Test(void) {char *str = NULL;GetMemory(&str); // 传递 str 的地址strcpy(str, "hello world");printf("%s\n", str);free(str); // 释放内存
}int main() {Test();return 0;
}
test2
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
这段代码的问题是返回局部变量的指针和未初始化指针。
在 GetMemory 函数中,p 是一个局部数组,它的内存位于栈上。当函数返回时,栈帧会被销毁,p 的内存不再有效。
因此,GetMemory 返回的指针指向一个无效的内存区域,导致 Test 函数中的 printf 操作会引发未定义行为(表现通常是打印乱码或程序崩溃)。
在 Test 函数中,str 被初始化为 NULL,但通过 GetMemory 赋值后,它指向了一个无效的内存地址。
这里的改变我们可以将局部变量声明为 static,使其生命周期延长到程序结束。这个后面两篇文章会讲。为什么static能延长生命周期。
这里粘贴一下,满足一下大家的好奇心。
#include <stdio.h>char* GetMemory(void) {static char p[] = "hello world"; return p;
}void Test(void) {char *str = NULL;str = GetMemory(); printf("%s\n", str);
}int main() {Test();return 0;
}
好了,感谢阅读,剩下的我们下一篇文章讲,希望大家好好理解这两道题。