博客主页:https://blog.csdn.net/wkd_007
博客内容:嵌入式开发、Linux、C语言、C++、数据结构、音视频
本文内容:介绍
金句分享:你不能选择最好的,但最好的会来选择你——泰戈尔
本文未经允许,不得转发!!!
C语言因为有指针而变得比其他语言更灵活,也更危险,所有的指针、分配的内存都需要仔细检测,不然出现的内存相关的问题容易隐藏重大的bug,更严重的,甚至会导致程序崩溃。本文就介绍一下C语言中内存相关的一些注意点。
只定义而没有初始化的指针,就是野指针。
定义了一个指针而不初始化,那么这个指针的值可能是任何值。
看例子:
#include
void fun()
{
int *pi;
char *pc;
printf("pi=%p pc=%p\n",pi,pc);
}
int main()
{
fun();
return 0;
}
在函数fun
中定义了两个指针pi
、pc
,都没有初始化,但它们打印出来却是有值的,如下图。这就是野指针,如果直接使用这些地址,可能是程序发生一些不可预测的行为。
定义指针变量的同时最好初始化为
NULL
,用完指针之后也将指针变量的值设置为NULL
。也就是说除了在使用时,别的时间都把指针“栓”到 0 地址处。这样它就老实了。
不是所有的东西都能存进内存的,内存分为三部分:
定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存。
struct student
{
char *name;
int score;
}stu,*pstu; //定义了stu,但stu.name是一个未初始化的指针
int main()
{
strcpy(stu.name,"Jimy");
stu.score = 99;
return 0;
}
对策:对于结构体的指针成员,使用前要确保已经给它分配了内存。struct student
{
char *name;
int score;
}stu,*pstu;
int main()
{
pstu = (struct student*)malloc(sizeof(struct student*));// 只分配了一个指针大小的内存,错误
pstu->score = 99;
free(pstu);
return 0;
}
对策:给结构体指针分配内存时,注意要分配完整的结构体大小,而不是结构体指针大小。 if(NULL != p)
或 assert(NULL != p)
来判断参数的合法性。在函数里定义了变量,没初始化就使用;或者为指针malloc一段内存后,直接使用;这些没初始化的情况是存在不可知的问题的,因为没初始化的内存里可能是任何的值,有些值可能导致程序崩溃。
最常用的就是定义了结构体,直接使用,但只给部分结构体成员赋值了,最后会使用到没赋值的成员。
看例子:
#include
typedef struct stu
{
char *name;
int age;
int grade;
}st_stu;
void fun(st_stu* pstu)
{
printf("name=%s, age=%d grade=%d\n",pstu->name, pstu->age, pstu->grade);
}
void createStudent()
{
st_stu student;
student.name = "mike";
fun(&student);
}
int main()
{
createStudent();
return 0;
}
上面代码中,定义了结构体变量student
,但只给name成员赋值了,就将结构体变量传给其他函数使用,该函数会使用到三个结构体成员,这样的结果就很随机了。下面是运行结果,age成员是一个随机数。
对策:定义完变量或分配完内存一定要初始化,如果对于数组、结构体变量这样一整块的内存,可以使用memset
函数赋值。
内存分配成功,且已经初始化,但是操作越过了内存的边界。
情况1:为指针分配了内存,但是内存大小不够,导致出现越界错误。
char *p1 = “abcdefg”;
char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
strcpy(p2,p1);
p1 是字符串常量,其长度为 7 个字符,但其所占内存大小为 8 个 byte。初学者往往忘了字符串常量的结束标志“\0”。这样的话将导致 p1 字符串中最后一个空字符“\0”没有被拷贝到 p2 中。
对策:分配内存时,如果要存放字符串,要分配的内存大小为strlen(str)+sizeof(char)
。
情况2:使用数组越界
int a[10] = {0};
for (i=0; i<=10; i++)
{
a[i] = i;
}
对策:操作数组时,要注意判断下标是否越界。
会产生泄漏的内存就是堆上的内存,也就是说由malloc 系列函数或 new 操作符分配的内存。如果用完之后没有及时 free 或 delete,这块内存就无法释放,直到整个程序终止。
对策:规范地使用malloc、free。
malloc 函数分配内存成功之后, 返回这块内存的首地址。你需要一个指针来接收这个地址,但是由于函数的返回值是
void *
类型的,所以必须强制转换成你所接收的类型。也就是说,这块内存将要用来存储什么类型的数据。比如:char *p = (char *)malloc(100);
free 函数就做了一件事:斩断指针变量与这块内存的关系。但指针变量的值并没有变,只是那块内存不能再使用了,所以free之后,应该将指针变量赋值为
NULL
。
本质介绍C语言内存管理常见的一些问题,野指针、静态区、堆、栈、常见的内存错误及对策
如果文章有帮助的话,点赞、收藏⭐,支持一波,谢谢