C语言 - 结构体、结构体数组、结构体指针和结构体嵌套

news2025/1/19 2:59:44

结构体的意义

问题:学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用 C 语言程序存储并处理一组学生的学籍。
单个学生学籍的数据结构:

  • 学号(num): int 型
  • 姓名(name) :char [ ] 型
  • 性别(sex):char 型
  • 年龄(age):int 型
  • 分数(score):float 型
    思考:如果有多个学生,该怎么定义,已学数据类型无法解决(已学的数据类型需要定义好多变量,不友好)。

概述

  • 正式:
    结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据被称为结构型数据的 “成员” ,其描述了一块内存区间的大小及解释意义。
  • 通俗:
    结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。

在C语言中,定义结构体的语法格式如下:

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

其中,结构体名是您自定义的结构体类型名称,可以根据需求进行命名。成员1成员2等表示结构体的成员变量,每个成员都有自己的类型和名称。

定义结构体后,可以使用该结构体类型创建结构体变量,并访问结构体的成员。访问结构体成员的语法是使用结构体变量名后跟成员名,中间使用点.进行连接。

结构体的使用

  • struct 结构体名 变量名

  • struct 结构体名 变量名 = {成员1值,成员2值…}

  • 定义结构体时顺便创建变量(这时候创建几个变量都可以,中间用逗号隔开,直接在创建的时候赋值也可以,例如:)

    struct student
    {
      int num; //学号
      char name[16];  //姓名
      float score;  //成绩
    }stu5 = {1002,"lihua",89},stu6;
    
  • 如果只想给一部分数据赋值的话:

    struct 结构体名 变量名 = {
    .name = "cuiyi",
    .num = 111,
    };
    

下面是一个更完整的示例:

#include <stdio.h>

// 定义一个结构体
struct Person {
    char name[50];
    int age;
    float height;
};

int main() {
    // 创建一个结构体变量
    struct Person person1;

    // 访问结构体的成员
    strcpy(person1.name, "John");
    person1.age = 25;
    person1.height = 1.75;

    // 输出结构体的成员
    printf("Name: %s\n", person1.name);
    printf("Age: %d\n", person1.age);
    printf("Height: %.2f\n", person1.height);

    return 0;
}

在上述示例中,我们定义了一个名为Person的结构体,它包含了姓名、年龄和身高三个成员变量。然后,我们创建了一个名为person1的结构体变量,并给它的成员赋值。最后,使用printf函数输出结构体的成员值。

结构体数组

  • 作用:将自定义的结构体放入数组中方便维护
  • 语法:
    struct 结构体名 数组名[元素个数] = {{}, {}, …{}}
    示例:
#include<stdio.h>

struct stu
{
	char name[16];
	int age;
	float score;
}s[3];

int main()
{
	struct stu s[3] = {{"zhangsan",18,500},{"lisi",18,530},{"wangwu",18,550}};
	int i;

	for (i = 0; i < 3; i++)
	{
		printf("name=%s, age=%d, score=%f\n",s[i].name,s[i].age,s[i].score);
	}

	return 0;
}

结构体指针

  • 作用:通过指针访问结构体的成员
  • 语法:struct 结构体名 *指针名;
  • 利用操作符->可以通过结构体指针访问结构体属性(比如s.name 有一个指针 ps 指向 s ,那么可以用 ps->name 代替 s.name

示例:
结构体数组和结构体指针

#include<stdio.h>

struct stu
{
	char name[16];
	int age;
	float score;
}s[3];

int main()
{
	struct stu s[3] = {{"zhangsan",18,500},{"lisi",18,530},{"wangwu",18,550}};
	struct stu *ps = s;//定义一个指针指向结构体数组
	int i;

	for (i = 0; i < 3; i++)
	{
		printf("name=%s, age=%d, score=%f\n",(*(ps+i)).name,(*(ps+i)).age,(*(ps+i)).score);
	}

	return 0;
}

在上面的代码中,一定要记得 (*(ps+i)) 才是一个大括号里面的值,这样才能 .name .age .score 。

结构体嵌套结构体

  • 含义
    结构体中的成员可以是另一个结构体
  • 语法
struct 结构体名 
{
	struct 结构体名 成员名;
};

示例:

#include <stdio.h>
#include <string.h>
 
struct person
{
    char name[16];
    int age;
    char sex;
};
 
struct  student
{
    struct person stu; 
    float score;
};
 
struct teacher
{
    struct person tea;
    char phone[12];
};
 
int main(int argc, const char *argv[])
{
    struct student s;
 
    strcpy (s.stu.name,"zhangsan");
    s.stu.age = 12;
    s.stu.sex = 'm';
    s.score = 98;
 
    printf("name = %s,age = %d, sex = %c, score = %f\n", s.stu.name, s.stu.age, s.stu.sex, s.score);
 
    struct teacher t;
    struct teacher *p = &t;
 
    strcpy (p->tea.name, "lisi");
    p->tea.age = 54; //注意这里操作符 -> 的用法
    p->tea.sex = 'w';
    strcpy (p->phone, "13112341234");
 
    printf("name = %s,age = %d, sex = %c, score = %s\n", t.tea.name, t.tea.age, t.tea.sex, t.phone);
     
    return 0;
}

上述代码中,有一个部分用到了 p->tea.age 这种形式,这是因为p是指针,而 tea 只是一个普通变量,所以从 tea 出发不能用 ->,只有指针才可以使用这个操作符。

结构体大小

字节对齐

  • 含义
    字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率。(因为如果按照类型实际的大小来判断的话,那么需要判断很多次,这样对齐了以后有规律就不用判断了)
  • 作用
    • 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    • 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

计算方法

  • 自身对齐 (这个数据类型大小是多少就是多少)
  • 默认对齐 (4字节)
  • 有效对齐 (在自身对齐和默认对齐之间选最小)
    在这里插入图片描述

规则(地址 / 有效地址) 必须是整数。

计算过程:

  1. 把结构体里每个变量的类型的自身对齐,默认对齐和有效对齐分别写出来;
  2. 以有效对齐为准写每个变量的地址,最开始那个变量的地址肯定是0,然后后面叠加,注意在这个过程中要遵从**<规则>**,比如图中的变量 b ,本来地址应该是 1 ,但是因为 1 / 4 不是整数,所以要扩充到 4 凑整,那么这个时候 变量 a 的地址浪费了 1 2 3 这三个地址,又因为 b 本身就是 4 个字节,所以它的地址是 4 5 6 7。 c 和 d 因为都可以整除有效对齐,所以每个都加 1 个字节就行;
  3. 最终看一下,有效对齐最大的是 4 ,所以每个都要以 4字节 对齐,则要在变量 d 的后面再补 2 个地址:10 和 11 (因为前面的 8 和 9 已经占了 2 个地址了,还差 2 个地址凑够 4 个地址)。
  4. 得出结果:结构体 A 的地址是 0~11 ,所以大小是 12 。

上述过程要注意:能不能整除只能决定每个变量开头的地址,具体要每一行的地址从开头的地址要写到几要看变量类型的 sizeof 是多少。比如有 double c,c的开头地址是 8 ,那么这个变量占的字节就是 8 9 10 11 12 13 14 15 这八个字节。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Day-22慢就是快】代码随想录-栈与队列-前K个高频元素

给定一个非空的整数数组&#xff0c;返回其中出现频率前 k 高的元素。 示例 1: 输入: nums [1,1,1,2,2,3], k 2输出: [1,2] 示例 2: 输入: nums [1], k 1输出: [1] ———————————————————————————————————————— 这道题目主要涉…

一文解析:共享WiFi项目到底怎么样呢?

大家都知道&#xff0c;现代社会已经离不开互联网的便利&#xff0c;而WiFi的普及更是提升了人们的生活质量和工作效率。然而&#xff0c;面对庞大的用户群体和不断增长的网络需求&#xff0c;无论人们到哪都是习惯性的连接上wifi。而共享WiFi的出现&#xff0c;正是满足了大众…

AtCoder Beginner Contest 317(D-G)

D - President (atcoder.jp) &#xff08;1&#xff09;题目大意 &#xff08;2&#xff09;解题思路 考虑到z最大不超过1e5&#xff0c;N最多不超过100&#xff0c;因此可以考虑用背包来写&#xff0c;dp[j]表示拿高桥拿j分最少需要花费多少个选民转换&#xff0c;最后把答案取…

div盒子标签

华子目录 什么是divdiv盒子模型盒模型标签属性&#xff1a;边框&#xff08;border&#xff09;怪异盒与标准盒模型 元素类型块级元素基础特性&#xff08;block&#xff09;行内元素基础特性&#xff08;inline&#xff09;行内块元素&#xff08;inline-block&#xff09;元素…

设备健康管理如何减少维护成本?

在现代制造和工业领域&#xff0c;设备健康管理已经成为降低维护成本和提高生产效率的关键策略。通过实时监测和数据分析&#xff0c;预测性维护等方法已经取得了显著的成果&#xff0c;帮助企业在维护方面实现成本效益和效率的提升。本文将以PreMaint设备数字化平台为例&#…

在线OJ的项目演示

目录 登录界面 注册界面 主界面 题目列表 编写代码界面 代码的编辑报错 正确编译 Mysql的表 登录界面 注册界面 主界面 题目列表 编写代码界面 代码的编辑报错 时间超时 空间过大 编译报错 正确编译 Mysql的表

一图看懂架构划分原则:技术划分 OR 领域划分?

架构划分原则 技术划分 描述: 按技术用途组织系统组件典型示例: 分层(多层)架构 组件按技术层组织 用户界面: 与用户直接交互的部分业务规则和核心处理: 逻辑和算法与数据库交互: 数据存取和查询数据库层: 数据存储和管理 优点: 当大部分更改与技术层次对齐时适用 缺点: 域更…

problem(4)一听就懂字符集、ASCII、GBK、UTF-8、Unicode、乱码、字符编码、解码问题的讲解

程序员在开发中&#xff0c;肯定要与数据打交道&#xff0c;很多时候遇到乱码&#xff0c;或者通信时&#xff0c;或者读写数据时&#xff0c;一头雾水&#xff0c;根本原因就是因为没有搞明白字符集&#xff0c;如ASCII、GBK、Unicode、UTF-8、字符编码、解码、乱码问题。现在…

交换机介绍

什么是交换机&#xff1f; 交换机&#xff0c;英文名称为Switch&#xff0c;也称为交换式集线器&#xff0c;它是一种基于MAC地址(网卡的硬件地址)识别&#xff0c;能够在通信系统中完成信息交换功能的设备。 交换机的工作特点 拥有一条很高带宽的背板总线和内部交换矩阵 所有…

springboot集成es 插入和查询的简单使用

第一步&#xff1a;引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId><version>2.2.5.RELEASE</version></dependency>第二步&#xff1a;…

Linux 最常用命令:能解决 95% 以上的问题

来源&#xff1a;blog.csdn.net/qq_43647359 /article/details/104792569 操作系统概述 Linux 操作系统安装 Linux 文件系统 Linux 命令操作 Linux 权限管理 用户和用户组 用户操作命令 权限操作 Linux 进程管理 Linux 其他常用命令大全 Linux 系统软件安装 常用软件…

***一种改版后检查硬件PCB生产资料的方法***,简单实用,且不容易出错

一、前言 硬件电路设计改版是常有的事,不管小的实物,还是需求变更经常会遇到要增加或者减少器件,修改走线这些。在第一版已经做了生产资料投板的情况下,可以和第一板对比一下就知道改了哪些地方,怎么才能快速的定位出来改动点并检查是否更改呢。 有的人是通过PCB文件来检…

老Python程序员职业生涯感悟—写给正在迷茫的你

我来讲几个极其重要&#xff0c;但是大多数Python小白都在一直犯的思维错误吧&#xff01;如果你能早点了解清楚这些&#xff0c;会改变你的一生的。所以这一期专门总结了大家问的最多的&#xff0c;关于学习Python相关的问题来给大家聊。希望能带给大家不一样的参考。或者能提…

Java底层起步

Java底层起步 Java介绍 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQ6tQLFm-1693272724323)(./Java介绍.png)] 什么是面向对象&#xff1f; 例如&#xff1a;小戴正在做饭时&#xff0c;发现没酱油了&#xff0c;对着外面的朋友小张说&#…

使用亥姆霍兹线圈的注意事项

亥姆霍兹线圈由一对完全相同的圆形导体线圈组成。采用直角坐标系&#xff0c;两个半径为R的圆形线圈的中心轴与z轴同轴。两个圆形线圈的z坐标分别为和。每个导体线圈都有相同的电流I。 设置可以减少两个线圈中心O(即原点)的磁场不均匀性。这种动作促使&#xff0c;也意味着非零…

ssm+vue校园活动管理平台源码和论文

ssmvue校园活动管理平台源码和论文090 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 使用旧方法对校园活动信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在校园活动信…

使用Python进行可视化呈现

热搜榜是一个反映社会热点话题的实时排行榜。通过监控、分析和可视化 热搜数据&#xff0c;我们可以了解当前的热点事件、舆论走向以及用户关注度。本文将介绍如何使用Python进行 热搜排名监控、分析与可视化呈现。 一、环境准备 首先&#xff0c;确保您已经安装了Python环境。…

Vue3 Element-plus Upload 上传图片

技术栈&#xff1a;Vue3 Ts Element-plus 官网地址&#xff1a;Upload 上传 | Element Plus 一、背景&#xff1a; 表单上传图片功能 二、效果&#xff1a; 三、流程&#xff1a; ①点击上传图片按钮&#xff0c;系统弹出文件选择对话框&#xff0c;选择图片并确认 ②调…

vscode编译C语言

首先把c文件拖到vscode中 然后安装这个插件 安装完毕后会提示你代码中的语法错误&#xff0c;并在编译器的右上角出现编译按钮 我当前的问题是没有GCC&#xff0c;我们点一下编译的按钮也可以看出来这个问题 在 django笔记中 附录二 windows上直接安装uwsgi(不可行) 附录二 win…

c刷题(三)

程序运行结果 int a, b, c; a 5; c a; b c, c, a, a; b a c; printf("a %d b %d c %d\n", a, b, c); line3&#xff1a;c6&#xff0c;a6&#xff1b; line4&#xff1a;(逗号表达式&#xff0c;从左向右计算&#xff0c;结果为最后一个表达式)c8&#xff…