您的位置 首页 基础

结构体中动态内存的办理(malloc和free)

C语言中内存的管理主要是依据malloc和free实现的,其中malloc主要是实现内存的分配,而free则是实现内存的释放。虽然这是我们已经很熟悉的

C言语中内存的办理首要是依据malloc和free完结的,其间malloc首要是完结内存的分配,而free则是完结内存的开释。尽管这是咱们现已很熟悉的,可是仍是存在一些问题。特别是当结构体中存在指针的情况下,各种问题也就会议现出来。

其间最大的问题是:结构体中指针变量没有指向一块合法的内存空间,就对指针参数进行操作,这也是许多C言语程序员经常犯的过错。
简略的实例如下:
struct student
{
char *name;
int score;
}stu,*pstu;
int main()
{
strcpy(stu.name,”Jimy”);
stu.score = 99;
strcpy(pstu->name,”Jimy”);
pstu->score = 99;
}
这种代码是新手经常犯的过错,其间的首要过错是指针变量没有指向一块内存空间,其间包含ptest没有指向一块内存空间,一起结构体中的指针变量name也没有指向一块内存空间。
这种代码一般都会编译经过,可是运转进程中会发生新手编程经常呈现的段过错Segmentation fault (core dumped),我经过gdb对程序进行调试发现了存在的一些问题。其间stu.name中的内容是0x0,也便是地址0x0。这样我就知道了0x0为什么会发生段过错了,因为在Linux中进程都有一个独立的虚拟存储空间4G,可是其间在最底部的0x0是没有映射的,详细的参看进程的存储器映射联系。0x0并没有映射,这样发生段过错也就不奇怪了。
也便是说指针变量里存储的地址值并不是一个咱们需求的值,为了指向一块内存空间,因而需求选用malloc分配一块内存空间。
改写上面的代码完结内存的分配。
int main()
{
/*创立一块内存空间,并让stu.name指向这块内存空间*/
stu.name = (char *)malloc(20*sizeof(char));
/*完结字符串的仿制进程*/
strcpy(stu.name,”Jimy”);
stu.score = 99;
/*创立一块内存空间,并让pstu指向这块内存空间*/
pstu = (struct student *)malloc(sizeof(struct student));
/*创立一块内存空间,并让pstu->name指向这块内存空间*/
pstu->name = (char *)malloc(20*sizeof(char));
/*完结字符串的仿制进程*/
strcpy(pstu->name,”Jimy”);
pstu->score = 99;
return 0;
}
这样弥补今后的代码就为指针变量添加了指向的目标,由所以选用malloc动态请求的存储空间,那么这段存储空间是分配在堆中,而不是在栈中,假如是在被调用函数中请求内存空间,那么在函数回来后该内存空间并不会开释。
Breakpoint 1, main () at TestStructPoint.c:21
21 stu.name = (char *)malloc(20*sizeof(char));
Missing separate debuginfos, use: debuginfo-install glibc-2.12.90-17.i686
(gdb) p stu —-stu中的内容
$1 = {name = 0x0, score = 0}
(gdb) p stu.name —-stu.name其间的内容是0x0,也便是指向0x0
$2 = 0x0
(gdb) c
Continuing.
Breakpoint 2, main () at TestStructPoint.c:25
25 strcpy(stu.name,”Jimy”);
(gdb) p stu.name —–stu.name其间的内容不再是0x0,而是一个地址值,该地值中的内容为空
$3 = 0x804a008 “”
(gdb) c
Continuing.
Breakpoint 3, main () at TestStructPoint.c:26
26 stu.score = 99;
(gdb) p stu.name —–stu.name中存储的地址的内容发生了改动。
$4 = 0x804a008 “Jimy”
(gdb) c
Continuing.
Breakpoint 4, main () at TestStructPoint.c:29
29 pstu = (struct student *)malloc(sizeof(struct student));
(gdb) p pstu —-pstu指向的地址也是0x0
$5 = (struct student *) 0x0
(gdb) c
Continuing.
Breakpoint 5, main () at TestStructPoint.c:32
32 pstu->name = (char *)malloc(20*sizeof(char));
(gdb) p pstu —-pstu指向的内存地址发生了改动,不再是0x0
$6 = (struct student *) 0x804a020
(gdb) c
Continuing.
Breakpoint 6, main () at TestStructPoint.c:35
35 strcpy(pstu->name,”Jimy”);
(gdb) p pstu
$7 = (struct student *) 0x804a020
(gdb) p pstu->name —-pstu->name中的地址也不再是0x0,而是一个非零的地址值
$8 = 0x804a030 “”
(gdb) c
Continuing.
Breakpoint 7, main () at TestStructPoint.c:36
36 pstu->score = 99;
(gdb) p pstu->name
$9 = 0x804a030 “Jimy” —-pstu->name指向地址中的内容发生改动
(gdb) c
Continuing.
Program exited normally.
依据上面的调试能够知道,指针变量在界说进程中没有初始化为NULL,则指针变量指向的地址便是0x0,而在Linux中的进程虚拟存储器映射中地址0x0并没有映射,因而会呈现过错。因而结构体中的指针变量一定要指向一块详细的存储空间之后才干进行相应的操作。一起其他的指针也有必要指向相应的地址今后再操作。
可是分配完地址后还需求在相应操作完毕后开释分配的存储器,否则会形成糟蹋,以及内存的走漏。这也是许多程序员忘掉完结的作业。
内存的开释选用free函数即可,free函数是将分配的这块内存与指针(malloc回来的指针)之间的一切联系切断,指针变量P中存储的地址(这块内存的开始地址)值也没有发生改动,一起存储器中存储的内容也并没有发生改动,改动的仅仅指针对这块内存地址的一切权问题。可是该开始地址地点内存中的数据内容现已无法使用了,即时选用其他的指针也不能拜访。假如下一次调用malloc函数或许会在方才开释的区域创立一个内存空间,因为开释今后的存储空间的内容并没有改动(我是参阅书上的,但我以为free后存储器中的内容是发生改动的,后边的调试能够阐明这个问题,仅仅不知道发生什么改动,我也仅仅猜想,可是不要拜访这个存储空间的内容是最安全的),这样或许会影响后边的成果,因而需求对创立的内存空间进行清零操作(防止前面的操作影响后边),这一般选用memset函数完结,详细参看memset函数。还有指针变量P中存储的地址值并没有改动,因为指针P没有对这个地址的拜访权限,程序中对P的引证都或许导致过错的发生,形成野指针,因而最终还需求将指针P指向NULL,防止野指针的发生。当然也需求对创立是否成功需求检测,但这儿我暂时不考虑这些过错的处理。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/jichu/317792.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部