第九章、结构体与共用体

9.1 结构体变量定义、引用、初始化

9.1.1 结构体概述

类型回顾: int float double char int a[10] float b[100]

结构体概述:

结构体也是一种数据类型,被叫做结构体类型

结构体: 将多种不同类型的数据组到一起。目的是为了表达更丰富的信息。类似于SQL语言中的“记录”。

形式:

#include "stdio.h"
int main(){
    struct student
    {
        int num;            //学号
        char name[100];     //姓名
        int sex;            //性别, 0->女, 1->男
        int age;            //年龄
        char address[100];  //地址
    };
}

总结:

结构体类型 定义的一般形式

struct 结构体名 
{
//成员列表(可以有多个) 各个成员之间都带一个分号;
};  // 不能忘记这个分号;

9.1.2 定义结构体类型变量的方法

二: 定义结构体类型变量的方法

需要将结构体名看成一个类型名就行了,

总共有三种写法

1. 普通写法

struct  结构体名  变量名列表;

例如:
struct student s1,s2; //定义两个结构体类型变量

2. 定义结构类型的时候顺便定义了变量。变量位于} 之后 ; 之前多个变量之间使用 , 分割

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

#include "stdio.h"
int main(){
    struct student
    {
        int num;            //学号
        char name[100];     //姓名
        int sex;            //性别, 0->女, 1->男
        int age;            //年龄
        char address[100];  //地址
    **}s1,s2;**
}

1. 直接定义结构类型变量,连结构体名都省略了

struct 
{
	//成员列表
**} 变量名列表;**

说明:

  • 使用结构体,我们一般要先定义一个结构体类型,然后定义某些变量为该类型的变量。
  • 结构体内可以套结构体
struct date
{
	int month;
	int day;
	int year;
};

    struct student
    {
        int num;            //学号
        char name[100];     //姓名
        int sex;            //性别, 0->女, 1->男
        int age;            //年龄
        char address[100];  //地址
				 **struct date birthday;  //生日,结构体类型变量**
    };

int main()
{
struct student s1,s2;
}
  • 结构体内的成员变量,可以与程序中的变量名相同,彼此间不影响

9.1.3 结构体类型变量的引用

三: 结构体类型变量的引用

  • 不能将结构体变量作为一个整体进行引用,比如s1,s2都是结构体变量,但不能拿过来直接用,只能对结构体变量中的各个成员分别引用,

引用方法:

**// 结构体变量名.成员名**
**s1.num = 1; //将1赋值给s1变量中的成员num;  这个 . 叫结构成员运算符 
//该 . 运算符的优先级跟()是同级别 还有 ->**
**所以可将s1.num当成一个整体来看待**

如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级成员,只能对最低级别成员进行赋值或者存取。

#include "stdio.h"
struct date {
    int month;
    int day;
    int year;
};
struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;
    // }s1,s2;
};
int main() {
    int num; //这个名字和结构体变量的名字相同,但互不影响.
    struct student s1,s2;
    s1.num = 001; //将001赋值为s1结构体变量中的成员num.
    //
    **s1.birthday.day = 1; //如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级成员,只能对最低级别成员进行赋值或者存取。**

return 0;
}

成员变量

//成员变量,可以像普通变量一样进行各种运算
s1.age = 19;
s2.age = s1.age;
int AgeSum = s1.age + s2.age;
s1.age++; //年龄自加1,因为.的优先级最高,所以s1.age是个整体

9.1.4 结构体变量的初始化

// 成员变量也是有地址的.
//结构体名不可以有地址


// s1++  s1.birthday++  这都是错的
int *p = &s1.num;
    printf("%d",*p); //也可以使用指针变量来取得其地址

//结构体变量的初始化,定义时初始化
struct student s3 = {1003,"网速",1,19,"浦东",10,14,2018};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aw4VI4cA-1667044997212)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3520ce3c-9115-41d9-abb7-fcc7d3c06369/Untitled.png)]

9.2 结构体数组、结构体指针

9.2.1结构体数组

如何定义结构体数组

a. 单独写成一行定义

struct studeng stu[3];  //可以用的下标 0-2

b. 定义结构的时候顺便定义结构体数组


struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;

}stu[3];

c. 定义结构体数组的时候还可以同时进行初始化

一般形式:

struct student stu[] = { {…},{…},{…}};


struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
        {2019250116,"zhangsan",1,18,"2401",12,30,2000},
        {2019250119,"振华",0,22,"小区2401",11,11,1999},
        {2019250118,"郭襄",0,20,"平凉",9,23,2001}
};
printf("stu[%d]",stu[1].age);

9.2.2 结构体指针

  • 就是结构体变量的指针,这个指针肯定是指向该结构体变量所占据的内存段的起始地址
  • 结构体变量指针,也可以指向结构体数组中的元素。因为结构体数组中的每个元素就相当于一个结构体变量
#include "stdio.h"
#include "string.h"
struct date {
    int month;
    int day;
    int year;
};
struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;

};//stu[3];
int main() {

    **//结构体指针
    //就是结构体变量的指针,这个指针肯定是指向该结构体变量所占据的内存段的起始地址
    //结构体变量指针,也可以指向结构体数组中的元素。因为结构体数组中的每个元素就相当于一个结构体变量
    struct  student stu{}; //定义一个结构体变量,
    struct student *ps; //定义结构体变量的指针
    ps = &stu;
    strcpy(stu.name,"小虎");
    stu.age = 18;
    //ps已经指向了stu,stu里面的内容若改变了,就等于ps所指向的内容改变了。

    //如何通过结构体变量的指针来访问结构体变量的成员呢?两种方法:
    //1.
    (*ps).age=29; //* 与 . 的运算等级不一样, .是最高的,所以这里要用 (*ps).age
    ps -> num = 2019250119;
    //2.
    ps -> sex = 1;  //其中 -> 叫指向结构体成员运算符 .
    printf("name=%s\n",ps->name);
    printf("age=%d\n",ps->age);
    printf("num=%d\n",stu.num);
    printf("sex=%d\n",stu.sex);

    return 0;
}**

#include "stdio.h"
#include "string.h"
struct date {
    int month;
    int day;
    int year;
};
struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;

};//stu[3];
int main() {

    struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
            {2019250116,"zhangsan",1,18,"2401",12,30,2000},
            {2019250119,"振华",0,22,"小区2401",11,11,1999},
            {2019250118,"郭襄",0,20,"平凉",9,23,2001}
    };
    printf("stu[%d]",stu[1].age);

    **//演示指向结构体数组的指针**
    **struct student *ps;
    ps = stu; //数组名代表数组首地址。
    int i; //随时使用随时定义
    for(i=0;i<3;i++){
        printf("num=%d\n",ps->num);
        printf("name=%s\n",ps->name);
        printf("age=%d\n",ps->age);
        ps++; //ps指向了下一个数组元素的开始地址
        printf("-----------------\n");
    }
    int ILen = sizeof(struct student);
    printf("%d\n",ILen);**
#include "stdio.h"
#include "string.h"
struct date {
    int month;
    int day;
    int year;
};
struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;

};//stu[3];
int main() {

    struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
            {2019250116,"zhangsan",1,18,"2401",12,30,2000},
            {2019250119,"振华",0,22,"小区2401",11,11,1999},
            {2019250118,"郭襄",0,20,"平凉",9,23,2001}
    };
    printf("stu[%d]",stu[1].age);

    **//演示指向结构体数组的指针
    struct student *ps;
    ps = stu; //数组名代表数组首地址。

    (++ps)->num; //值为2019250119,指针指向了2019250119
    (ps++)->num; //值为2019250116,指针指向了2019250119
}**

(2)不能让ps指向某一个数组元素中的成员。

错误写法

ps =&stu[0].num; //可以强制转,但没有意思

ps = &stu[0]; //这是对的

9.2.3 用指向结构体的指针做函数参数

#include "stdio.h"
#include "string.h"
struct date {
    int month;
    int day;
    int year;
};
struct student //定义一个结构体类型
{
    int num; //学号
    char name[100]; //姓名
    int sex; //
    int age; //年龄
    char address[100]; //地址
    struct date birthday;

};//stu[3];
int main() {

    struct student stu[3] = { //stu包含的元素程序自己会判断出来,所以可以写成stu[]
            {2019250116,"zhangsan",1,18,"2401",12,30,2000},
            {2019250119,"振华",0,22,"小区2401",11,11,1999},
            {2019250118,"郭襄",0,20,"平凉",9,23,2001}
    };
    printf("stu[%d]",stu[1].age);

    **//演示指向结构体数组的指针
    struct student *ps;
    ps = stu; //数组名代表数组首地址。

    (++ps)->num; //值为2019250119,指针指向了2019250119
    (ps++)->num; //值为2019250116,指针指向了2019250119
}**

(2)不能让ps指向某一个数组元素中的成员。

错误写法

ps =&stu[0].num; //可以强制转,但灭有意思

ps = &stu[0]; //这是对的

9.3 共用体、枚举类型、typedef

9.3.1共用体(联合)

将几种不同类型的变量存放到同一段内存单元(同一个内存地址开始的单元中)。

几个变量共同占同一段内存的结构,叫共用体

union 共用体名
{
	//成员列表
} 变量列表;
union myuni
{
	int carnum;     //车编号,
	char cartype;   //车的类型
	char cname[60]; //轿车名
}a,b,c;

结构体与共用体的区别

结构体:

占用的内存是其成员所占内存之和。 如果定义的结构体不能被4整除或被某个数整除的话,系统会多分配几个字节以保证字节对齐

保证字节对齐的目的是为了效率问题。

#include "stdio.h"
#include "string.h"
struct student  //结构体
{
    int num;
    char name[101];
    int sex;
};
int main(){
    union MyUni a,b,c;
    int StructLen(sizeof(struct student)); //StructLen=112;
// 4+101+4=109; 112-109=3 
//保持的是4k对齐,108/4=27 109-112是4个字节。
printf("StructLen=%d\n",StructLen); // 112

共用体: 所占用内存长度等于最长的成员长度。

#include "stdio.h"
#include "string.h"
union MyUni   //共用体
{
    int CarNum;     //车编号,
    char CarType;   //车的类型
    char name[60]; //轿车名
};

int main(){
    union MyUni a,b,c;
int UnionLen(sizeof(union MyUni));
    printf("UnionLen=%d\n",UnionLen); // UnionLen=60
//最长的成员类型长度

说明:

a、共用体变量的引用

a.name;
a.CarNum;

b、共用体变量的特点

同一段内存存放几种不同类型的成员,但每一个瞬间只能存放其中一种。也就是说,每个瞬间只能由一个成员起作用,其他成员不起作用,并不是同时存在、都起作用

程序代码中最后给哪个成员赋值,那么哪个成员就起作用

#include "stdio.h"
#include "string.h"
union MyUni   //共用体
{
    int CarNum;     //车编号,
    char CarType;   //车的类型
    char name[60]; //轿车名
};

struct student  //结构体
{
    int num;
    char name[101];
    int sex;
};
int main(){

    union MyUni a,b,c;
    int StructLen(sizeof(struct student)); //StructLen=112;
    // 4+101+4=109; 112-109=3 保持的是4k对齐,108/4=27 109-112是4个字节。
    int UnionLen(sizeof(union MyUni));
    printf("StructLen=%d\n",StructLen);
    printf("UnionLen=%d\n",UnionLen);

**a.name;
    a.CarNum = 12; //这个不起作用
    strcpy(a.name,"ab"); //这是最后一个成员,所以这个才起作用
    printf("%d\n",a.CarNum); //不确定的值
    printf("%s\n",a.name);  //ab**


c、共用体变量的地址 和 其他成员地址都相同

&a &a.Carnum &a.name &a.CarType

这三个地址都相同

d、共用体变量不能在定义的时候初始化,而结构体可以初始化

e、不能把共用体变量作为函数参数,也不能让函数带回共用体变量

9.3.2枚举类型

例如:

//四种颜色: 红,绿,蓝,黄

// Red表红色

//Green

//Blue

//Yellow

枚举值当成整型值用就行了

枚举类型关键字

enum

enum color
{
		Red, //枚举常量,值不能被改变(可以当成一个整形数字)
	//占用4个字节
    Green,
    Blue,
    Yellow
};

枚举就是将值一一列举出来,那么定义的枚举变量值就只限于列出来的这些值的范围内;

可以直接定义枚举变量,不要枚举名,这就要直接定义枚举变量才行

enum
{
	Red,
	Green,
	Blue,
	Yellow
}MyColor1,MyColor2;

这些Red,Green,Blue,Yellow叫做枚举常量,这些常量的值不能被改变

//枚举常量,值不能被改变(可以当成一个整形数字),占用4个字节

d、可以直接给 枚举类型变量 赋值

#include "stdio.h"
#include "string.h"
enum color
{
    Red,    //0,默认从0开始,
    Green,  //1
    Blue,   //2
    Yellow  //3
};

int main(){
    
    **enum color  MyColor1,MyColor2;**
    printf("%d\n",Red);
    printf("%d\n",Yellow);
		**MyColor1 = Red; // 0
		Mycolor2 = Yellow; // 3**

}

e、定义枚举类型时,直接给枚举常量一个值。

#include "stdio.h"
#include "string.h"
enum color
{
Red= 12,  // 从12开始 往下走每次加1
Green,    //13
Blue,     //14
Yellow    //15
};

int main(){
    enum color  MyColor1,MyColor2;
    printf("%d\n",Red); //12
    printf("%d\n",Yellow); //15
    MyColor1 =Red; //Red当做常量
    printf("%d\n",MyColor1); //12

}

f、枚举值,理解成整型值

枚举值可以做比较

MyColor1 = (enum color)-8;
//强制转换将-8给了Red这个常量
if(MyColor1 == Red // 枚举值可以做比较
{
	printf("OK");
}
MyColor1 = (enum color)20000
printf("%d\n",MyColor1);  
//枚举值其实就是整型值,可以互通 

g、枚举值可以赋给一个整形

int abc;
abc = Green;
	printf("%d\n",Green);  
	printf("%d\n",abc); 

//两个的值都是一样的

9.3.3用typedef来定义类型

使用typedef来定义新的类型名,可以用来代替已有的类型名,

#include "stdio.h"
#include "string.h"
enum color
{
    Red = 12,
    Green,
    Blue,
    Yellow
};

int main(){

    typedef int INTEGER; //可以使用INTEGER来代表int型,那再次定义整形变量时我们
    //就可以如下定义
    INTEGER a,b,c; //
    int a1,a2,a3;  // 这两个都是一样的

    **//如何定义结构体类型
    typedef struct date
    {
        int month;
        int day;
        int year;
    }DATE;
    DATE birthday;
    DATE *p1; //p为指向此结构体类型数据的指针

    //变形:
     typedef int NUM[100]; //定义num数组是整形
     NUM n; // 等价于int n[100];
     typedef char *RNG; //定义RNG为字符指针类型
     RNG p,q; // char *p,*q;**

     **//指向函数的指针
     typedef int (*POINTER)(); //定义pointer为指向函数的指针类型,该函数返回的是整型值
     POINTER x,y;**
}
//总结: 第一步:先写出常规的整形数组定义方式
int n[100];
//第二步:将变量名替换成自己想用的类型名
int NUM[100];
//第三步:在前面加上typedef
typedef int NUM[100];

说明:

  1. typedef中用的类型别名使用大写
  2. typedef用来定义类型名的,不是定义变量
  3. typedef只是对已存在的类型增加一个类型名,没有创建新的类型
  4. typedef是在编译的时候处理的,是在编译环节进行的

可执行文件需要经过编译(预处理(#define,#include,#ifdef)**,编译(typedef),**汇编),链接,

1. typedef主要作用:

程序的通用性和可移植性

int a,b,c;
typedef int INTEGER;
INTEGER a,b,c;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨优秀&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值