C语言中关于结构体指针的内存分配问题
话不多说先上一段代码
typedef struct stu
{
char filename[100];
char *name;
}stu;
int main()
{
stu *st;
strcpy(st->filename,"dsssssddd");
strcpy(st->name,st->filename);
printf("%s\n%s",st->name,st->filename);
return 0;
}
熟悉的小伙伴一眼应该就可以看出哪里出错了,对就是我们常说的结构体指针的内存分配的问题,既然分配出错我们对其分配内存就好了,于是有了以下代码。
typedef struct stu
{
char filename[100];
char *name;
}stu;
int main()
{
stu *st;
st=(stu *)malloc(sizeof(stu));
strcpy(st->filename,"dsssssddd");
strcpy(st->name,st->filename);
printf("%s\n%s",st->name,st->filename);
free(st);
return 0;
}
这样是不是就没问题,所以我们将代码运行一番。
run: line 1: 3 Segmentation fault (core dumped) ./a.out
Exited with error status 139
想法是对的,但结果却出现的偏差,问题就出在我们结构体中的指针类型也需要分配空间,当然除非你的指针指向文字常量区,但那样就属于把char *给初始化了。也就是我们无法对其进行修改了。
st->name="8554"; //OK
strcpy(st->name,"9999"); //error
就会再次发生上面同样的错误
说了这么久的常见错误,是时候写一下正确的示范了
typedef struct stu
{
char filename[100];
char *name;
}stu;
int main()
{
stu *st;
st=(stu *)malloc(sizeof(stu));
st->name=(char*)malloc(sizeof(char)*20);
strcpy(st->filename,"77777");
strcpy(st->name,"fffff");
printf("%s\n%s\n",st->name,st->filename);
strcpy(st->name,st->filename);
printf("%s\n%s\n",st->name,st->filename);
free(st->name);
free(st);
return 0;
}
来让我们看一下运行结果
fffff
77777
77777
77777
我们不仅需要对结构体指针分配空间,还需要对结构体内部的指针分配空间;
为此我们在做一个小实验,我们对name分配空间之后,是否还可以进行初始化操作,又是否需要free掉开辟的堆空间
stu *st;
st=(stu *)malloc(sizeof(stu));
st->name=(char*)malloc(sizeof(char)*20);
strcpy(st->filename,"77777");
strcpy(st->name,"fffff");
printf("%s\n%s\n",st->name,st->filename);
st->name="66666";
printf("%s\n%s\n",st->name,st->filename);
free(st->name);
free(st);
将上面的代码运行后,将会出现
**free(): invalid pointer **这个错误,说明我们free了一个无效的指针
但是我们把free(st->name)删除之后,我们重新运行结果却又正确
结论: 我们malloc是把数据存储在堆空间中需要进行手动的释放,但是我们把name初始化是将数据放在了文字常量区,它是跟随程序结束后自动释放的,当我们对char 进行初始化指向了文字常量,那么我们就不可以在对其进行修改的操作,相当于const char name =“66666”;不能在对其进行修改。
stu *st;
st=(stu *)malloc(sizeof(stu));
st->name=(char*)malloc(sizeof(char)*20);
strcpy(st->filename,"77777");
strcpy(st->name,"fffff");
printf("%s\n%s\n",st->name,st->filename);
free(st->name);//释放掉name
st->name="66666";//重新初始化
printf("%s\n%s\n",st->name,st->filename);
free(st);
那么我们在重新初始化需要将我们开辟的堆空间先释放掉,避免我们开启的堆空间没有了主人,导致内存泄漏。这很重要,养成好习惯!