C语言学习笔记-9

九、结构体

构造类型

不是基本类型的数据结构也不是指针类型, 它是若干个相同或不同类型的数据构成的集合

结构体类型

结构体是一种构造类型的数据结构,是一种或多种基本类型或构造类型的数据的集合。

1.结构体类型定义

定义:

(1).先定义结构体类型, 再去定义结构体变量

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

struct stu{
int num;
char name[20];
char sex;
};
//有了结构体类型后, 就可以用类型定义变量了
struct stu lucy,bob,lilei;//定义了三个 struct stu 类型的变量,每个变量都有三个成员, 分别是 num name sex

(2).在定义结构体类型的时候顺便定义结构体变量, 以后还可以定义结构体变量

struct 结构体类型名{
成员列表;
}结构体变量 1,变量 2;

struct 结构体类型名 变量 3, 变量 4;

struct stu{
int num;
char name[20];
char sex;
}lucy,bob,lilei;
struct stu xiaohong,xiaoming;
无结构体类型名

在定义结构体类型的时候, 没有结构体类型名, 顺便定义结构体变量,

因为没有类型名, 所以以后不能再定义相关类型的数据了

struct {
成员列表;
}变量 1, 变量 2;

struct {
int num;
char name[20];
char sex;
}lucy,bob;
//以后没法再定义这个结构体类型的数据了, 因为没有类型名
最常用:

通常咱们将一个结构体类型重新起个类型名, 用新的类型名替代原先的类型

typedef struct stu{
int num;
char name[20];
char sex;
}STU;
//以后 STU 就相当于 struct stu
STU lucy;struct stu lucy;是等价的。

2.结构体变量的定义初始化及使用

1、 结构体变量的定义和初始化

(1):在定义结构体变量之前首先得有结构体类型, 然后再定义变量
(2):在定义结构体变量的时候, 可以顺便给结构体变量赋初值, 被称为结构体的初始化
(3):结构体变量初始化的时候, 各个成员顺序初始化

struct stu{
int num;
char name[20];
char sex;
};struct stu boy;
struct stu lucy={
101,
"lucy",
'f'
};
//结构体内后面的变量可以不初始化,中间的变量必须初始化

2、 结构体变量的使用

(1).结构体变量成员的引用方法 :结构体变量.成员名

struct stu{
int num;
char name[20];
char sex;
char* addr;
};
struct stu bob;
bob.num=101;//bob 是个结构体变量,但是 bob.num 是个 int 类型的变量
bob.name 是个字符数组,是个字符数组的名字,代表字符数组的地址,是个常量
//bob.name ="bob";是不可行,是个常量
strcpy(bob.name,"bob");strcpy(bob.addr,"beijing")//错误,bob.addr是个野指针
bob.addr="beijing";//正确
#include <stdio.h>
struct stu{
int num;
char name[20];
int score;
char *addr;
};
int main(int argc, char *argv[])
{
struct stu bob;
printf("%d\n",sizeof(bob));
printf("%d\n",sizeof(bob.name));
printf("%d\n",sizeof(bob.addr));
return 0;
}
//结构体大小,为各元素的大小之和

3、相同类型的结构体变量相互赋值

#include <stdio.h>
struct stu{
int num;
char name[20];
char sex;
};int main(int argc, char *argv[])
{
struct stu bob={101,"bob",'m'};
struct stu lilei;
lilei=bob;//类型相同
printf("%d %s %c\n",lilei.num,lilei.name,lilei.sex);
return 0;
}

3.结构体数组

结构体数组是个数组, 由若干个相同类型的结构体变量构成的集合

1、结构体数组的定义方法

struct 结构体类型名 数组名[元素个数];

struct stu{
int num;
char name[20];
char sex;
};
struct stu edu[3];//定义了一个 struct stu 类型的结构体数组 edu,
这个数组有3个元素分别是 edu[0]、 edu[1]、edu[2]

结构体数组元素的引用: 数组名[下标]

数组元素的使用

edu[0].num =101;//用 101 给 edu 数组的第 0 个结构体变量的 num 赋值
strcpy(edu[1].name,"lucy");
#include <stdio.h>
typedef struct student
{
int num;
char name[20];
float score;
}STU;
STU edu[3]={
{101,"Lucy",78},
{102,"Bob",59.5},
{103,"Tom",85}
};
int main()
{
int i;
float sum=0;
for(i=0;i<3;i++)
{sum+=edu[i].score;} 
printf("平均成绩为%f\n",sum/3);
return 0;
}

4.结构体指针

即结构体的地址, 结构体变量存放内存中, 也有起始地址。咱们定义一个变量来存放这个地址, 那这个变量就是结构体指针变量。
结构体指针变量也是个指针, 既然是指针在 32 位环境下, 指针变量的占 4 个字节, 存放一个地址编号。

1、 结构体指针变量的定义方法:

struct 结构体类型名 * 结构体指针变量名;

struct stu{
int num;
char name[20];
};
struct stu * p;//定义了一个 struct stu *类型的指针变量
//变量名是p,p占4个字节,用来保存结构体变量的地址编号
struct stu boy;
p=&boy;boy.num=101;//可以,通过 结构体变量名.成员名
(*p).num=101;//可以,*p 相当于 p 指向的变量 boy
p->num=101;//可以,指针->成员名
//通过结构体指针来引用指针指向的结构体的成员, 前提是指针必须先指向一个结构体变量。

2、应用场景

(1): 保存结构体变量的地址

typedef struct stu{
int num;
char name[20];
float score;
}STU;int main()
{
STU *p,lucy;
p=&lucy;
p->num=101;
strcpy(p->name,"baby");
//p->name="baby";//错误,因为 p->name 相当于 lucy.name 是个字符数组的名字,是个常量
}

(2): 函数传结构体变量的地址

#include<stdio.h>
#include<string.h>
typedef struct stu{
int num;
char name[20];
float score;
}STU;
void fun(STU *p)
{
p->num=101;
(*p).score=87.6;
strcpy(p->name,"lucy");
} int main()
{
STU girl;
fun(&girl);
printf("%d %s %f\n",girl.num,girl.name,girl.score);
return 0;
}

(3): 传结构体数组的地址

结构体数组, 是由若干个相同类型的结构体变量构成的集合。 存放在内存里,
也有起始地址, 其实就是第 0 个结构体变量的地址。

#include<stdio.h>
#include<string.h>
typedef struct stu{
int num;
char name[20];
float score;
}STU;
void fun(STU *p)
{
p[1].num=101;
(*(p+1)).score=88.6;
}
int main()
{
STU edu[3];
fun(edu);
printf("%d %f\n",edu[1].num,edu[1].score);
return 0;
}
注意:

(1): 结构体变量的地址编号和结构体第一个成员的地址编号相同, 但指针的类型不同

#include <stdio.h>
typedef struct stu{
int num;
char name[20];
int score;
}STU;
int main(int argc, char *argv[])
{
STU bob;
printf("%p\n",&bob);//STU*
printf("%p\n",&(bob.num));//int*
return 0;
}

(2): 结构体数组的地址就是结构体数组中第 0 个元素的地址

#include <stdio.h>
struct stu{
int num;
char name[20];
int score;
};int main(int argc, char *argv[])
{
struct stu edu[3];
printf("%p\n",edu);//struct stu *
printf("%p\n",&(edu[0]));//struct stu *
printf("%p\n",&(edu[0].num));//int *
return 0;
}//各地址相同

5.结构体内存分配

规则 1: 以多少个字节为单位开辟内存

(1): 成员中只有 char 型数据 , 以 1 字节为单位开辟内存。
(2): 成员中出现了 short int 类型数据, 没有更大字节数的基本类型数据。以 2 字节为单位开辟内存
(3): 出现了 int ,float 没有更大字节的基本类型数据的时候以 4 字节为单位开辟内存。
(4): 出现了 double 类型的数据
情况 1:
在 vc6.0 和 Visual Studio 中里, 以 8 字节为单位开辟内存。
情况 2:
在 Linux 环境 gcc 里, 以 4 字节为单位开辟内存。
无论是那种环境, double 型变量, 占 8 字节。

(5):如果出现指针的话, 没有占字节数更大的类型的, 以 4 字节为单位开辟内存。

struct stu{
char sex;
int age;
}lucy;
//lucy 的大小是 4 的倍数。

规则 2: 字节对齐

(1): char 1 字节对齐 , 即存放 char 型的变量, 内存单元的编号是 1 的倍数即可。
(2): short int 2 字节对齐 , 即存放 short int 型的变量, 起始内存单元的编号是 2 的倍数即可。

(3): int 4 字节对齐 , 即存放 int 型的变量, 起始内存单元的编号是 4 的倍数即可
(4): long int 在 32 位平台下,4 字节对齐,即存放 long int 型的变量, 起始内存单元的编号是 4
的倍数即可
(5): float 4 字节对齐 , 即存放 float 型的变量, 起始内存单元的编号是 4 的倍数即可
(6): double
vc6.0 和 Visual Studio 环境下
8 字节对齐, 即存放 double 型变量的起始地址, 必须是 8 的倍数, double 变量占 8 字节

gcc 环境下
4 字节对齐, 即存放 double 型变量的起始地址, 必须是 4 的倍数, double 变量占 8 字节。

注意 3: 当结构体成员中出现数组的时候, 可以看成多个变量。
注意 4: 开辟内存的时候, 从上向下依次按成员在结构体中的位置顺序开辟空间

#include<stdio.h>
struct stu{
char a;
short int b;
int c;
}temp;
int main()
{
printf("%d\n",sizeof(temp));
printf("%p\n",&(temp.a));
printf("%p\n",&(temp.b));
printf("%p\n",&(temp.c));
return 0;
}

在这里插入图片描述

结果分析:
a 的地址和 b 的地址差 2 个字节
b 的地址和 c 的地址差 2 个字节

#include<stdio.h>
struct stu{
char a;
int c;
short int b;
}temp;
int main()
{
printf("%d\n",sizeof(temp));
printf("%p\n",&(temp.a));
printf("%p\n",&(temp.b));
printf("%p\n",&(temp.c));
return 0;
}

在这里插入图片描述

结果分析:
a 和 c 的地址差 4 个字节
c 和 b 的地址差 4 个字节

struct stu{
char buf[10];
int a;
}temp;
//temp 占 16 个字节

在这里插入图片描述

在 vc 和 Visual Studio 中占 16 个字节 a 和 b 的地址差 8 个字节
在 gcc 中占 12 个字节 a 和 b 的地址差 4 个字节
#include<stdio.h>
struct stu{
char a;
double b;
}temp;
int main()
{
printf("%d\n",sizeof(temp));
printf("%p\n",&(temp.a));
printf("%p\n",&(temp.b));
return 0;
}

在这里插入图片描述

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

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

相关文章

Test——BUG篇

目录 一软件测试的生命周期 二BUG 1概念 2描述Bug 3Bug级别 4Bug的生命周期 三与开发人员发生争执怎么办 ​编辑1先自省&#xff1a;是否Bug描述不清晰 2站在用户角度考虑并抛出问题 3Bug定级有理有据 4不仅要提出问题&#xff0c;还要给出解决方案 5Bug评审 5.1…

【Block总结】HWAB,半小波注意力块|即插即用

论文信息 标题: HALF WAVELET ATTENTION ON M-NET+ FOR LOW-LIGHT IMAGE ENHANCEMENT 地址: arXiv:2203.01296 日期: 2022年3月 创新点 改进的分层架构 M-Net+: 提出了一个专为低光图像增强设计的改良分层模型 M-Net+。该架构旨在缓解采样过程中的空间信息损失问题。通过采用…

Spring 中的事务

&#x1f9fe; 一、什么是事务&#xff1f; &#x1f9e0; 通俗理解&#xff1a; 事务 一组操作&#xff0c;要么全部成功&#xff0c;要么全部失败&#xff0c;不能只做一半。 比如你转账&#xff1a; A 账户扣钱B 账户加钱 如果 A 扣了钱但 B 没收到&#xff0c;那就出问…

Flutter极速接入IM聊天功能并支持鸿蒙

Flutter极速接入IM聊天功能并支持鸿蒙 如果你们也是Flutter项目&#xff0c;想快速接入聊天&#xff0c;包括聊天的UI界面&#xff0c;强烈推荐这一家。因为我们已经完成了集成&#xff0c;使用非常稳定&#xff0c;集成也非常快捷方便。 而且&#xff0c;就在今天&#xff0c…

C# 类库生成后自动复制到指定目录

C# 类库生成后自动复制到指定目录 在C#中,当你开发了一个类库项目(通常是.NET Core或.NET Framework项目),你可能会希望在构建(Build)完成后自动将生成的DLL文件复制到指定的目录。有几种方法可以实现这个需求,下面是一些常用的方法: 方法1:使用MSBuild的AfterBuild…

13-产品经理-产品多分支平台管理

禅道16.0版本开始&#xff0c;优化和增强了产品的分支/平台功能&#xff0c;主要特点如下&#xff1a; 多分支/平台功能兼容各种大小型项目&#xff0c;项目/迭代可以关联对应产品的某个分支/平台。分支/平台支持灵活管理&#xff0c;可以把分支/平台理解为时间层面的概念&…

手搓多模态-04 归一化介绍

在机器学习中&#xff0c;归一化是一个非常重要的工具&#xff0c;它能帮助我们加速训练的速度。在我们前面的SiglipVisionTransformer 中&#xff0c;也有用到归一化层&#xff0c;如下代码所示&#xff1a; class SiglipVisionTransformer(nn.Module): ##视觉模型的第二层&am…

Qt 入门 1 之第一个程序 Hello World

Qt 入门1之第一个程序 Hello World 直接上操作步骤从头开始认识&#xff0c;打开Qt Creator&#xff0c;创建一个新项目&#xff0c;并依次执行以下操作 在Qt Creator中&#xff0c;一个Kits 表示一个完整的构建环境&#xff0c;包括编译器、Qt版本、调试器等。在上图中可以直…

深入理解MySQL:核心特性、优化与实践指南

MySQL是一个开源的关系型数据库管理系统(RDBMS)&#xff0c;由瑞典MySQL AB公司开发&#xff0c;目前属于Oracle公司。它是目前世界上最流行的开源数据库之一&#xff0c;广泛应用于各种规模的Web应用和企业系统中。 目录 一、核心特点 关系型数据库&#xff1a; 开源免费&am…

Linux 系统安装与优化全攻略:打造高效开发环境

一、开篇引言 &#xff08;一&#xff09;Linux 系统的广泛应用 Linux 凭借其开源、稳定且安全的特性&#xff0c;在服务器、嵌入式设备以及开发环境等领域都有着极为广泛的应用。 &#xff08;二&#xff09;撰写本文的目的 为读者提供一套全面且实用的指南&#xff0c;助…

代码训练day22回溯算法p1

1.组合 &#xff08;1&#xff09;模板 void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择&#xff1a;本层集合中元素&#xff08;树中节点孩子的数量就是集合的大小&#xff09;) {处理节点;backtracking(路径&#xff0c;选择列表); // 递归回溯&#…

2024华为OD机试真题-任务最优调度(C++/Java/Python)-E卷-200分

2024华为OD机试最新E卷题库-(D卷+E卷)-(JAVA、Python、C++) 目录 题目描述 输入描述 输出描述 用例1 考点 题目解析 代码 c++ java python 题目描述 给定一个正整数数组表示待系统执行的任务列表,数组的每一个元素代表一个任务,元素的值表示该任务的类型。请计算执…

每日习题:20250407

2025 2025 2025年 04 04 04月 06 06 06日 题目 1 设 X X X是实随机变量&#xff0c;任意光滑的函数 f : R → R f:\mathbf{R} \rightarrow \mathbf{R} f:R→R&#xff0c;都有&#xff1a; E ( X f ( X ) ) E ( f ′ ( X ) ) E\left(Xf(X)\right)E\left(f(X)\right) E(Xf(X)…

TensorRT 有什么特殊之处

一、TensorRT的定义与核心功能 TensorRT是NVIDIA推出的高性能深度学习推理优化器和运行时库&#xff0c;专注于将训练好的模型在GPU上实现低延迟、高吞吐量的部署。其主要功能包括&#xff1a; 模型优化&#xff1a;通过算子融合&#xff08;合并网络层&#xff09;、消除冗余…

JCR一区文章,壮丽细尾鹩莺算法Superb Fairy-wren Optimization-附Matlab免费代码

本文提出了一种新颖的基于群体智能的元启发式优化算法——壮丽细尾鹩优化算法&#xff08;SFOA&#xff09;,SFOA从精湛的神仙莺的生活习性中汲取灵感。融合了精湛的神仙莺群体中幼鸟的发育、繁殖后鸟类喂养幼鸟的行为以及它们躲避捕食者的策略。通过模拟幼鸟生长、繁殖和摄食阶…

使用Ubuntu18恢复群晖nas硬盘数据外接usb

使用Ubuntu18恢复群晖nas硬盘数据外接usb 1. 接入硬盘2.使用Ubuntu183.查看nas硬盘信息3. 挂载nas3.1 挂载损坏nas硬盘(USB)3.2 挂载当前运行的nas 4. 拷贝数据分批传输 5. 新旧数据对比 Synology NAS 出现故障&#xff0c;DS DiskStation损坏&#xff0c;则可以使用计算机和 U…

linux 安装 mysql记录

sudo apt-get install mysql-server 一直报错&#xff0c;按照下面的终于安装出来了 这个链接 https://cn.linux-console.net/?p13784 第 1 步&#xff1a;要删除 MySQL 及其所有依赖项&#xff0c;请执行以下命令&#xff1a; sudo apt-get remove --purge mysql* 第 2 步…

UE5学习笔记 FPS游戏制作35 使用.csv配置文件

文章目录 导入.csv要求首先创建一个结构体导入配置文件读取配置 导入 .csv要求 第一行必须包含标题 第一列的内容必须不能重复&#xff0c;因为第一列会被当成行的名字&#xff0c;在数据处理中发挥类似于字典的key的作用 当前的配置文件内容如下 首先创建一个结构体 结构…

谈谈策略模式,策略模式的适用场景是什么?

一、什么是策略模式&#xff1f;​​ 策略模式&#xff08;Strategy Pattern&#xff09;属于​​行为型设计模式​​。核心思路是将一组​​可替换的算法​​封装在独立的类中&#xff0c;使它们可以在运行时动态切换&#xff0c;同时使客户端代码与具体算法解耦。它包含三个…

AGI大模型(10):prompt逆向-巧借prompt

1 提示词逆向 明确逆向提示词⼯程概念 我们可以给ChatGPT提供⼀个简洁的提示词,让它能够更准确地理解我们所讨论的“逆向提示词⼯程”是什么意思,并通过这个思考过程,帮它将相关知识集中起来,进⽽构建⼀个专业的知识领域 提示词:请你举⼀个简单的例⼦,解释⼀下逆向pro…