概念

结构体是一种构造类型,由若干个成员组成,成员可以是基本数据类型,或是另一个结构体

声明结构体

struct 结构体名
{
成员列表
};

结构体名表示结构的类型名。

声明一个结构体表示创建一种新的类型名(自定义数据类型),然后用类型名定义变量。

struct Product
{
char name[10];
char shape[10];
char color[10];
float price;
}

使用结构体定义变量有三种方式

第一种:声明结构体类型,再定义变量

struct Product p1;
struct Product p2;

p1和p2是结构体变量名,这两个变量具有相同的结构

类比:

   类型名             变量名
int a;
| |
struct Product p;

struct Product整体表示一种数据类型

定义结构体变量后,系统会为其分配内存单元

第二种:声明结构体类型时,同时定义变量(可以定义多个变量)

struct 结构体名
{
成员列表
} 变量名列表;

example:

struct Product
{
char name[10];
char shape[10];
char color[10];
float price;
} p1, p2;

第三种:直接定义结构体类型变量(匿名结构体,没有结构体名称)

struct
{
成员列表
} 成员变量;

example:

struct
{
char name[10];
char shape[10];
char color[10];
float price;
} p1, p2;

类型和变量时不同的:

  • 只能对变量进行赋值操作,而不能对一个类型操作
  • 类型不分配空间,只对变量分配空间

结构体成员也可以时结构体类型变量:

struct date
{
int year;
int month;
int day;
}; struct student
{
char name[20];
char gender;
int age;
// 结构体类型变量
struct date birthday;
};

结构体变量的引用

结构体变量名.成员名

example:

p1.name = "IceBox";
p2.price = 2000;

如果成员本身又属于另一个结构体类型,需要使用多个成员运算符

struct student s;
s.birthday.year = 1986;
s.birthday.month = 11;
s.birthday.day = 6;

不仅可以对结构体变量成员的地址进行引用,还可以对结构体变量的地址进行引用

scanf("%d", &p1.price);
printf("%O", &p1); // 输出p1的首地址

结构体类型的初始化

struct Student
{
char name[10];
char gender;
int grade;
} student = { "Felix", "m", 4 };

注意:每一个数据要与结构体的成员列表的顺序一样。


定义结构体数组

struct 结构体名
{
成员列表
}数组名;

example:

struct Student
{
char name[20];
int code;
char gender;
int grade;
} student[5];

这种方式是声明结构体类型的同时定义结构体数组。也可以先声明结构体类型,再定义变量

struct Student student[5];

或直接定义结构体数组:

struct
{
char name[20];
int code;
char gender;
int grade;
} student[5];

以上定义了一个数组,其中元素为struct Student类型的数据,每个数据中又有4个成员变量。看图:


结构体数组的初始化

struct 结构体名
{
成员列表
} 数组名 = {初始值列表};

example:

struct Student
{
char name[20];
int code;
char gender;
int grade;
} student[5] = {
{"关羽", 192829, 'M', 3},
{"张飞", 82873, 'M', 2},
{"赵云", 827348, 'M', 4},
{"黄忠", 9238347, 'M', 4},
{"刘备", 983784, 'M', 5}
};

为数组进行初始化时,最外层的大括号列出数组的元素,因为每个元素都是结构体类型,所以每个元素也使用大括号,其中包含每一个结构体成员数据。

定义结构体数组时,也可以先声明结构体类型,再定义结构体数组。

struct Student student[5] = {
{"关羽", 192829, 'M', 3},
{"张飞", 82873, 'M', 2},
{"赵云", 827348, 'M', 4},
{"黄忠", 9238347, 'M', 4},
{"刘备", 983784, 'M', 5}
};

结构体指针

一个指向变量的指针,表示变量所占用内存中的起始地址。如果一个指针指向结构体变量,则该指针指向的时结构体变量的起始地址。

定义结构体指针:

结构体类型 *指针名;

example:

// 指向struct Student结构类型的pStudent指针变量
struct Student *pStudent;

使用指向结构体变量的指针访问成员有两种方法:

第一种:使用点运算符引用结构体成员

// 一定要使用括号,因为点运算符的优先级最高
(*pStudent).成员名
// example
(*pStudent).code = 9837849;

第二种:使用指向运算符引用结构体成员

pStudent->成员名;
// example
pStudent->code = 393848;

如果student是结构体变量,pStudent是指向结构体变量的指针,以下三种效果是等价的:

student.成员名;
(*pStudent).成员名;
pStudent->成员名;

指向结构体数组的指针

结构体指针变量不但可以指向一个结构体变量,还可以指向结构体数组,此时指针变量的值就是结构体数组的首地址。

结构体指针变量可以直接指向结构体数组中的元素,这时指针变量的值就是该结构体数组元素的首地址。

// 假设:struct Student student[5];
struct Student *pStudent;
// 指向数组的首地址
pStudent = student;

数组不使用下标时,表示数组的第一个元素的地址,所以指针指向数组的首地址。 如果想利用指针指向第3个元素,则在数组名后附加下标,然后在数组名前使用取地址符号&

pStudent = &student[2];

结构体作为函数参数

使用结构体作为函数参数有3种形式:

  • 使用结构体变量作为函数的参数
  • 使用结构体变量的成员作为函数参数
  • 使用指向结构体变量的指针作为函数的参数

第一种:使用结构体变量作为函数的参数

使用结构体变量的作为函数的实参时,采取的是"值传递",会将结构体变量所占内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量

void display(struct Student stu);

在形参位置使用结构体变量,但是函数调用期间,形参也要占用内存单元,这种传递方式在空间和时间上开销都比较大。

根据函数参数传值方式,如果在函数内部修改了变量中成员的值,则改变的值不会返回到主调函数中。

第二种:使用结构体变量的指针作为参数

在使用结构体变量作为函数的参数时,传值过程中空间和时间开销大,可以使用结构体变量的指针作为函数的参数进行传递。

在使用结构体变量的指针时,只是将结构体变量的首地址进行传递,并没有将变量的副本进行传递。

void display(struct Student *stu);

因为这里传递的变量时地址,如果在函数中改变成员中的数据,那么返回主调函数时变量会发生改变。

#include <stdio.h>

struct Student {
char name[20];
float score[30];
} student = { "刘备", 98.39f, 89.0, 93.5f }; void display(struct Student *s) {
printf("-------------以下是学生信息-------------\n");
printf("姓名: %s\n", s->name);
printf("数学成绩: %.2f\n", s->score[2]);
// 修改了数组元素的值
s->score[2] = 90.2f;
} int main(int argc, char const *argv[]) {
struct Student *pStudent;
pStudent = &student;
display(pStudent);
// 也可以直接传递结构体变量的地址作为参数
// display(&student); // 主调函数中,结构体成员的值发生了改变
printf("修改后的数学成绩: %.2f\n", pStudent->score[2]);
return 0;
}

重学C语言之结构体的更多相关文章

  1. Go语言 6 结构体、方法和接口

    文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 结构体(struct)是由一系列具有相同类型或不同类 ...

  2. C语言之结构体概述

    C语言之结构体概述1.结构体类型是一种自定义类型(1)C语言中有2种类型:原生类型和自定义类型.2.结构体使用时先定义结构体类型再用类型定义变量(1)结构体定义时需要先定义结构体类型,再用类型来定义变 ...

  3. C语言中结构体赋值问题的讨论

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  4. C语言的结构体和C++结构体的区别

    关于C++中声明结构体中需要使用构造器创建实例对象的语法: <C++的结构体构造方法的基本概念:结构体的构造方法需要和结构体的名字相同,并且无返回值,也不要void关键字,这样的方法就是构造器的 ...

  5. 01.C语言关于结构体的学习笔记

    我对于学习的C语言的结构体做一个小的学习总结,总结如下: 结构体:structure 结构体是一种用户自己建立的数据类型,由不同类型数据组成的组合型的数据结构.在其他高级语言中称为记录(record) ...

  6. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  7. 逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式

    逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式 一丶了解什么是结构体,以及计算结构体成员的对其值以及总大小(类也是这样算) 结构体的特性 1.结构体(struct)是由一系列具有相同类型或不 ...

  8. C语言中结构体赋值问题的讨论(转载)

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  9. go语言学习-结构体

    结构体 go语言中的结构体,是一种复合类型,有一组属性构成,这些属性被称为字段.结构体也是值类型,可以使用new来创建. 定义: type name struct { field1 type1 fie ...

随机推荐

  1. android 第三方开源库 学习汇总

    依赖注入框架ButterKnife  https://github.com/JakeWharton/butterknife  学习过程     专注于android的View注入框架,并不支持其他方面 ...

  2. sap设置SE38编辑器背景色

    1.SE38,随便找个程序进入,编辑模式. 点击客户端最右下角的文件夹图标: 2.设置normal 背景颜色: 3.退出,重新进就可以了. 这里很多其他类型的颜色和字体设置,根据个人爱好调整.

  3. Vue2.0 新手入门 — 从环境搭建到发布

    什么是 Vue Vue 是一个前端框架,特点是数据绑定 比如你改变一个输入框 Input 标签的值,会自动同步更新到页面上其他绑定该输入框的组件的值 组件化 页面上小到一个按钮都可以是一个单独的文件. ...

  4. volume create: k8s-volume: failed: Host 172.31.182.142 is not in 'Peer in Cluster' state

    问题描述: 1.gluster peer status查询存在节点 2.创建volume失败提示节点不存在 排查方法: 1.hosts文件是否配置正确 2.检查防火墙是否打开,打开的话放行24007端 ...

  5. AI-图像基础知识-01

        目前人工智能Artificial Intelligence主要分为两大分支: 计算机视常见:Computer Vision,简称CV   CV主要是研究如何让机器看懂世界的一种技术,通过各种光 ...

  6. 网传英特尔酷睿第十代桌面处理器(Comet Lake 14nm)规格

    自从农企(AMD)2016年开始崛起时,牙膏厂(英特尔)就开始发力,陆续两代推出性价比颇高的桌面处理器, 第八代.第九代酷睿桌面处理器相当的给力,而第十代酷睿桌面处理器会很猛啊,据传从酷睿i3到酷睿i ...

  7. vuex的简单总结使用

    State负责存储整个应用的状态数据,一般需要在使用的时候在跟节点注入store对象,后期就可以使用this.$store.state直接获取状态 辅助函数的使用 1.mapState state的m ...

  8. linux 以导入文件形式添加定时任务(crontab)时需要注意的坑

    在实际操作过程中发现,使用导入文件形式添加定时任务时,会将用户已有的定时任务全部覆盖清理(先清空,再重新导入),所以在使用文件导入定时任务时,需要先将已有定时任务导出,然后将新任务进行追加到已有定时任 ...

  9. 阿里巴巴java开发手册 学习

    3. [强制]类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外: DO / BO / DTO / VO / AO 正例: MarcoPolo / UserDO / Xml ...

  10. 请解释一下css3的flexbox(弹性盒布局模型),以及适用场景

    弹性盒模型是c3规范的新的布局方式,该布局模型的目的是提供一种更加高效的方式来对容器的条目进行布局.对齐和分配空间.在传统的布局中,block布局是把块级元素在垂直方向从上向下一次排列的,而inlin ...