复杂数据类型和结构体

通过声明某一数据类型的变量,可以描述某一事物的某一特性。越复杂的事物特性越多,这时候用单一的变量来描述事物的特性会比较麻烦,所以C语言引入了结构体类型,结构体类型可以对事物整体进行封装。
如描述学生的特性
以前:
char id[8]; //id
char names[8] //名字
int age;// 年龄
char sex; //性别
… … …
现在:

struct student  //特性之间不在分离,而是一个整体
{
	char id[8];
	char names[8];
	int age;
	char sex;
};

1. 结构体类型

注:结构体类型属于我们构造的类型

1.1 结构体类型定义

定义格式:
struct 结构体类型标识符
{
成员变量列表; //可以是基本数据类型,或构造类型
};

struct student
{
	char id[8];
	char names[8];
	int age;
	char sex;
};
struct class
{
	struct student yuanyuan;//成员为结构体类型
	struct student wenwen;
	struct student wenwen;  //error 不能同名
	struct class A_senior_class; //error 不能嵌套定义相同类型的结构体变量
	
	struct class *A_senior_class; 
	//correct 成员变量可以指向本类型
};

注:
可以在结构体中定义别的结构体,但是不能在本结构体定义本身,或者说不能在本结构体声明本结构体的变量。
可以在本结构体中定义指向本结构体的指针。

小结:
①struct student 和struct class是结构体类型名,student和class不是结构体类型名
②成员名称不能相同
③C语言不允许嵌套定义相同类型的结构体变量,允许成员变量可以指向本类型
④结构体的有效范围和在源程序文件中定义的位置有关。

1.2 结构体类型声明和初始化

声明

声明方式①

struct student yuanyuan,wenwen;

声明方式②

struct student  
{
	char id[8];
	char names[8];
	int age;
	char sex;
}yuanyuan,wenwen;//定义的同时进行声明

声明方式③

//可以这样用
struct class
{
	... ... ...
	struct   //没有标识符,意味着无法在别处声明
	{
		char id[8];
		char names[8];
		int age;
		char sex;
	}yuanyuan, wenwen;
	... ... ...
};

初始化

格式:
结构体类型名 变量名 = {成员1的初值,成员1的初值…}
初值列表中的初值顺序必须和结构成员顺序一致。
初始化也有三种方式,分别对应声明的三种方式。
注意:
若是部分初始化,则未初始化的为对应类型的零值。

1.3 结构体变量的引用

引用格式:
结构体类型变量.成员变量

代码演示:

#include<stdio.h>

struct student
{
	char id[8];
	char names[8];
	int age;
	char sex;
};

int main()
{
	struct student yuanyuan = {
		"1907020",
		"wenwen",
		18,
		'W'
	};
	struct student wenwen = yuanyuan;
	//对结构体变量的操作和对普通变量和数组的操作类似
	printf("names = %s\n", wenwen.names);
	printf("age = %d\n", wenwen.age);
	printf("id = %s\n", wenwen.id);	
	printf("sex = %c\n", wenwen.sex);

	/*运行结果:
		names = wenwen
		age = 18
		id = 1907020
		sex = W*/
	return 0;
}

注:相同结构的类型可以赋值(有字符数组也可以)。

1.4 结构体数组

结构体数组是一组结构体数据集合,其定义和引用和基本数据类型的数组相同。

代码演示:

#include<stdio.h>

struct student
{
	char id[8];
	char names[8];
	int age;
	char sex;
};

int main()
{
	//对应上面说的三种,这里也有三种。这里只说一种
	struct student a[3] = {
		{"1907020","wenwen",18,'W'},
		{"1907020","wenwen",18,'W'},
		{"1907020","wenwen",18,'W'},
	};
	for (int i = 0; i < 3; ++i)
	{
		printf("%s,%s,%d,%c\n", a[i].id, a[i].names, a[i].age, a[i].sex);
	}
	/*运算结果:
			1907020, wenwen, 18, W
			1907020, wenwen, 18, W
			1907020, wenwen, 18, W
		*/
	return 0;
}

结构体数组的存储和,基本类型类似,但是得遵循内存对齐原则,下面将简单介绍一下。

代码演示:

#include<stdio.h>

struct student
{
	char id[8];     //8B
	char names[8];   //8B
	char sex;   //1B
	int age;    //4B
	
};

int main()
{
	struct student a;
	//按理论a的大小应为8+8+4+1=21
	printf("a的大小为: %d\n", sizeof(a));
	printf("id的首地址:%p\n", a.id);
	printf("names的首地址:%p\n", a.names);
	printf("sex的首地址:%p\n", &a.sex);
	printf("age的首地址:%p\n", &a.age);

	/*运行结果:
				a的大小为: 24 
				id的首地址:0019FA54      //偶数
				names的首地址:0019FA5C   // C(十进制的12)偶数
				sex的首地址:0019FA64    //偶数
				age的首地址:0019FA68    //偶数
*/ 
}
}

内存对齐原则是指为了提高可移植性以及减少CPU读取内存的次数,系统在分配变量地址空间时,都是以2B(16位CPU)或4B(32位CPU)的整数倍为起始地址进行分配,即各变量的起始地址都对齐在内存空间的偶数地址上。
注意:虽然给1个字节的sex分配了4个字节的空间,但是,sex只可以用第一个字节,后面三个字节不能用。

结构体与函数

与基础类型和数组的参数传递类似,结构体类型作函数参数也遵循单向值传递原则。结构体数组也类似。当然,函数的返回值也可以是结构体类型。
代码演示:

#include<stdio.h>

struct student
{
	char id[8];
	char names[8];
	int age;
	char sex;
};

struct student fun(struct student x)
{
	x.age = 999999;
	return x;
}

int main()
{
	struct student wenwen = {
		"1907020",
		"wenwen",
		18,
		'W'
	};
	struct student yuanyuan = fun(wenwen);
	printf("%s,%s,%d,%c\n", wenwen.id, wenwen.names, wenwen.age, wenwen.sex);

	printf("%s,%s,%d,%c\n", yuanyuan.id, yuanyuan.names, yuanyuan.age, yuanyuan.sex);
	
	//按值传递并不改变原有数据
	/*
	运行结果:
		1907020, wenwen, 18, W
		1907020, wenwen, 999999, W
		*/

	return 0;
}

1.5 结构体类型指针

除了引用成员要使用->之外就没什么特别的地方.

代码演示:

#include<stdio.h>

struct student
{
	char id[8];
	char names[8];
	int age;
	char sex;
};

int main()
{
	struct student a;
	struct student *p=&a;
	p->age = 18;
	p->sex = 'W';

	printf("%d,%c", p->age, p->sex);

	/*运行结果:
		18, W
		*/
	return 0;
}

2. 共用体

概述:共用体也是用户自定义得类型,共用体类型的定义,变量声明以及引用方式于结构体类似,不同的是共用体可以将不同类型的变量存放在同意内存区域内。

定义格式:
union 共用体标识符
{
成员变量列表;
}

共用体变量的赋值和引用同结构体

代码演示:

#include<stdio.h>

union variant
{
	char a;
	int b;
	double c;
};
//所有变量共用一段内存,即当声明变量时,系统只为其分配8B的空间

int main()
{
	union variant val; // 声明共用体变量
	printf("val的大小为: %d\n", sizeof(val));
	printf("val.a的大小为: %d\n", sizeof(val.a));
	printf("val.b的大小为: %d\n", sizeof(val.b));
	printf("val.c的大小为: %d\n", sizeof(val.c));

	val.a = 'W';  //给共用体赋值,只使用了1B的空间,其余的空间空闲
	printf("%c\n", val.a);

	val.c = 12.15;  //给共用体赋值,使用全部的空间,即8B
	printf("%lf\n", val.c);
	return 0;

	/*
	运行结果:
		val的大小为: 8
		val.a的大小为: 1
		val.b的大小为: 4
		val.c的大小为: 8
		W
		12.150000
		*/

}

注:共同体分配的空间大小为:共同体中最大一个成员变量的大小,如果使用的是较小的变量,那么空间肯定会剩余
①这里的的大小指的是变量在内存中占字节的大小
②剩余的空间其他变量不能使用

3. 枚举类型

生活中的很多问题所描述的状态仅为有限个,如东南西北,上下左右,周一到日,一月到十二月等等。
如,我们可以定义定义一组符号常量来描述上下左右

//后面将详细讲解这个方式
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGNT 4

尽管这4个变量为同一类型,但是他们不能作为一个完整的逻辑整体。故C语言提供了枚举类型,为具有少量可列举状态的变量定义一种新的数据类型。枚举类型同样是用户自定义类型。

定义格式:
enum 枚举标识符
{
常量列表;
}

代码演示1:

#include<stdio.h>

int main()
{
	enum text1{a,b,c,d,e};  //a,b,c,d,e叫枚举常量,
	                        //此后不得其他的变量的名字不能和枚举常量一致
	enum text2
	{
		f = 2,
		g,
		h = 1,
		i,
		j
	};
	printf("a=%d b=%d c=%d d=%d e=%d\n", a,b,c,d,e);
	printf("f=%d g=%d h=%d i=%d j=%d\n", f,g,h,i,j);
//		运行结果:
//		a=0 b=1 c=2 d=3 e=4
//	    f = 2 g = 3 h = 1 i = 2 j = 3
	//故,如果不给枚举量值,他将从0开始,依次加1
	//    如果给枚举值,则从这个枚举值开始依次加1
	return 0;
}

代码演示2:

#include<stdio.h>

enum text { UP=1,DOWN=2,LEFT=3,RIGNT=4}; //定义枚举类型

int main()
{
	enum text a;//声明一个enum text类型的变量
	a = UP;
	printf("%d ", a);
	a = DOWN;
	printf("%d ", a);
	a = LEFT;
	printf("%d ", a);
	a = RIGNT;
	printf("%d ", a);
	a = 1999;                //不会出错
	printf("\n%d", a);

	/*
	运行结果:
		1 2 3 4
		1999
		*/
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值