c语言之结构

今天来说一下C语言里的结构体(struct)、共用体(l联合体)union、枚举。
欢迎加入嵌入式学习群:559601187

(一)结构体:struct

1.1 概念

  • 是一种自定义的数据类型
  • 结构体是构造类型的一种
  • 不同数据类型的集合
  • 地址空间连续,每次分配最大数据类型的宽度
  • 占用内存为所有变量的总大小(注意字节对齐问题)

1.2 定义

1.先定义结构体类型,再说明结构体变量

struct stu
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
};
struct stu  student;

上面的程序使用strcuct关键字定义了一个结构体名为stu的结构体类型。和定义变量一样,声明一个结构体类型变量可以使用:数据类型 变量名 的形式。
struct stu student表示定义了一个变量名为stduent,类型为stu的结构体。该结构体含有4个成员:name、num、age、score
注意大括号后面的分号;不能少,这是一条完整的语句。
2.定义结构体类型的同时定义结构体变量

struct stu
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
}student;

在定义时直接声明结构体变量,只需要将结构体变量名放在花括号后面,并加上分号即可。
3.直接说明结构体变量

struct 
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
} student;

这种定义方式并不常用,这样做书写虽然简单,但是因为没有结构体名,后面就没法用该结构体定义新的变量。
4.typedef重定义

typedef struct 
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
} STU;
STU student;

这种方式比较常见,我们使用typedef重定义结构体为STU,这里STU就是此结构体类型,可以用STU去定义结构体变量

1.3 初始化

1.在定义结构体变量的时候全部初始化

struct stu
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
}student={“ha”,1234,56,99};

2.定义完结构体变量后,之后只能单个赋值

struct stu
{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
};
struct stu  student;
student.name="ha";
student.num=1234;
student.age=56;
student.score=99;

1.4 调用

结构体变量.成员

结构体变量名+点(’.’)+成员就可以调用了

1.5 结构体指针

当一个指针变量指向结构体时,我们就称它为结构体指针。C语言结构体指针的定义形式一般为:

struct 结构体名 *变量名;
//结构体
struct stu{char *name;  //姓名int num;  //学号int age;  //年龄float score;  //成绩
} stu1 = { "hah", 12, 18, 23, 136.5 };
//结构体指针
struct stu *pstu = &stu1;

注意结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给 pstu 赋值只能写作:

1.6 获取结构体成员

通过结构体指针可以获取结构体成员,一般形式为:

(*pointer).memberName

或者:

pointer->memberName

第一种写法中,.的优先级高于*,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于*(pointer.memberName),这样意义就完全不对了。

第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。

1.7 结构体内存分析

注意点

  1. 给整个结构体变量分配储存空间和数组一样,从内存地址比较大的开始分配
  2. 给结构体变量中的属性分配储存空间也和数组一样,从所占内存地址比较小的开始分配
  3. 定义结构体类型不会分配储存空间,只有定义结构体变量的时候才会分配储存空间
  • 结构体在分配内存的时候,会做一个内存对齐的操作
  • 会先获取所有属性中占用内存最大的属性的字节数
  • 然后在开辟出最大属性字节的内存给第一个属性,如果分配给第一个属性之后还能继续分配给第二个属性,那么就继续分配给第二个属性
  • 如果分配给第一个属性之后,剩余的内存不够分配给第二个属性了,那么会再次开辟最大属性的内存,再次分配 依次类推
#include <stdio.h>int main(){//定义结构体struct Person{char name; // 1 个节点  //开辟4个字节 char 占用1个int age;  // 4个字节   // 剩余三个 不够int  再开辟4个字节int money; // 4个字节 // 再开辟4个字节};struct Person p; // 所以p = 4+4+4printf("sizeof(p) = %i\n",sizeof(p)); // 12个字节return 0;
}

(二)共用体(联合体):union

2.1概念

  • 所有变量共用一段空间
  • 每次分配按最大长度进行分配
  • 是一种构造数据类型
  • 同一时刻只能保存一个成员的值
  • 不能直接引用共用体变量名

2.2定义

它的定义和结构体一样,分为先定义共用体再说明共用体变量、在定义共用体的同时说明共用体变量、直接说明共用体变量

union 共用体名{成员列表
};

示例:

//先定义共用体再说明共用体变量
union data{int n;char ch;double f;
};
union data a, b, c;

2.3 引用

和结构体一样,通过共用体变量名 . 成员名

union data{int n;char ch;double f;
} a, b, c;
a.n=3;

关于共用体的详细介绍可以看下这篇文章C语言共用体(C语言union用法)详解,讲到共用体这里要说明一下大小端模式的问题。
大小端
小端模式:低地址存放低字节,高地址存放高字节
大端模式:低地址存放高字节,高地址存放低字节

(三)枚举:enum

3.1 概念

  • 作用:列举出所有的可能性,增强代码的可阅读性
  • 枚举成员都是常量
  • 不能再对已经定义好的枚举常量赋值

3.1 定义

enum 枚举名 
{
枚举变量
};

示例:

enum week
{ 
Mon, Tues, Wed, Thurs, Fri, Sat, Sun};
typedef enum
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
}Date;

枚举是一种类型,通过它可以定义枚举变量:

Date a,b,c

我们也可以给每个名字都指定一个值:

enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };

更为简单的方法是只给第一个名字指定值:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };

这样枚举值就从 1 开始递增,跟上面的写法是等效的。
也可以在定义枚举类型的同时定义变量:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;

有了枚举变量,就可以把列表中的值赋给它:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;

或者:

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;

特点:可以在定义枚举时给成员赋值,被赋值的成员往后依次增加1,也可以在中间改变某一个成员的值。

3.1 引用

直接使用就行,需要注意的是**枚举列表中的数据作用范围是全局的,不能在定义与它们名字相同的白能量;Mon、Tues、Wed 等都是常量,不能对它们赋值,只能将它们的值赋给其他的变量。
示例:

#include <stdio.h>
int main(){enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;scanf("%d", &day);switch(day){case 1: puts("Monday"); break;case 2: puts("Tuesday"); break;case 3: puts("Wednesday"); break;case 4: puts("Thursday"); break;case 5: puts("Friday"); break;case 6: puts("Saturday"); break;case 7: puts("Sunday"); break;default: puts("Error!");}return 0;
}

Mon、Tues、Wed 这些名字都被替换成了对应的数字。这意味着,Mon、Tues、Wed 等都不是变量,它们不占用数据区(常量区、全局数据区、栈区和堆区)的内存,而是直接被编译到命令里面,放到代码区,所以不能用&取得它们的地址。这就是枚举的本质。


本文章仅供学习交流用禁止用作商业用途,文中内容来水枂编辑,如需转载请告知,谢谢合作

微信公众号:zhjj0729

微博:文艺to青年

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

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

相关文章

C语言实现音乐播放器(Linux madplay)

&#xff08;一&#xff09;需求分析 1.扫描指定路径下的音乐&#xff0c;并显示出来 2.实现音乐的播放、暂停、上一首和下一首的功能 3.程序退出释放内存资源 &#xff08;二&#xff09;思路 1.扫描出指定路径下的音乐文件(便利指定文件夹&#xff0c;找出音频文件放在数组…

虚拟机中安装linux

&#xff08;一&#xff09;前言 就在昨天电脑的固态突然崩掉&#xff0c;无奈重新把系统装在的以前的硬盘上&#xff0c;为了能够继续工作重新配置嵌入式linux系统开发环境&#xff0c;本教程主要记录在虚拟机中安装linux。 &#xff08;二&#xff09;环境准备 虚拟机&…

Ubuntu设置root登录

1.、Ubuntu 管理员用户 root 默认没有密码&#xff0c;在使用前最好添加密码&#xff0c;使用指令&#xff1a; sudo passwd root 注意&#xff1a;命令行输入密码时不显示&#xff0c;输入时需注意密码的准确性&#xff1b; 2、Ubuntu 想要用 root 帐户登录&#xff0c;可在普…

vim配置之spacevim

为了更好的利用vim&#xff0c;我们一般需要自己配置&#xff0c;今天介绍了一下经常用的spacevim &#xff08;一&#xff09;配置环境 Ubuntu16.04vim 7.4版本以上(必须&#xff01;&#xff01;) &#xff08;二&#xff09;安装spacevim 1.检查vim的版本&#xff1a; v…

Ubuntu更换gnome桌面环境后不能root登录

安装完Ubuntu后感觉界面有点丑陋&#xff0c;安装了gnome桌面环境试一下 sudo apt-get install gnome-shell sudo apt-get install ubuntu-gnome-desktop如果选择了lightdm后可以使用sudo dpkg-reconfigure gdm3 重新改回gdm3 sudo apt-get install unity-tweak-tool sudo ap…

Ubuntu下安装tilix终端仿真器

安装环境 Ubuntu 16.04 操作步骤 首先添加这个终端模拟器仓库的公钥。这里我都是以root超级用户权限操作的&#xff0c;如果没有的话&#xff0c;请在命令前面加sudo。 add-apt-repository ppa:webupd8team/terminixapt update安装Tilix。 apt install tilix安装完成测试结…

vim配置之snippets代码块

&#xff08;一&#xff09;目的 我们在编写程序的过程中&#xff0c;经常会敲一些重复的代码&#xff0c;我们可以利用snippets来达到输入简写来敲出完整的代码 &#xff08;二&#xff09;安装步骤 安装使用Vundle,没有vbundle的先执行下面的命令 git clone https://gith…

c语言实现跳动的心

本文章分为两部分&#xff1a;第一部分为实现多彩的心&#xff0c;第二部分是实现心得跳动&#xff0c;两个代码均独立运行 本篇文章转载自公众号&#xff1a; C语言程序设计基础知识 &#xff08;一&#xff09;C语言实现多彩的心 实现过程其实很简单 首先使用for循环绘制心…

Linux下使用消息队实现 ATM 自动取款机功能

文章分五部分&#xff1a;需求分析、项目所需知识点、思路讲解、代码实现、功能演示 本文内容较长&#xff0c;建议是按照我自己的思路给大家讲解的&#xff0c;如果有其他问题&#xff0c;欢迎评论区讨论 文章中的代码是在linux下编译实现的&#xff0c;注意自己的环境。 &…

200行代码实现视频人物实时去除

今天在GitHub上发现了一个好玩的代码&#xff0c;短短几百行代码就实现了从复杂的背景视频中去除人物&#xff0c;不得不说这位大佬比较厉害。 这个项目只需要在网络浏览器中使用JavaScript&#xff0c;用200多行TensorFlow.js代码&#xff0c;就可以实时让视频画面中的人物对…

codeforces C. Vanya and Scales

C. Vanya and ScalesVanya has a scales for weighing loads and weights of masses w0, w1, w2, ..., w100 grams where w is some integer not less than 2(exactly one weight of each nominal value). Vanya wonders whether he can weight an item with mass m using …

菱形继承和虚继承、对象模型和虚基表

1.菱形继承&#xff08;钻石继承&#xff09;&#xff1a;两个子类继承同一父类&#xff0c;而又有子类同时继承这两个子类。例如B,C两个类同时继承A&#xff0c;但是又有一个D类同时继承B,C类。 2.菱形继承的对象模型 class A { public:int _a; };class B :public A { p…

c++虚函数和虚函数表

前言 &#xff08;1&#xff09;虚基表与虚函数表是两个完全不同的概念 虚基表用来解决继承的二义性(虚基类可以解决)。虚函数用来实现泛型编程&#xff0c;运行时多态。 &#xff08;2&#xff09;虚函数是在基类普通函数前加virtual关键字&#xff0c;是实现多态的基础 &a…

VS2017安装配置Qt

这篇文章作为qt的开发环境配置篇&#xff0c;记录如何在vs2017中安装qt的 所需软件下载链接如下&#xff1a; QT下载链接&#xff1a;QT visual studio下载链接&#xff1a;visual studio 这里推荐安装最新的&#xff0c;原因是vs2017不支持一些老版本的makefile文件生成&#…

STM32位带区和位带别名区的浅谈

1.首先谈下为什么要使用位带&#xff1f; 在学习51单片机时就已经使用过位操作&#xff0c;比如使用sbit对单片机IO口的定义&#xff0c;但是STM32中并没有这类关键字&#xff0c;而是通过访问位带别名区来实现&#xff0c;即通过将每个比特位膨胀成一个32位字&#xff0c;当访…

Hibernate的数据查找,添加!

1.首先看一下测试数据库的物理模型 2.测试所需要的Hibernate的jar包 3.数据库的sql /**/ /* DBMS name: MySQL 5.0 */ /* Created on: 2015/7/3 23:17:57 */ /**/drop table if exists books;drop tab…

新手如何在Altium Designer中绘制电路板

好久没用AD画电路板了&#xff0c;这次电子实训让画个PCB板&#xff0c;借着这个机会写了一篇新手教程。 此教程所用的电路图是自动循迹小车&#xff0c;虽然元件比较简单&#xff0c;但是感觉还是很厉害的&#xff0c;一块看一下吧。 此教程仅适用于没有基础的同学 一、概述 …

Qt模仿QQ登录界面(一)

这两天研究qt&#xff0c;练习时做了个仿QQ登录界面&#xff0c;我这次实现的比较简单&#xff0c;先在这里记录一下&#xff0c;以后有空了会继续完善的。 &#xff08;一&#xff09;效果图 这里使用我的qq号测试的如图&#xff1a; &#xff08;二&#xff09;工程文件 &…

回流焊和波峰焊的区别

本文首先分别介绍回流焊和波峰焊的特点&#xff0c;然后对两者进行比较&#xff0c;欢迎评论补充哦~ 最近在实习看到了厂里面的回流焊的波峰焊&#xff0c;有点好奇就查了点资料&#xff0c;分享给同样爱学习的你。 一.回流焊 一般的表面贴装工艺分三步&#xff1a;印刷机施加…

三对角矩阵的压缩

三对角矩阵&#xff0c;从第二行开始选中的元素的个数都为3个。对于a[i,j]将要存储的位置k&#xff0c;首先前(i-1)行元素的个数是(i-2)*3 2(第一行元素的个数为2)&#xff0c;又a[i,j]属于第i行被选中元素的第j-i1个元素&#xff0c;所以k (i-2)*3 2 j-i1 2*ij-3 如果知道了…