C/C++指针与内存的常见错误踩坑
- 一、常见错误
-
- 1、野指针
- 2、内存泄漏
- 3、缓冲区溢出
- 4、空指针解引用
- 5、双重释放
- 6、指针类型不匹配
- 7、忘记初始化指针
- 8、指针没有指向一块合法的内存
- 9、没有为结构体指针分配足够的内存
- 10、为指针分配的内存太小
- 11、内存越界
- 二、代码示例

一、常见错误
1、野指针
- 原因:指针在内存被释放后继续使用,导致指向无效地址。
- 后果:程序行为未定义,可能崩溃或数据损坏。
- 示例代码:#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
*ptr = 10;
free(ptr); // 内存释放
*ptr = 20; // 错误:ptr现在指向无效内存(野指针)
return 0;
} - 避免方法:在释放内存后将指针设为NULL,并在使用前检查指针有效性。
2、内存泄漏
- 原因:动态分配的内存未被释放,导致程序占用内存持续增长。
- 后果:长期运行的程序可能耗尽系统内存。
- 示例代码:#include <stdlib.h>
void leak_example() {
int *ptr = (int *)malloc(sizeof(int));
*ptr = 5;
// 忘记释放ptr,内存泄漏
}
int main() {
leak_example();
return 0;
} - 避免方法:确保每个malloc或new都有对应的free或delete。在C++中,使用智能指针(如std::unique_ptr)自动管理内存。
3、缓冲区溢出
- 原因:访问数组或缓冲区时超出其分配边界。
- 后果:可能覆盖相邻内存,导致数据损坏、安全漏洞(如栈溢出攻击)。
- 示例代码:#include <string.h>
int main() {
char buffer[5];
strcpy(buffer, "HelloWorld"); // 错误:写入超出buffer大小
return 0;
} - 避免方法:使用安全函数如strncpy代替strcpy,并检查数组索引范围。
4、空指针解引用
- 原因:尝试访问或修改空指针(NULL或nullptr)指向的内容。
- 后果:程序通常崩溃(segmentation fault)。
- 示例代码:int main() {
int *ptr = NULL;
*ptr = 10; // 错误:解引用空指针
return 0;
} - 避免方法:在使用指针前检查是否为NULL,并确保初始化指针。
5、双重释放
- 原因:同一内存块被释放多次。
- 后果:内存管理数据结构损坏,可能导致程序崩溃。
- 示例代码:#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
free(ptr);
free(ptr); // 错误:双重释放
return 0;
} - 避免方法:释放内存后将指针设为NULL,避免重复释放。
6、指针类型不匹配
- 原因:指针类型与指向的数据类型不一致,如将int*强制转换为char*后错误访问。
- 后果:数据解释错误或对齐问题。
- 示例代码:int main() {
int num = 10;
char *cptr = (char *)# // 强制转换
*cptr = 'A'; // 可能只修改部分字节,导致未定义行为
return 0;
} - 避免方法:避免不必要的指针类型转换,使用正确的类型。
7、忘记初始化指针
- 原因:指针未初始化就使用,可能指向随机地址。
- 后果:未定义行为,可能崩溃或安全风险。
- 示例代码:int main() {
int *ptr; // 未初始化
*ptr = 5; // 错误:指向无效地址
return 0;
} - 避免方法:始终初始化指针为NULL或有效地址。
8、指针没有指向一块合法的内存
-
原因:定义了指针变量,但是没有为指针分配内存
-
后果:未定义行为,可能崩溃或安全风险。
-
示例代码:
struct student
{
char *name;
int score;
}stu,*pstu;int main()
{
strcpy(stu.name,'Jimy');
stu.score = 99;
return 0;
} -
避免方法:记得使用malloc分配内存。
9、没有为结构体指针分配足够的内存
-
原因:为结构体分配了内存,但是没有给结构体内部成员指针分配内存
-
后果:可能崩溃或安全风险。
-
示例代码:
struct student
{
char *name;
int score;
}stu,*pstu;
int main()
{
pstu = (struct student*)malloc(sizeof(struct student*));
strcpy(pstu->name,'Jimy');
pstu->score = 99;
free(pstu);
return 0;
} -
避免方法:记得只要是指针都需要使用malloc分配内存。
10、为指针分配的内存太小
-
原因:字符串后面有个结束符没有计算入大小。
-
后果:可能崩溃或安全风险。
-
示例代码:
int main()
{
char *p1 = “abcdefg”;
char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
strcpy(p2,p1);
return 0;
} -
避免方法:字符串结尾有结束符\\0所以strlen后的长度要加1。
11、内存越界
-
原因:内存分配成功,且已经初始化,但是操作越过了内存的边界。
-
后果:可能崩溃或安全风险。
-
示例代码:
int main()
{
int a[10] = {0};
for(uint8_t i=0;i<=10;i++)
{
a[i] = i;
}
return 0;
} -
避免方法:for 循环的循环变量一定要使用半开半闭的区间,而且如果不是特殊情况,循环变量尽量从0 开始。
二、代码示例
错误代码
#include <stdlib.h>
void createArray() {
int *arr = (int *)malloc(5 * sizeof(int)); // 分配内存给一个包含5个整数的数组
if (arr == NULL) {
// 处理分配失败
return;
}
for (int i = 0; i < 5; i++) {
arr[i] = i; // 初始化数组
}
// 函数结束,但没有释放 arr 指向的内存
// free(arr); // 缺少这行,导致内存泄漏
}
int main() {
createArray(); // 调用函数
return 0;
}
错误分析
- 错误原因:在 createArray 函数中,使用 malloc 分配了内存,但在函数返回前没有调用 free(arr) 来释放内存。每次调用该函数时,都会分配新的内存块,但程序无法再访问这些内存(因为没有指针指向它),导致内存泄漏。
- 后果:如果程序多次调用 createArray,内存使用量会持续增加,最终可能导致系统内存不足、程序变慢或崩溃。
- 常见场景:内存泄漏在长期运行的程序(如服务器或GUI应用)中尤其危险,也容易在循环或递归中发生。
修复方法 要修复内存泄漏,必须在不再需要内存时显式释放它。以下是修复后的代码:
#include <stdlib.h>
void createArray() {
int *arr = (int *)malloc(5 * sizeof(int));
if (arr == NULL) {
return;
}
for (int i = 0; i < 5; i++) {
arr[i] = i;
}
// 使用完毕后释放内存
free(arr); // 添加释放操作
}
int main() {
createArray();
return 0;
}
修复说明 添加 free(arr) 确保在函数退出前释放内存。在C++中,可以使用智能指针(如 std::unique_ptr)自动管理内存,避免手动释放。



