一、结构体的概念

        结构体(struct)是 C 语言中一种自定义数据类型,它允许你将不同类型的数据项组合在一起,形成一个新的复合数据类型。

        想象一下:如果要表示一个 "学生",需要包含姓名(字符串)、年龄(整数)、成绩(浮点数)等信息。这些数据类型不同,无法用单一的基本类型表示,这时就需要结构体来将它们组织起来。

二、结构体的定义和声明

2.1 结构体的基本定义格式

struct 结构体名 {数据类型 成员名1;数据类型 成员名2;// ... 更多成员
};

示例:定义一个学生结构体

struct Student {char name[20];  // 姓名int age;        // 年龄float score;    // 成绩
};

注意:

        结构体类型的名字是由一个关键字 struct 和结构体名组合而成的(例如 struct Student )。结构体名是由用户指定的,又称“结构体标记”(structure tag),以区别于其他结构体类型。上面的结构体声明中Student就是结构体名(结构体标记)。花括号内是该结构体所包括的子项,称为结构体的成员(member)。

2.2 结构体的声明

2.2.1 先定义结构体类型,再声明变量

struct Student {char name[20];int age;float score;
};// 声明结构体变量
struct Student stu1, stu2;

2.2.2 定义结构体类型的同时声明变量

struct Student {char name[20];int age;float score;
} stu1, stu2;

        它的作用与第一种方法相同,但是在定义struct Student类型的同时定义两个struct Student类型的变量stu1和stu2。这种定义方法的一般形式为

struct 结构体名

{  成员表列

} 变量名表列;

        声明类型和定义变量放在一起进行,能直接看到结构体的结构,比较直观,在写小程序时用此方式比较方便,但写大程序时,往往要求对类型的声明和对变量的定义分别放在不同的地方,以使程序结构清晰,便于维护,所以一般不多用这种方式。

2.2.3 匿名结构体(不指定类型名而直接定义结构体类型变量)

struct {char name[20];int age;float score;
} stu1, stu2;

        其一般形式为

struct

                {  成员表列

                        } 变量名表列;

        指定了一个无名的结构体类型,它没有名字(不出现结构体名)。显然不能再以此结构体类型去定义其他变量。这种方式用得不多。

说明:

        (1)结构体类型与结构体变量是不同的概念,不要混淆。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。

        (2)结构体类型中的成员名可以与程序中的变量名相同,但二者不代表同一对象。例如,程序中可以另定义一个变量 num,它与 struct Student 中的 num 是两回事,互不干扰。

        (3)对结构体变量中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。

2.3 结构体嵌套

        结构体可以嵌套在另一个结构体中,即成员可以属于另一个结构体类型:

#include <stdio.h>// 定义日期结构体
struct Date {int year;int month;int day;
};// 定义学生结构体,嵌套了日期结构体
struct Student {char name[20];struct Date birthday;  // 嵌套结构体float score;
};int main() {struct Student stu = {"张三",{2005, 3, 15},  // 初始化嵌套的结构体95.5f};printf("姓名:%s\n", stu.name);printf("生日:%d年%d月%d日\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);printf("成绩:%.1f\n", stu.score);return 0;
}

        运行结果:

三、结构体变量的初始化和引用

3.1 结构体变量的初始化

        (1)在定义结构体变量时可以对它的成员初始化。初始化列表是用花括号括起来的一些常量,这些常量依次赋给结构体变量中的各成员。

        (2)注意:是对结构体变量初始化,而不是对结构体类型初始化。

// 方法1:按顺序初始化
struct Student stu1 = {"张三", 18, 95.5f};// 方法2:指定成员初始化(C99标准支持)
struct Student stu2 = {.name = "李四",.age = 19,.score = 88.0f
};

3.2 结构体变量的引用

        (1)可以引用结构体变量中成员的值,引用方式为

结构体变量名.成员名

 例:

#include <stdio.h>
#include <string.h>struct Student {char name[20];int age;float score;
};int main() {struct Student stu;// 给结构体成员赋值strcpy(stu.name, "王五");  // 字符串赋值需使用strcpy函数stu.age = 20;stu.score = 92.5f;// 访问结构体成员printf("姓名:%s\n", stu.name);printf("年龄:%d\n", stu.age);printf("成绩:%.1f\n", stu.score);return 0;
}

        运行结果:

       

         “.”是成员运算符,它在所有的运算符中优先级最高,因此可以把stu.age作为一个整体来看待,相当于一个变量。上面赋值语句 stu.age = 20; 的作用是将整数20赋给stu变量中的成员 age。

        注意:不能企图通过输出结构体变量名来达到输出结构体变量所有成员的值。

        下面用法不正确:

printf("%s\n",stu);		//企图用结构体变量名输出所有成员的值

只能对结构体变量中的各个成员分别进行输入和输出。

        (2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。如果在结构体struct Student类型的成员中包含另一个结构体struct Date类型的成员 birthday(见2.3节结构体嵌套代码),则引用成员的方式为

        stu.name         (结构体变量stu中的成员name)

        stu. birthday.month             (结构体变量stu中的成员birthday中的成员month)

不能用 stu.birthday来访问stu变量中的成员 birthday,因为 birthday本身是一个结构体成员。

        (3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。例如:

stu2.score=stu1.score;               //(赋值运算)

sum=stu1.score+stu2.score;      //(加法运算)

stu1.age++;                                 //(自加运算)

        由于“.”运算符的优先级最高,因此 stu1.age++是对(stu1.age)进行自加运算,而不是先对 age 进行自加运算。

        (4)同类的结构体变量可以互相赋值,如:

stu1=stu2;            //假设stu1和stu2已定义为同类型的结构体变量

        (5)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。例如:

                        scanf(“%d”, &stu1. num);                   (输人stu1.num的值)

                        printf("%o",&stu1);                             (输出结构体变量studentl的起始地址)

        但不能用以下语句整体读入结构体变量,例如:

scanf("%d,%s,%c,%d,%f,%s\n",&stu1);

        说明:结构体变量的地址主要用作函数参数,传递结构体变量的地址。

 四、结构体数组

4.1 结构体数组的定义与声明

定义结构体数组一般形式是

①struct 结构体名

{成员表列} 数组名[数组长度];

②先声明一个结构体类型(如struct Person),然后再用此类型定义结构体数组;

结构体类型 数组名[数组长度];

4.2 结构体数组的初始化

对结构体数组初始化的形式是在定义数组的后面加上:

={初值表列};

例:

#include <stdio.h>struct Student {char name[20];int age;float score;
};int main() {// 定义并初始化结构体数组struct Student students[3] = {{"张三", 18, 95.5f},{"李四", 19, 88.0f},{"王五", 20, 92.5f}};// 遍历结构体数组for (int i = 0; i < 3; i++) {printf("第%d个学生:\n", i+1);printf("  姓名:%s\n", students[i].name);printf("  年龄:%d\n", students[i].age);printf("  成绩:%.1f\n", students[i].score);}return 0;
}

五、结构体指针

        所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。

5.1 指向结构体变量的指针

        指向结构体对象的指针变量既可指向结构体变量,也可指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同。例如:

struct Student * pt;	//pt可以指向struct Student类型的变量或数组元素

例题:

#include <stdio.h>
#include <string.h>
int main()
{struct Student               //声明结构体类型 struct Student{long num;char name[20];char sex;float score;};struct Student stu_1;        //定义 struct Student 类型的变量 stu_1struct Student* p;           //定义指向 struct Student 类型数据的指针变量 pp = &stu_1;                  //p 指向 stu_1stu_1.num = 10101;           //对结构体变量的成员赋值strcpy_s(stu_1.name, "Li Lin");//用字符串复制函数给 stu_1.name 赋值stu_1.sex = 'M';stu_1.score = 89.5;printf("No.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",stu_1.num, stu_1.name, stu_1.sex, stu_1.score);      //输出结果printf("\nNo.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",(*p).num, (*p).name, (*p).sex, (*p).score);return 0;
}

运行结果:

        第1个 printf 函数是通过结构体变量名 stu_1 访问它的成员,输出 stu_1 的各个成员的值。用 stu_1.num 表示 stu_1 中的成员 num,依此类推。第2个 printf 函数是通过指向结构体变量的指针变量访问它的成员,输出 stu_1 各成员的值,使用的是 (*p).num 这样的形式。(*p) 表示p指向的结构体变量,(*p).num是p所指向的结构体变量中的成员 num。注意 *p两侧的括号不可省,因为成员运算符“.”优先于”*”运算符, *p.num 就等价于 *(p.num) 了。

        说明:为了使用方便和直观,C语言允许把 (*p).num 用 p->num 代替,“->” 代表一个箭头,p->num 表示 p 所指向的结构体变量中的 num 成员。同样,(*p).name 等价于 p->name。“->” 称为指向运算符。

如果 p 指向一个结构体变量 stu,以下3种用法等价:

① stu. 成员名(如 stu.num);

② (*p).成员名(如 (*p).num);

③ p-> 成员名(如 p->num)。        

例:结构体指针是指向结构体的指针变量,使用箭头运算符(->)访问成员:

#include <stdio.h>
#include <string.h>struct Student {char name[20];int age;float score;
};int main() {struct Student stu;struct Student *p_stu = &stu;  // 结构体指针指向stu变量// 通过指针给结构体成员赋值strcpy(p_stu->name, "赵六");p_stu->age = 19;p_stu->score = 89.0f;// 也可以使用(*p_stu).成员名的方式访问printf("姓名:%s\n", (*p_stu).name);printf("年龄:%d\n", p_stu->age);printf("成绩:%.1f\n", p_stu->score);return 0;
}

5.2指向结构体数组的指针

例:

#include <stdio.h>
// 声明结构体类型 struct Student
struct Student
{int num;char name[20];char sex;int age;
};struct Student stu[3] = {{10101, "Li Lin", 'M', 18},{10102, "Zhang Fang", 'M', 19},{10104, "Wang Min", 'F', 20}
};int main()
{// 定义指向 struct Student 结构体变量的指针变量struct Student* p;printf(" No.  Name                 sex age\n");// 遍历结构体数组for (p = stu; p < stu + 3; p++){// 通过指针访问成员输出printf("%5d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age);}return 0;
}

运行结果:

六、结构体作为函数参数

        结构体可以作为函数参数传递,有两种方式:

6.1 传递结构体变量(值传递)

#include <stdio.h>struct Student {char name[20];int age;float score;
};// 结构体作为函数参数(值传递)
void printStudent(struct Student s) {printf("姓名:%s\n", s.name);printf("年龄:%d\n", s.age);printf("成绩:%.1f\n", s.score);
}int main() {struct Student stu = {"张三", 18, 95.5f};printStudent(stu);  // 传递结构体变量return 0;
}

6.2 传递结构体指针(地址传递)

#include <stdio.h>struct Student {char name[20];int age;float score;
};// 结构体指针作为函数参数(地址传递)
void updateScore(struct Student *s, float newScore) {s->score = newScore;  // 修改结构体成员的值
}int main() {struct Student stu = {"张三", 18, 95.5f};printf("修改前成绩:%.1f\n", stu.score);updateScore(&stu, 98.0f);  // 传递结构体地址printf("修改后成绩:%.1f\n", stu.score);return 0;
}

        注意:值传递会复制整个结构体,效率较低;地址传递只传递指针,效率更高,且可以在函数内部修改结构体的值。

七、typedef 与结构体

        使用typedef可以为结构体类型定义一个别名,简化代码:

#include <stdio.h>// 使用typedef定义结构体别名
typedef struct {char name[20];int age;float score;
} Student;  // Student是结构体的别名int main() {// 直接使用别名声明变量,无需再写structStudent stu = {"张三", 18, 95.5f};printf("姓名:%s\n", stu.name);return 0;
}

八、结构体应用示例

         下面是一个综合示例,演示结构体的各种用法:

#include <stdio.h>
#include <string.h>// 定义学生结构体
typedef struct {char name[20];int id;float scores[3];  // 三门课成绩float average;    // 平均分
} Student;// 计算平均分
void calculateAverage(Student *stu) {float sum = 0;for (int i = 0; i < 3; i++) {sum += stu->scores[i];}stu->average = sum / 3;
}// 打印学生信息
void printStudent(Student stu) {printf("学号:%d\n", stu.id);printf("姓名:%s\n", stu.name);printf("成绩:%.1f, %.1f, %.1f\n", stu.scores[0], stu.scores[1], stu.scores[2]);printf("平均分:%.1f\n\n", stu.average);
}int main() {// 定义学生数组Student students[3];// 初始化学生信息strcpy(students[0].name, "张三");students[0].id = 1001;students[0].scores[0] = 90.5f;students[0].scores[1] = 85.0f;students[0].scores[2] = 92.5f;strcpy(students[1].name, "李四");students[1].id = 1002;students[1].scores[0] = 88.0f;students[1].scores[1] = 91.5f;students[1].scores[2] = 89.0f;strcpy(students[2].name, "王五");students[2].id = 1003;students[2].scores[0] = 95.0f;students[2].scores[1] = 87.5f;students[2].scores[2] = 93.0f;// 计算每个学生的平均分for (int i = 0; i < 3; i++) {calculateAverage(&students[i]);}// 打印所有学生信息printf("学生信息列表:\n");for (int i = 0; i < 3; i++) {printStudent(students[i]);}return 0;
}

九、结构体的注意事项

  1. 结构体变量占用的内存空间是所有成员占用空间的总和(可能存在内存对齐)

  2. 结构体成员名可以与普通变量名相同,两者的作用域不同

  3. 不能在结构体内部初始化成员变量

  4. 结构体可以嵌套,但不能包含自身类型的成员(可以包含自身类型的指针)

  5. 结构体赋值可以直接使用=进行整体赋值(浅拷贝)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92755.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92755.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/92755.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小白入门指南:Edge SCDN 轻松上手

在互联网飞速发展的当下&#xff0c;网站性能与安全至关重要。对于小白而言&#xff0c;Edge SCDN 可能是个陌生概念&#xff0c;但它却能极大助力网站运营。本文将用简单易懂的语言&#xff0c;带大家了解 Edge SCDN&#xff0c;探讨其运用方法。​一、Edge SCDN 是什么&#…

探秘酵母单杂交技术:解锁基因调控的密码

在生命科学研究领域&#xff0c;基因的表达调控机制一直是科学家们关注的焦点。为了深入探究这一复杂过程&#xff0c;众多先进技术应运而生&#xff0c;酵母单杂交技术便是其中极具价值的一项&#xff0c;它为研究 DNA 与蛋白质之间的相互作用提供了独特视角与有效手段。酵母单…

大模型备案要点一次过【附材料清单详解】

最近&#xff0c;广东省公布了最新一批的大模型备案&#xff08;登记&#xff09;名单&#xff0c;很多准备要做大模型备案的企业都在纷纷咨询&#xff1a;“大模型备案的周期是多久&#xff1f;”“做大模型备案有什么要求&#xff1f;”“做大模型备案一共需要准备多少材料&a…

启保停-----------单相照明灯的接法

一.单相照明灯-K21使用的器材,单相电能表,空开,插座,开关,灯泡二.启 保 停1.需要用到的器材1.空开2.三相电机3.接触器4.熔断器5.按钮2.电路的作用按按钮 运转 在按按钮 停止运转3.电动4.加上辅助触点 控制电路5.在加上按钮 停止电路

TF-IDF:信息检索与文本挖掘的统计权重基石

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 1. 背景与定义 TF-IDF 是一种统计加权方法&#xff0c;用于衡量词语在…

[论文阅读] (41)JISA24 物联网环境下基于少样本学习的攻击流量分类

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

react中父子数据流动和事件互相调用(和vue做比较)

前言&#xff1a;react中父子数据流动和事件互相调用&#xff0c;父组件给子组件数据&#xff0c;父组件调用子组件的事件&#xff0c;同理&#xff0c;子也可以调用父的数据和传值。react是单向数据流&#xff0c;具体使用跟vue是不同的。1、父组件的数据传给子组件&#xff0…

杰理手表-增加提示音-提示音音量调整--使用提示音

本章节非常详细的介绍这个提示音的增加-调整-使用&#xff0c;其余耳机包之类的也是差不多的&#xff01;&#xff01; 目录 1.添加自己需要用的提示音 2.根据添加的提示音-代码中配置 1.在tone_player.h中枚举里添加本次提示音的名称 2.把定义好的提示音放到tone_player.…

数据库的基本操作(视图,存储,触发器)

1、视图&#xff08;1&#xff09;什么是视图视图是虚拟表&#xff0c;是基于查询结果的可视化表&#xff0c;视图的作用有&#xff1a;①简化复杂查询 ②限制数据访问 ③提供数据独立性 ④汇总数据&#xff08;2&#xff09;怎么创建视图创建视图 CREATE OR REPLACE VIEW 视图…

Pytest项目_day13(usefixture方法、params、ids)

usefixture 我们还可以使用mark.usefixtures来调用fixture 这样相比在传入参数处调用fixture&#xff0c;会更加直接 但是如果我们在一个测试用例中使用了多个usefixtures&#xff0c;那么测试用例会先调用离他最近的那个fixtureparams fixture中还可以带参数 当我们用request.…

Rust 异步生态实战:Tokio 调度、Pin/Unpin 与零拷贝 I/O

&#x1f31f; Hello&#xff0c;我是蒋星熠Jaxonic&#xff01; &#x1f308; 在浩瀚无垠的技术宇宙中&#xff0c;我是一名执着的星际旅人&#xff0c;用代码绘制探索的轨迹。 &#x1f680; 每一个算法都是我点燃的推进器&#xff0c;每一行代码都是我航行的星图。 &#x…

通用 maven 私服 settings.xml 多源配置文件(多个仓库优先级配置)

<?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/SETTINGS/1.0.…

AT F-Intervals 题解

简化题意&#xff1a; 有 nnn 个区间&#xff0c;保证所有区间同时覆盖一个点&#xff0c;每次将区间平移一个单位&#xff0c;问使得区间两两不交的最小操作数&#xff08;端点处可重叠&#xff09;。n≤5000。l,r≤231−1n\leq 5000。l,r\leq 2^{31}-1n≤5000。l,r≤231−1。…

《飞算Java AI:从安装到需求转实战项目详细教学》

前引&#xff1a;在当今快速发展的技术环境中&#xff0c;人工智能&#xff08;AI&#xff09;与编程语言的结合为开发者提供了前所未有的便利。飞算Java AI作为一款智能化编程工具&#xff0c;能够显著提升Java开发效率&#xff0c;减少重复性工作&#xff0c;并帮助开发者更专…

6深度学习Pytorch-神经网络--过拟合欠拟合问题解决(Dropout、正则化、早停法、数据增强)、批量标准化

过拟合、欠拟合 在机器学习和深度学习中&#xff0c;过拟合&#xff08;Overfitting&#xff09;和欠拟合&#xff08;Underfitting&#xff09;是模型训练过程中常见的两种问题&#xff0c;直接影响模型的泛化能力&#xff08;即对未见过的数据的预测能力&#xff09;。 1. 欠…

新手向:Python编写简易翻译工具

Python 编写简易翻译工具&#xff1a;从零开始入门指南对于刚接触编程的新手来说&#xff0c;编写一个实用的工具是快速入门的好方法。本文将详细介绍如何用 Python 编写一个简易的翻译工具&#xff0c;帮助理解基础编程概念和实际应用。无需任何编程基础&#xff0c;只需按照步…

爬虫与数据分析结和

任务描述 爬取目标&#xff1a;高三网中国大学排名一览表&#xff0c;网址为 2021中国的大学排名一览表_高三网。爬取内容&#xff1a;学校名称、总分、全国排名、星级排名、办学层级。数据存储&#xff1a;爬取后的数据保存在 CSV 文件中。 代码实现&#xff08;爬取&#xff…

linux下安装php

1.php官网下载所需要的php版本 下载php 2.将下载好的压缩包上传至linux服务器&#xff0c;解压并配置 tar -xzvf php-8.4.11.tar.gz cd php-8.4.11 ./configure --prefix/home/admintest/php/php-8.4.11 # 配置安装路径和选项 make sudo make install3.使用make命令编译完成…

nurbs曲线的matlab

基于MATLAB的NURBS曲线生成与可视化程序 %% NURBS曲线生成与可视化 clc; clear; close all;%% 基本参数设置 degree 3; % 曲线阶数 (degree k-1, k为控制点数) numCtrlPts 6; % 控制点数量 weights ones(1, numCtrlPts); % 权重向量&#xff08;可调整&#…

AWS WAF防护机制深度研究:多模式验证与绕过技术解析

AWS WAF防护机制深度研究&#xff1a;多模式验证与绕过技术解析 技术概述 AWS WAF&#xff08;Web Application Firewall&#xff09;作为亚马逊云服务的核心安全组件&#xff0c;为Web应用提供了多层次的防护机制。该系统基于先进的机器学习算法和规则引擎&#xff0c;能够实…