一篇文章带你用C语言玩转结构体
前言
C语言提供了不同的数据类型,比如说int、float、double、char等,不同的类型决定了一个变量在内存中应该占据的空间以及表现形式。
但是,当我们定义一个人的时候,人的不同属性就比较难用同一个数据类型来定义了,因为人的身高、年龄、体重等属性往往需要不同数据类型,在这个时候,我们便引入结构体这个概念。
一、结构体的声明与定义
1.结构体的声明
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量
当我们面对的事物有多个不同的数据类型的时候,我们就可以使用结构体来组织了。
比如说,一本书有书名、作者、售价、出版日期等等不同的数据类型,这时候我们可以创建结构体来包含书的不同数据类型。
而结构体声明是描述结构体组合的主要方法,语法格式为:
struct 结构体名称
{
结构体成员1;
结构体成员2;
结构体成员3;
…
};//分号不能丢
【注意】
结构体成员既可以是任何一种基本的数据类型,也可以是另一种结构体,如果是后者就相当于结构体的嵌套。(俗称套娃)
例如:
struct Book//描述一本书的相关属性,其中Book是这个框架的名称 { char name[20];//书名 char author[20];//作者 float price;//价格 };//分号一定不能丢
这样就相当于描述了一本书的框架。
2.结构成员的类型
结构成员的类型可以是标量、数组、指针、甚至是其他结构体。
3.结构体的定义
结构体的声明只是进行一个简单的描述,实际上在没有定义结构体类型变量之前,它是不会在内存中分配空间的。
也就是说,它还没有被真正使用,虚拟存在,只有定义了结构体类型变量,才真实存在。
举个例子,上面定义了书的框架
struct Book//描述一本书的相关属性,其中Book是这个框架的名称 { char name[20];//书名 char author[20];//作者 float price;//价格 };//分号一定不能丢
这里在编译器中,并不会分配内存空间,它仅仅是虚拟存在。而一旦我们定义了结构体类型变量,它就可以被分配空间了。
比如:
struct Book//描述一本书的相关属性,其中Book是这个框架的名称 { char name[20];//书名 char author[20];//作者 float price;//价格 };//分号一定不能丢 int main() { struct Book book;//局部变量--放在栈区 return 0; }
我们在上面例子中也可以注意到,定义结构体变量的语法是:
struct 结构体名称 结构体变量名
此外,还可以在结构体声明的时候定义结构体变量
struct Book//描述一本书的相关属性 { char name[20]; char author[20]; float price; }b1,b2;//b1,b2是全局变量。放在静态区 int main() { struct Book book;//局部变量--放在栈区 return 0; }
b1、b2结构体变量是一个全局变量,在其他函数中也可以对它进行访问。
二、初始化结构体
我们在定义一个变量或数组的时候可以对其进行初始化,
例如:
int a=10; int arr[10]={1,2,3,4,5,6,7,8,9,0};
同理,定义结构体变量的时候,我们也可以同时为其初始化
struct Book//描述一本书的相关属性 { char name[20]; char author[20]; float price; }b1,b2;//b1,b2是全局变量。放在静态区 int main() { struct Book book= { "《笑傲江湖》","金庸",30 };//这样的话,就将结构体变量初始化了,也就是定义变量的同时赋初值 return 0; }
三、访问结构体成员
结构体变量访问成员 结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。
比如,book.name就是引用book结构体变量的name成员,它是一个字符数组。
#include <stdio.h> struct Book//描述一本书的相关属性 { char name[20]; char author[20]; float price; }b1, b2;//b1,b2是全局变量。放在静态区 int main() { struct Book book= { "《笑傲江湖》", "金庸", 30 };//这样的话,就将结构体变量初始化了,也就是定义变量的同时赋初值 printf("%s %s %f\n", book.name, book.author, book.price); //用. 来访问 return 0; }
四、结构体嵌套
如果访问嵌套的结构体成员的话,就需要使用多层点号运算符来进行操作。因为C语言的结构体只能对最底层的成员进行访问,如果存在多级结构体嵌套的话,就需要一级一级地深入,直到找到最底层的成员才行
struct S { int a; char c; double d; }; struct T { struct S s;//结构体嵌套 char name[20]; int num; }; int main() { struct T t = { {100,'c',3.14},"里斯",30 }; printf("%d %c %f %s %d\n", t.s.a, t.s.c, t.s.d, t.name, t.num);//使用了两层点号运算符寻找成员 return 0; }
五、结构体指针
在开头的时候说过,结构的成员可以是标量、数组、指针。
在这里,我们来认识一下结构体指针。
struct Book *pt;
这里声明了一个指向Book结构体类型的指针变量pt
struct S { int a; char c; double d; }; struct T { struct S s; char name[20]; int num; }; int main() { struct T t = { {100,'c',3.14},"里斯",30 }; printf("%d %c %f %s %d\n", t.s.a, t.s.c, t.s.d, t.name, t.num); struct T*pt = &t;//拿到地址的方式 printf("%d %c %f %s %d\n", (*pt).s.a, (*pt).s.c, (*pt).s.d, (*pt).name, (*pt).num); printf("%d %c %f %s %d\n",pt->s.a,pt->s.c,pt->s.d,pt->name,pt->num); return 0; }
【注意】数组名指向的是第一个元素的地址,所以可以直接将数组名赋值给指针变量。但是结构体变量的变量名并不是指向该结构体的地址,所以要使用取地址运算符(&)才能获取其地址。
如上面的:
struct T*pt = &t;//拿到地址的方式
通过上面的例子我们也可以发现,通过结构体指针访问结构体成员有以下两种方法:
(1)(*结构体指针).成员名
(2)结构体指针->成员名
第一种由于点号运算符(.)比指针的取值运算符(*)优先级高,所以要使用小口号先对指针进行解引用,让它变成该结构体变量,再用点运算符取访问其成员。
以上两种方法在实现的时候完全等价。但是,切记,点号(.)只能用于结构体,而箭头(->)只能用于结构体指针。
【打印结果一样】
当二者皆可用的时候,优先采用第二种方法,因为箭头具有指向性,很直观的就可以把它与指针联系起来了。
六、结构体传参
函数调用的时候,参数的传递就是值传递的过程,也就是将实参传给形参的过程。所以,结构体变量可以作为函数的参数传递,两个相同结构体类型的结构体变量也支持直接赋值。
struct S { int arr[100]; int num; char ch; double d; }; //结构体传参 void print1(struct S ss) { printf("%d %d %d %c %1f", ss.arr[0],ss.arr[2],ss.num,ss.ch,ss.d); } //结构体地址传参 void print2(struct S*ps) { printf("%d %d %d %c %1f", ps->arr[0], ps->arr[2], ps->num, ps->ch, ps->d); } int main() { struct S s = { {1,2,3,4,5}, 100, 'w',3.14 }; print1(s);//传结构体 print2(&s);//传地址 return 0; }
可以看到,确实把参数传递过去了。
那么,上面的 print1 和 print2 函数哪个好些?
答案是:首选print2函数。 原因:
函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
因此,结构体传参的时候,要传结构体的地址。
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注猪先飞的更多内容!
相关文章
- 这篇文章主要为大家详细介绍了C语言实现放烟花的程序,有音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-23
- 本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下...2020-04-25
- 这篇文章主要介绍了详解如何将c语言文件打包成exe可执行程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-25
- free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
- 这篇文章主要介绍了C语言中计算正弦的相关函数总结,包括正弦和双曲线正弦以及反正弦的函数,需要的朋友可以参考下...2020-04-25
详解C语言中的rename()函数和remove()函数的使用方法
这篇文章主要介绍了详解C语言中的rename()函数和remove()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25- 这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
- 这篇文章主要介绍了C# 结构体struct 的相关资料,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2020-11-03
- 本篇文章主要讲解C语言 基本语法,这里提供简单的示例和代码来详细讲解C语言的基本语法,开始学习C语言的朋友可以看一下,希望能够给你带来帮助...2021-09-18
- 这篇文章主要介绍了C语言中send()函数和sendto()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25
- 今天小编就为大家分享一篇C语言实现从文件读入一个3*3数组,并计算每行的平均值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-25
- 这篇文章主要介绍了关于C#结构体的相关知识,以及使用方法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
- 这篇文章主要介绍了C语言中memcpy 函数的用法详解的相关资料,需要的朋友可以参考下...2020-04-25
- 这篇文章主要介绍了使用C语言操作文件的基本函数整理,包括创建和打开以及关闭文件的操作方法,需要的朋友可以参考下...2020-04-25
- 下面小编就为大家分享一篇基于C#调用c++Dll结构体数组指针的问题详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-06-25
- 这篇文章主要介绍了C语言中查找字符在字符串中出现的位置的方法,分别是strchr()函数和strrchr()函数的使用,需要的朋友可以参考下...2020-04-25
- 很多同学在学习c语言的时候是不是会碰到a++和++a都有甚么作用啊。今天我们就来探讨下...2020-04-25
- 这篇文章主要介绍了c# 结构体的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要对C语言中const关键字的用法进行了详细的分析介绍,需要的朋友可以参考下...2020-04-25
- 下面小编就为大家带来一篇C语言实现时间戳转日期的算法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-04-25