c语言中的结构体和共用体

结构体与共用体


1、结构体
格式:
struct 结构体名
{ 成员表列};

struct 结构体名  和我们使用的基本的数据类型以及数组等等类型是一样的。
都是可以进行:类型名 成员名
成员列表 成为 域表
每一个成员也称为结构体中的一个域。

结构体是一种存放不同的类型的组合。可以和数组进行比较 或者 和c++ 中的类进行比较。

eg:
struct student{
    int num;
    char name[20];
    char sex;
    int age;
    float age;
    char addr[30];
};

2、定义结构体类型变量的方法
上面的结构体类型只是相当于一个模型,或者一个种数据类型;其中并没有具体数据,系统对之也不分配实际的内存单元。

为了在程序中使用结构体数据,应当定义结构体类型的变量,并且在其中存放具体的数据。

1)先声明结构体类型再定义变量名

上面的结构体应该是一个声明的过程,所以没有被分配内存,和其他的基本的数据类型是一样的。
所以,需要定义之后才是有分配内存,真正具有变量和可以运行的特性。

格式:struct 结构体名 结构体的变量名;

eg:struct student student1,student2; //这个过程student1、student2 分别就被分配了59(=2+20+1+2+4+301)个字节。

如果结构体比较大的时候,我们经常也是会将它写在.h的头文件中。
因为这样就可以使用#include "头文件名" 来进行包含进去。

2)在声明类型的同时定义变量
格式:
struct 结构体名{
    成员表列
}变量名表列;

eg:
struct student{
    int num;
    char name[20];
    char sex;
    int age;
    float age;
    char addr[30];
}studnet1,student2;

3)直接定义结构体类型变量
格式:
struct{
    成员表列
}变量名表列;
(即为:这个时候没有出现结构体名)

说明:
(1)类型和变量是不同的概念,类型是一种模型,变量是一个实际的存储空间。变量可以进行赋值等等的操作以及系统对其分配内存空间,而类型是不行的。
(2)对结构体的成员 是可以独立使用的。
(3)成员也可以是一个结构体(我们经常在写图的数据算法的时候,定义其结构体是一般是需要定义多个结构体,所以存现结构体中包含有结构体的数据类型的情况)
(4)成员名可以与程序中的变量名相同,两种代表的是不同的对象。我们在写程序的时候来进行获取的时候就可以了解和区分开来。

3)结构体的引用
(1)不可以将一个结构体变量作为一个整体进行输入和输出。
格式:结构体变量名.成员名
即为使用"."这个符号来进行获取里面的成员变量,可以将他们看成为一个整体的变量。
(2)若是出现结构体内部出现结构体来进行定义 的时候,我们需要使用这个符号来进行 不断地按照从外部到里面的过程进行获取里面的成员变量。
(3)结构体中的成员可以向普通一样进行各种运算。
(4)可以引用“结构体变量的成员的地址”和“结构体变量地址”
结构体变量地址: 主要是用做函数参数,传递结构体变量的地址。

4、和其他的基本类型一样,可以对结构体进行初始化

5、结构体数组
(与一般的数组不同的地方就是, 结构图体数组中的每一个元素都是一个结构体变量)
1)定义结构体数组
eg:
struct student{
    int num;
    char name[20];
    char sex;
    int age;
    float age;
    char addr[30];
};

struct student stu[3];

2)结构体数组的初始化
结构体变量的初始化是对结构体变量中的成员进行初始化。(初始化的时候是对应的数值的表列)

结构体数组一般是用于相同的一群个体之间的,个体中都有很多相应的特性。

6、指向结构体类型数据的指针
1)指向结构变量的指针
和其他的基本变量一样定义体的变量指针。
注意结构体指针中的变量以及相应的指针的使用情况,尤其是符号“*”、“.”的使用。

以下3种形式是等价的
(1)结构体变量.成员名
(2)(*p).成员名
(3)p->成员名
“—>” :指向运算符,就是使用指针来对相应的对象的属性(成员进行操作的一种书写的方式)

2)我们知道了直线数据的指针和指向数组元素的指针的使用情况。同样的方式,我们可以对结构体数组以及其元素使用指针或者指针变量。
eg:
void main()
{
    struct student *p;
    for(int i=0; i<3 ;i++){
    printf("%5d%-20s%2c%4d \n",p->num,p->name,p->sex,p->age);
    }
}

说明:
(1)p的初始值是直线数组中的第一个元素,(++p)也就是指向了下一个元素。
(2)程序定义的p是直线给一个struct student类型数据的指针变量,它是用来指向一个struct student类型的数据(eg:stu数组的而一个元素(eg: stu[0],stu[1])的起始地址),不应用来指向stu数组元素中的某一个成员。
eg:p = stu[1].name; 出现类型的地址是不匹配的。
可以实现强制类型的转化:
p = (struct student*)stu[0].name;
这个是将后面的强制转化为前面p的同样的一种类型。
所以p的类型还是不变的。

3、使用结构体的变量和结构体变量的指针作函数的参数
(1)用结构体变量的成员作为参数。和普通的类型的变量传值是一样的,属于“值”传递。
(2)用结构体变量作为实参。这种方法由于结构体太大的时候,消耗内存比较大,同时造成很大的不变。这种方法是比较“少用”的。
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或者数组)的地址传递给形参。这种方式应该使用的会是比较多,因为这样和我们使用数组指针是一个道理。

7、使用指针处理链表
1)链表我们会经常使用,它也是一种特殊的数据结构。经常链表中有指向下一个节点的指针,所以链表中有一个指针类型。
2)简单的链表。
声明的节点;
stuct student{
    long num;
    float score;
    struct student *next;
};
这样就声明了一个链表的一个节点的数据结构体。

3)处理动态链表所需要的函数  (拓展:void * 类型是任意类型)
(1)malloc 函数
函数原型:void *malloc(unsigned int size)

内存的动态分配一个长度为size的连续空间,此函数的值(返回值)是一个指向分配域起始地址的指针(类型为:void*),如果此函数没有能够正确的执行(eg:内存的控件不足),则返回空指针(NULL)。

malloc 只是用来开辟一个内存空间。

(2)calloc函数
函数原型:void *calloc(unsigned n ,unsigned size)
内存的动态分配n个长度为size的连续空间,函数返回一个指向分配域起始地址的指针,如果分配不成功,返回null。

即为:calloc可以用来为一维数组开辟动态存储空间,n为数组元素个数,每一个元素长度为size。

(3)free函数
函数原型:void free(void* p)
释放由p指针指向的内存区域,这一部分的内存可以被其他的变量使用。

使用这几个函数对链表进行 创建、插入数据、删除数据、输出数据等等的操作。

8、共用体的概念(共用体似乎很少用)
1)公用体的概念
格式:
union 公用体名{
    成员列表
}变量表列。
其实它的声明以及定义和结构体的声明和定义的方式是一样的。
但是含义不一样。

有的时候需要集中不同类型的变量存放到同一段内存单元中。
eg:可以把一个整型变量、一个字符变量、一个实型变量放在同一地址开始的内存单元中。
即为:这几个类型的变量是从同一地址开始进行存储。

区别:
结构体变量:结构体变量所占内存长度是各个成员占的内存的长度之和,每一成员分别占有器自己的内存单元。
共用体变量:所占用的内存的长度等于最长的成员的长度。

2)共用体的变量的饮用方式
注意:只有先定义共用体才可以应用它,不能够引用共用体变量,并且引用的是共用体变量中的成员。
eg:
union data{
    int i;
    char ch;
    float f;
}a,b,c;

使用方式:
a.i a.f a.ch 这样都是正确的

printf("%d",a); //这样是错误的

3)共用体数据类型的特点
(1)同一个内存端可以用来存放几种不同的类型的成员,同一时间只能够使用一种成员变量。
(2)共用存放最后的一次的 成员起到作用,即为原有的成员就会失去作用。
(3)公用体变量的地址和它的各个成员的地址都是同一个地址,eg:&a,&a.i ,&a.c ,&a.f 都是相同的地址。
(4)不能够对公用体的变量名进行赋值,也不能够应用变量名来得到一个值,不能够在定义共用体变量的时候对其进行初始化。
下面的表述是错误的:
(1》》union{
    int i;
    char ch ;
    float f;
}a={1,'a',1.5};
a = 1;
m = a;
上面的这个三种方式都是错误的。
(5)不能把共用体变量作为函数的参数,也不能够使函数带回共用体变量,使用指向共用体变量的指针(与结构体变量这种用法相似)
(6)共用体也是一种(自定义的)数据类型,也是可以存放在其他类型中的。

9、枚举类型
枚举含义:将变量意义列举出来。
关键字:enum
eg:
enum weekday{sun,mon,tue,wed,thu,fri,sat};
声明了一个枚举类型weekday,可以是用来定义变量
enum weekday workday,week-end;
定义的变量可以知道是:workday、week-end
它们的值是:从sun到sat这几个值。
eg:
workday = mon;
week-end = sat;

同样也可以直接定义枚举变量;
enum {sun,mon,tue,wed,thu,fri,sat} workday ,week-end;
说明:
(1)枚举中的元素,是常量,所以是不可以用来赋值的。
(2)枚举元素是常量,它是有值的,按照定义的顺序分别为:0,1,2,3,……
也可以自定义数值,
eg:
enum  weekday{sun=7,mon=1,tue,wed……}
这样sun的值是7,mon的值是1,tue的值为2,即为后面自动加上1。
(3)枚举值可以用来作比较判断
(4)一个整数不能够直接赋值给一个枚举变量的
eg:workday = 2;(错误)
应该进行强制类型转换个给一个枚举变量。
eg:workday = (enum weekday)2

可以知道枚举类型也是一种自定义的类型,和结构体、共用体一样,都是可以自定义类型来进行使用。
枚举类型一般是用于比较少并且明确的分类中。

10、typedef
用来声明新的类型名来代替已有的类型名
eg:
typedef int INTERGER
即为:以后就可以使用INTERGER来替代int这个类型来定义变量。

声明一个新的类型名的方法:
(1)先按照定义变量的方法写出定一体(eg:int i)
(2)将变量名换成新类型名
(3)在最前面加typedef(eg:将i换成COUNT)
(4)然后可以用新类型名去定义变量

说明:
(1)typedef可以用声明各种类型名,但不可能用来定义变量。用typedef可以声明数组类型、字符串类型,这样使用比较方便。
(2)用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
eg:typedef int NUM[10]; 这个无非就是讲int n[10]定义的数组变量类型用一个新的名字NUM表示出来。无论使用哪一种方式定义变量,效果都是一样的。
(3)typedef与#define有相似之处
typedef int COUNT

#define COUNT int
作用都是COUTN 代表 int ,
区别:
#define 是在预编译的时候处理,它只能够简单的字符串替换。
typedef 是编译时处理,并不是做字符串的简单替换
eg:
typedef int NUM[100];(声明NUM为整型数组类型)
NUM n;(定义n为整型数组变量)

这里并不是用NUM[100]替换int,而是采用如同义变量的方法那样来声明一个类型。

(4)不同的文件中用到同一个类型数据(尤其是数组,指针,结构体、共用体等等),常用typedef声明一些数据类型,把他们单独放在一个文件中。使用#include 关键字包括进来。
(5)使用typedef有力程序的通用和移植。


总结:
该模块只要是复习了一下:
(1)结构体、共用体的使用,共用体很少用,最为主要的就是掌握结构体,尤其是在链表中经常使用到。(因为:涉及到结构体和指针的关系,结构体数组等等的关系)
(2)typdef和#define关键字的使用的异同。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值