关于C语言的结构体指针内存释放,有没有办法能够释放单个结构体指针内存释放的空间?

C语言中结构体struct编写的一些要点解析
转载 &更新时间:日 10:56:05 & 作者:whuslei
这篇文章主要介绍了C语言中结构体struct编写的一些要点解析,谈到了结构体的声明和指针指向等重要知识点,需要的朋友可以参考下
一、关于结构体的声明
1、匿名声明。如:
这段代码的含义是,声明一个无名(anonymous)的结构体,并创建了一个结构体变量point。如果这段声明是放在全局域(在任意函数(比如main函数)外)内,那么point内的变量将被初始化为默认值,换句话说,以这种方式声明结构体变量时就已经为它分配了内存空间。
适用于该结构体只需要产生一个变量!本例中,该匿名结构体将有且仅有point这个结构体变量!
不同的匿名结构体变量,类型是不同的!如
如果将 p1=p2 ,则ok;如果将 p1=p3 ,则编译器提示"incompatible types when assigning to type ‘struct &anonymous&' from type ‘struct &anonymous&'",两者的实际类型是不一样的。
2、显式声明一个结构体
struct node{
声明了一个结构体 struct node,如果需要声明一个它的对象,则可以这样:struct node n1;
可以声明多个该结构体的变量。
区别"C中的结构体变量" 和 "Java中的类对象"。C中,"struct node n1;"创建了一个结构体变量,并为它分配了内存空间,不一定初始化!得看这个变量是否在全局域;而Java中,"Node n1;"只是声明了一个类对象,也就是说是一个"空引用",可以想象成C中的空指针,当"n1 = new Node();"时,n1才指向了该对象的内存空间。因此,在Java中,可以通过"n1==null"来判断对象是否为空;在C中,不能通过"n1==NULL"来判断,因为"n1"并不是一个指针,而是一个类型变量的名字,就像""这种,显然"a"不是指针!
3、用typedef来简化结构体的写法
typedefstruct {
相当于把代码改名为Node了。以前需要这样声明"struct node n1;",现在只需要"Node n1;"。
这段代码中,如果没有typedef,代码的意思是"声明了一个匿名结构体变量"!注意区别。
4、在结构体中声明结构体变量。
typedef struct {
这段代码是错误的!
错误1:直接在结构体中声明另外一个结构体,会出现死循环,如A包括B,B又包括A,A又包括B……使得编译器无法知道结构体的空间大小,因此,无法通过编译!
错误2:typedef还没有将结构体命名为Node,你就在结构体中使用了Node,显然,编译器此时还不知到Node是什么!所以,无法通过编译!
正确的使用方法如下:
typedef struct node{
struct node *n1;
二、关于结构体的赋值
1、声明一个变量后的默认值
typedef struct {
char ch[256];
//声明一个变量,此时已为之分配了空间!
如前面提到的,如果这个变量声明是在全局,则"str.p等于NULL,str.i等于0,str.ch数组都是'\0'",为默认初始值;如果不在全局,则所有值都是"野值"。
2、手动初始化
mystr str2={"abc",2,"def"};
mystr str3={.p="abc",.ch="def"};
mystr str4={.ch[256]="def"};//error!
mystr str5={.ch[10]="def"};//right!
此时,str2声明时手动赋了初值。str2.p和str2.ch赋值时的行为是不一样的!str2.p是一个字符指针,也就是将p指向常量字符串"abc"在内存中的地址;而str2.ch是一个常量字符指针(无法操作指针),代表的是字符数组,也就是将常量字符串"def"逐字符copy到ch数组里,赋值结束后,ch的值是:'d','e','f','\0','\0'……
也可以像str3这样初始化结构体中的某些变量,值得注意的是str4和str5。对于数组(如 char a[size])来说,传递给常量字符指针,可以是"a",可以是"a[n]"(0&=n&size,编译器会忽略掉n),不能是"a[size]"(编译器会检测,报"array index in initializer exceeds array bounds")。
mystr str6;
str6.p = "abc";
mystr * pstr = & str6;//得到这个结构体变量的指针
pstr-&p = "abc";
4、动态生成结构体变量
mystr * pstr = (mystr*)malloc(sizeof(mystr));
pstr-&p = "abc";
注意,如果是动态生成的结构体变量(用到了malloc),则必须在丢弃该变量前将他的内存空间释放掉(用free)。
如果结构体内部也存在动态生成的对象,在释放结构体之前要先释放掉其内部的内存空间,如下
pstr-&p = (char*)malloc(sizeof(char)*256);
free(pstr-&p);
free(pstr);
三、结构体数组
我们知道基本数据类型的变量数组直接定义就可以分配空间了,结构体可以看作一种新类型,它也是定义声明变量之后就会自动分配空间的,结构体的数组也是这样。
struct book library[10];
这样就定义了一个有10个book变量的数组,并且已经分配了存储空间。 结构体的数组和普通数组索引方式是一样的。
结构体数组也可以使用字面量初始化方法,如下
struct book lib[2] = {
{"apue", "stevens", 128.0},
{"cpp", "prata", 60.0}
是不是很方便了。要注意最外面的是 { ,不是 [ 哦。 对于成员是一个结构的结构体变量,同样可以使用字面量初始化,记住,只是初始化,不能用于对结构体变量的赋值哦。
四、指向结构的指针
指向结构体的指针是一个一直都没有掌握好的点,希望这里能记录好一点,加强理解。
对于指针有几个好处,第一:就像指向数组的指针比数组本身更容易操作一样,指向结构的指针通常也更容易操作; 第二:在早期的C中参数传递只能使用结构的指针;第三:很多奇妙的数据表示都是用了包含指向其他结构的指针的结构。
和数组不同,结构的名字不是该结构的地址(即单独的结构名并不是该结构地址的同义词),必须使用 & 运算符。声明一个指针的方式与一个普通变量没有什么区别:
struct book *
struct book c = {
"c primer plus",
假设 lib 是一个 struct book 的数组,现在用结构指针 cpp 指向 lib[0],那么根据指针的运算规则, cpp+1 会指向 lib[1]。虽然在一般的认识里面,结构体中的元素在存储器中是一次排列的,所以可以根据各个元素的大小来计算 cpp+1 与 cpp 之间的地址差多少。但是考虑到系统对存储器的对齐要求,不同的系统对齐的方式可能不一样,所以使用各个成员大小相加的方式计算结构的存储大小是不合适的。
五、访问结构的成员
这个比较简单,注意结构和指向机构的指针访问成员的方式不一样,结构本身使用 .运算符访问,而指向结构的指针则使用 -& 访问。
strcut book cpp, *
title = cpp.
// title = pcpp-&
// title = (*pcpp). // 因为 . 的优先级比 * 高,必须要有括号
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具漫谈c语言结构体
单片机&嵌入式
单片机应用
嵌入式操作系统
学习工具&教程
学习和开发单片机的必备工具
(有问必答)
(带你轻松入门)
电子元件&电路模块
当前位置: >>
>> 浏览文章
漫谈c语言结构体
&相信大家对于结构体都不陌生。在此,分享出本人对语言结构体的研究和学习的总结。如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了。当然,水平有限,若发现不足之处恳请指出。代码文件我放在下面。
在此,我会围绕以下个问题来分析和应用语言结构体:
1.&C语言中的结构体有何作用
2.&结构体成员变量内存对齐有何讲究重点
对于一些概念的说明,我就不把语言教材上的定义搬上来。我们坐下来慢慢聊吧。
==============================================================================================================================================
1.&结构体有何作用
三个月前,教研室里一个学长在华为南京研究院的面试中就遇到这个问题。当然,这只是面试中最基础的问题。如果问你你怎么回答?
我的理解是这样的,语言中结构体至少有以下三个作用:
(1)有机地组织了对象的属性。
比如,在的开发中,我们需要数据来表示日期和时间,这些数据通常是年、月、日、时、分、秒。如果我们不用结构体,那么就需要定义个变量来表示。这样的话程序的数据结构是松散的,我们的数据结构最好是&高内聚,低耦合&的。所以,用一个结构体来表示更好,无论是从程序的可读性还是可移植性还是可维护性皆是:
typedef&struct&&&//公历日期和时间结构体
&&&&vu16 &
&&&&vu8&&&
&&&&vu8&&&
&&&&vu8&&&&
}_calendar_&
&_calendar_obj&&&//定义结构体变量
(2)以修改结构体成员变量的方法代替了函数入口参数的重新定义。
如果说结构体有机地组织了对象的属性表示结构体&中看&,那么以修改结构体成员变量的方法代替函数入口参数的重新定义就表示了结构体&中用&。继续以上面的结构体为例子,我们来分析。假如现在我有如下函数来显示日期和时间:
void&DsipDateTime(&_calendar_obj&&DateTimeVal)
那么我们只要将一个这个结构体类型的变量作为实参调用即可,通过的成变量来实现内容的显示。如果不用结构体,我们很可能需要写这样的一个函数:
void&DsipDateTime(&vu16 year,,,,,
显然这样的形参很不可观,数据结构管理起来也很繁琐。如果某个函数的返回值得是一个表示日期和时间的数据,那就更复杂了。这只是一方面。
另一方面,如果用户需要表示日期和时间的数据中还要包含星期周,这个时候,如果之前没有用机构体,那么应该在函数中在增加一个形参:
void&DsipDateTime(&vu16 year,,,vu8&week,,,可见这种方法来传递参数非常繁琐。所以以结构体作为函数的入口参数的好处之一就是
函数的声明不需要改变,只需要增加结构体的成员变量,然后在函数的内部实现上对作相应的处理即可。这样,在程序的修改、维护方面作用显著。
typedef&struct&&&//公历日期和时间结构体
&&&&vu16 &
&&&&vu8&&&
&&&&vu8&&&
&&&&vu8&&&&
}_calendar_&
&_calendar_obj&&&//定义结构体变量
&&&&(3)结构体的内存对齐原则可以提高对内存的访问速度以空间换取时间。
&&&&并且,结构体成员变量的地址可以根据基地址以偏移量offset)计算。我们先来看看下面的一段简单的程序,对于此程序的分析会在第部分结构体成员变量内存对齐中详细说明。
#include&stdio.h&
int main()
//声明结构体char_short_long
}char_short_
//声明结构体long_short_char
}long_short_
//声明结构体char_long_short
}char_long_
printf(& \n&);
printf(& Size of char
= %d bytes\n&,sizeof(char));
printf(& Size of shrot
= %d bytes\n&,sizeof(short));
printf(& Size of long
= %d bytes\n&,sizeof(long));
printf(& \n&); //char_short_long
printf(& Size of char_short_long
= %d bytes\n&,sizeof(char_short_long));
Addr of char_short_long.c = 0x%p (10进制:%d)\n&,&char_short_long.c,&char_short_long.c);
Addr of char_short_long.s = 0x%p (10进制:%d)\n&,&char_short_long.s,&char_short_long.s);
Addr of char_short_long.l = 0x%p (10进制:%d)\n&,&char_short_long.l,&char_short_long.l);
printf(& \n&);
printf(& \n&); //long_short_char
printf(& Size of long_short_char
= %d bytes\n&,sizeof(long_short_char));
Addr of long_short_char.l = 0x%p (10进制:%d)\n&,&long_short_char.l,&long_short_char.l);
Addr of long_short_char.s = 0x%p (10进制:%d)\n&,&long_short_char.s,&long_short_char.s);
Addr of long_short_char.c = 0x%p (10进制:%d)\n&,&long_short_char.c,&long_short_char.c);
printf(& \n&);
printf(& \n&); //char_long_short
printf(& Size of char_long_short
= %d bytes\n&,sizeof(char_long_short));
Addr of char_long_short.c = 0x%p (10进制:%d)\n&,&char_long_short.c,&char_long_short.c);
Addr of char_long_short.l = 0x%p (10进制:%d)\n&,&char_long_short.l,&char_long_short.l);
Addr of char_long_short.s = 0x%p (10进制:%d)\n&,&char_long_short.s,&char_long_short.s);
printf(& \n&);
程序的运行结果如下注意:括号内的数据是成员变量的地址的十进制形式:
2.&结构体成员变量内存对齐
首先,我们来分析一下上面程序的运行结果。前三行说明在我的程序中,型占个字节,型占个字节,型占个字节。、和是三个结构体成员相同但是成员变量的排列顺序不同。并且从程序的运行结果来看,&
&&&&Size&of long_short_char&=&8&bytes
&&&&Size&of char_long_short&=&12&bytes&&//比前两种情况大!
& & 并且,还要注意到,1 byte (char)+&2&byte&(short)+&4 byte&(long) = 7 byte,而不是8 byte。
& &所以,结构体成员变量的放置顺序影响着结构体所占的内存空间的大小。一个结构体变量所占内存的大小不一定等于其成员变量所占空间之和。如果一个用户程序或者操作系统比如中存在大量结构体变量时,这种内存占用必须要进行优化,也就是说,结构体内部成员变量的排列次序是有讲究的。
结构体成员变量到底是如何存放的呢?
在这里,我就不卖关子了,直接给出如下结论,在没有宏的情况下:
原则&&结构(或联合)的数据成员,第一个数据成员放在为的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如在位机为4字节,则要从的整数倍地址开始存储)。
原则2&&结构体的总大小,也就是的结果,必须是其内部最大成员的整数倍,不足的要补齐。
&&&*原则3&&结构体作为成员时,结构体成员要从其内部最大元素大小的整数倍地址开始存储。(里存有,里有,,等元素时,那么b应该从的整数倍地址处开始存储,因为sizeof(double)&=&8&bytes)
这里,我们结合上面的程序来分析暂时不讨论原则。
先看看char_short_long和这两个结构体,从它们的成员变量的地址可以看出来,这两个结构体符合原则和原则。注意,在
再看看这个结构体,的地址分布情况如下表:
成员变量十六进制地址
成员变量十进制地址
char_long_short.c
0x0012FF2C
char_long_short.l
0x0012FF30
char_long_short.s
0x0012FF34
可见,其内存分布图如下,共:
首先,1244972能被整除,所以放在处没有问题其实,就型成员变量自身来说,其放在任何地址单元处都没有问题,根据原则,在之后的中都没有能被因为整除的,能被整除,所以应该放在处,那么同理,最后一个是应该放在1244980处。
是不是这样就结束了?不是,还有原则。根据原则的要求,char_long_short这个结构体所占的空间大小应该是其占内存空间最大的成员变量的大小的整数倍。如果我们到此就结束了,那么所占的内存空间是4981共计,不符合原则,所以,必须在最后补齐个&。
至此,一个结构体的内存布局完成了。
下面我们按照上述原则,来验证这样的分析是不是正确。按上面的分析,地址单元、、以及、都是空的至少char_long_short未用到,只是&占位&了。如果我们的分析是正确的,那么,定义这样一个结构体,其所占内存也应该是:
struct&//声明结构体
& & &char&&c;
&&&&&char&&add1;&&//补齐空间
&&&&& & &char&&add2;&&//补齐空间
&&&&& & &char&&add3;&&//补齐空间
& & &long&&l;
& & &short&s;
& & & & &char&&add4;&&//补齐空间
& & & & &char&&add5;&&//补齐空间
}char_long_short_
运行结果如下:
可见,我们的分析是正确的。至于原则,大家可以自己编程验证,这里就不再讨论了。
&&&&所以,无论你是在还是,还是中,当你需要定义一个结构体时,只要你稍微留心结构体成员变量内存对齐这一现象,就可以在很大程度上节约的。这一点不仅仅应用于实际编程,在很多大型公司,比如、微软、百度、华为的笔试和面试中,也是常见的。
本例完整的程序代码下载: &
【】【】【】【】
上一篇:下一篇:
CopyRight @
单片机教程网 51hei.com , All Rights Reserved05-1502-1602-1602-1602-1602-1602-1602-1602-1602-16最新范文01-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-01深入理解C语言结构体成员变量内存分配深入理解C语言结构体成员变量内存分配算法与编程之美百家号本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列博客。1 问题描述在学习C语言的时候,我们都会频繁的接触到结构体,使用结构体定义新的数据类型,从而更加方便的存储数据。但是在使用结构体的时候,有些问题会经常会困扰我们,如下所示:第一种结构体定义:struct school{char address[100];char name[30];};第二种结构体定义:struct school_other{char *char *};以上两种结构体的定义有什么区别?我们在使用的时候需要注意什么?本文将和大家一起来深入的探讨这个问题。2 分析问题很多时候对于大家来说,最重要的不是得到问题的答案,而是学会别人是如何分析问题的,这种解决问题的思路对于大家来说才是最重要的,也是最精彩的地方。C语言中定义的任何一个变量,最终都会从你的内存条上拿走相应的内存空间,如定义了一个那么四个字节的空间就给a这个变量了。既然如此,我们很好奇,上述两种类型的结构体,分别占用了多大的内存空间呢?为了解决这个问题,我们编写了以下的程序:这个程序应该很简单,相信各位同学都能看懂,首先定义了两个结构体类型struct school和struct school_other,然后在main函数中定义了两个变量,最后使用sizeof()函数获得变量的内存空间大小。程序的输出结果如下:这种输出结果不知是大家意料之中还是意料之外呢?无论是哪种情况,我们一起来分析分析。如果要我们去计算第一个结构体的内存占用空间,你该如何去计算?struct school{char address[100];char name[30];};由于sizeof(char)==1得到每一个字符型数据占用的空间大小是一个字节,因此上述结构体占用的空间应该是:1 Byte * 100 + 1 Byte * 30 = 130 Byte,这个答案和输出的结果是一致的。按照同样的方式我们去计算另外一个结构体的内存占用空间:struct school_other{char *char *};由于sizeof(char *) == 8得到每一个指针类型的数据占用的空间是八个字节,因此上述结构体占用的空间应该是:8 Byte * 1 + 8 Byte * 1 = 16 Byte,这个答案也和输出结果一致。为什么要花这么多的篇幅去介绍结构体类型空间大小呢?貌似和主题无关,其实正是深入理解主题的核心所在。本文定义一个school结构体的目的在于通过school结构体能够保存某个学校的地址和名称,而地址和名称都是字符数组类型,这种类型可以保存多个字符。struct school这种结构体类型为其成员变量address和name分配了大小分别为100和30的内存空间,有了内存空间,因此可以直接使用。而struct school_other这种结构体类型并没有为其成员变量分配内存空间,因此在使用之前必须对其分配,才可以为其赋值。上述问题,其实可以进一步简化成:char address[100];char* address_这两种变量大家在使用时,应该注意什么?address变量已经有了100个字节的内存空间,因此可以直接对其进行赋值,而address_other只是一个指针即只是一个内存地址,而这个地址是多少并未知晓,因此在使用之前,务必要分配内存空间,然后才能使用。3 总结本文介绍了结构体指针类型的成员变量和数组类型的成员变量的区别,以及在使用时应该注意的问题,帮助大家更好的理解内存分配。更多精彩文章:关于c语言结构体偏移的一点思考(一)关于c语言结构体偏移的一点思考(二)C语言教程第1讲
程序模板C语言教程 实例 1到100求和聊一聊编程聊一聊栈(1)聊一聊栈(2)聊一聊C语言的参数传递聊一聊整数编码由stdout引发的思考史上最简单易懂的二进制转换四川旅游学院 where2go 团队微信号:算法与编程之美
本文由百家号作者上传并发布,百家号仅提供信息发布平台。文章仅代表作者个人观点,不代表百度立场。未经作者许可,不得转载。算法与编程之美百家号最近更新:简介:听说算法和编程爱好者都关注了我们,你呢?作者最新文章相关文章C语言。定了一个结构体没有定义变量,系统分配存储空间了吗?如果没有,系统又是怎么知道这结构体数据类型的
按时间排序
不会分配空间的。只有实例化对象才会。例如结构体student本身没有分配空间,student a就分配空间了
定义之后如果声明就会分配了,不声明就不分配
没有分配内存。编译器在编译的时候会根据struct关键字来识别结构体类型,但如何没有定义变量,生成的目标文件里也不会有相关的内容。
感谢您为社区的和谐贡献力量请选择举报类型
经过核实后将会做出处理感谢您为社区和谐做出贡献
确定要取消此次报名,退出该活动?
请输入私信内容:

我要回帖

更多关于 c 结构体 的文章

 

随机推荐