C语言学习第九章——用户建立自己的数据类型

本文详细介绍了C语言中的结构体,包括定义、初始化、结构体变量的字节长度、结构体数组和指针的使用。通过实例展示了如何输入、排序和输出多个学生信息,同时探讨了复杂数据类型的理解,如指针和数组的结合。此外,还提到了typedef声明新类型名的方法。
摘要由CSDN通过智能技术生成

结构体
1.c语言允许用户自己建立由不同数据组成的组合型的数据结构,它称为结构体。在其他一些高级语言中称为“记录”。
2.定义结构体的一般形式

struct 结构体标记	//struct+结构体标记  即结构体的类型名
{
	成员表列
}变量表列;

注意:结构体可以定义在函数外部或者内部。结构体标记和变量至少有一种。如果有变量,可以进行初始化。
3.建立一个结构体类型,它只相当于一个模型,其中没有具体数据,系统也不为其分配存储单元。—―相当于设计好了图纸,但没有建成具体的房屋。

结构体定义和初始化

#include<stdio.h>
//结构体定义总结:结构体标记和变量至少有一种。如果有变量,可以进行初始化。
struct Student{			//1.定义时为结构体起一个结构体标记名 
	char name[30];
	int age;
	double score;
};
struct Student2{			//2.定义时为结构体起一个结构体标记名 并定义这种数据类型的变量 
	char name[30];
	int age;
	double score;
}A,*p;
struct Student3{			//3.定义时为结构体起一个结构体标记名 并定义这种数据类型的变量 并为变量进行初始化 
	char name[30];
	int age;
	double score;
}A1 = {"zhangsan",20},*p1;
struct{						//4.只定义结构体类型的变量 
	char name[30];
	int age;
	double score;
}A2,*p3;
void f(void);
int main(void){ 
	//f();
	struct Student a = {"zhangsan",20,98.5};	//1.完全初始化 
	struct Student b = {"zhangsan",20};			//2.不完全初始化,未被赋值的成员将有一个默认值0 
	struct Student c = a;						//3.定义结构体变量时,使用其他的结构体变量完成初始化 
	//struct Student d = {.score = 18.5};		//4.C99编译器的新功能:在定义一个结构体变量的时候对某个成员初始化,这里会报错 
	printf("学生的姓名:%s, 年龄:%d, 成绩:%lf\n",a.name,a.age,a.score);
	printf("学生的姓名:%s, 年龄:%d, 成绩:%lf\n",b.name,b.age,b.score);
	printf("学生的姓名:%s, 年龄:%d, 成绩:%lf\n",c.name,c.age,c.score);
	printf("学生的姓名:%s, 年龄:%d, 成绩:%lf\n",d.name,d.age,d.score);
	return 0;
}
void f(void){
	struct Student a;
	printf("请输入学生的姓名,年龄和成绩:\n");
	scanf("%s%d%lf",a.name,&a.age,&a.score);
	printf("学生的姓名:%s,	年龄:%d, 成绩:%lf\n",a.name,a.age,a.score);	//1.可以通过 变量名.成员名 的方式访问一个结构体变量的成员 
	struct Student *p=&a;
	printf("学生的姓名:%s,	年龄:%d, 成绩:%lf\n",p->name,p->age,p->score);	//2.可以通过 指针->成员名 的方式访问一个结构体变量的成员 
}

结构体变量所占字节长度

#include<stdio.h>
int main(void){
	//字节对齐,各种数据类型是按照一定的规则在内存当中排列的 
	short a;
	int b;
	double c;
	printf("%d,%d,%d\n",(int)&a%2,(int)&b%4,(int)&c%8);//0,0,0		基本数据类型变量的地址是能够被它们所占字节的长度所整除的 
	struct Stu1{
		char a;
		short b;
	};
	struct Stu2{
		char a;
		int b;
	};
	struct Stu1 A;
	struct Stu2 B;
	printf("%d,%d\n",(int)&A%2,(int)&B%4);	//0,0		1.结构体变量的首地址能够被其最宽基本类型成员的大小所整除
	printf("%d,%d\n",sizeof(A),sizeof(B));	//4,8		2.结构体成员相对于结构体变量的首地址的偏移量(结构体变量的地址编号和结构体成员的地址编号所差的字节数)都是其成员大小的整数倍
	printf("%d,%d\n",((int)&A.b-(int)&A)%2,((int)&B.b-(int)&B)%4);	//0,0
	struct Stu3{
		char a;
		double f;
		int b;
	}C;
	printf("%d\n",sizeof(C));	//24		3.结构体的总大小为结构体最宽基本类型成员的整数倍 
	struct Stu4{
		char a;
		struct Stu2 b;
	}D;
	/*
	D中最宽的基本类型成员是D.b.b 长度为4个字节,所以
	1.D的首地址必须被4整除
	2.D的长度必须被4整除
	struct Stu2数据类型可知:
	1.D.b的地址能够被4整除
	2.D.b的长度是8
	*/
	printf("%d\n",sizeof(D));	//12	2【特殊】.如果结构体成员是复合数据类型的,那么它相对于结构体首地址的偏移量,应该是其最宽基本类型成员大小的整数倍
	return 0;
} 

结构体数组和指针
输入n个学生的姓名和成绩并按成绩排序输出

#include<stdio.h>
#define N 4
struct Stu{
	char name[30];
	double score;
}; 
void input(struct Stu *p,int len){
	for(int i=0;i<len;++i){
		printf("请输入第%d个学生的姓名和成绩:\n",i+1);
		scanf("%s%lf",p[i].name,&p[i].score);
	}
}
void show(struct Stu *p,int len){
	for(int i=0;i<len;++i){
		printf("第%d个学生的姓名:%s,成绩:%lf\n",i+1,p[i].name,p[i].score);
	}
}
void sort(struct Stu *p,int len){
	for(int i=0;i<len-1;++i){
		for(int j=0;j<len-1-i;++j){
			if(p[j].score>p[j+1].score){
				struct Stu b=p[j];
				p[j]=p[j+1];
				p[j+1]=b;
			}
		}
	}
}
int main(void){
	//struct Stu m[]={{"zhangsan",89.6},{"lisi",67},{"wangwu",23.5}};		//结构体数组定义时的初始化 
	//show(m,3);
	struct Stu a[N];
	input(a,N);
	sort(a,N);
	show(a,N);
	return 0;
}

复杂的数据类型
1.已知 int a[5]是定义一个含有5个整型元素的数组,那么如何理解 int(* p)[5]所代表的含义?我们把 int[5] 当成是一个数据类型,并设一个数据类型 A 和其等价,则 int a[5] 和 A a 等价。同理我们可以把 int(* p)[5]转化成 A* p。

因为 A 是一个含有5个整型元素数组类型,所以 A* 就代表是一个含有5个整型元素的数组的指针类型,那么 p 就是该类型的变量。

2.已知 int f(int) 是定义一个返回值是 int,形参为 int 的函数。那么如何理解 int (* p)(int) 所代表的含义?

我们把 int (int) 当成是一个数据类型,并设一个数据类型 A 和其等价,则 int f(int) 和 A f 等价。
同理我们可以把 int(* p)(int) 转化成 A* p。
因为 A 是一个返回值是 int,形参为 int 的函数类型,所以 A* 就是一个返回值是 int,形参为 int 的函数的指针类型,那么 p 就是该类型的变量。

结论:看变量所属圆括号的最外层,把最外层的数据类型设为一个新数据类型,然后去掉变量最外层的花括号。通过这种方法,直到原式转化成 “数据类型 变量” 的形式。

3.分析:int a[3][4] 中 a 的数据类型是什么?

(1)设数据类型 A 和 int[4] 等价,都是定义一个含有4个 int 的数组。则原式可以转化为:A a[3]。
(2)设数据类型 B 和 A[3] 等价,都是定义一个含有3个 A 的数组。则原式可以转化为 B a。 所以 a 是一个含有3个 A 的数组。
(3)又因为 A 是一个含有4个 int 的数组,所以 p 就是一个含有3个元素的数组,每个元素又是一个含有4个 int 的数组。

4.分析:int* (* (* p ) [10] )(void) 中 p 的数据类型是什么?

(1)设数据类型 A 和 int * (void) 等价,都是定义一个返回值为 int* ,形参为 void 型的函数。
则原式可以转换为A* (* p) [10]。
(2)设数据类型 B 和 A* [10] 等价,都是定义含有10个 A 的指针的数组。
则原式可以转换为 B* p。那么 p 就是一个含有10个 A 的指针的数组的指针。
(3)又因为 A 的数据类型是一个返回值为 int*,形参为 void 型的函数。 所以 p 就是一个含有10个(返回值为 int*,形参为 void 型的函数)的指针的数组的指针。
你也可以说 p 指向一个含有10个元素的数组,其中每个元素是一个返回值为 int* ,形参为 void 型的函数的指针。

在这里插入图片描述
在这里插入图片描述
用 typedef 声明新类型名
按照定义变量的方式,把变量名换上新类型名,并且在最前面加“typedef”,就声明了新类型名代表原来的类型。

#include<stdio.h>
typedef int Count;		//1.Count 就代表 int 类型 
typedef int Num[3];		//2.Num 代表一个含有3个 int 型元素的数组类型 
typedef struct{
	int a;
	double b;
}Stu;		//3.Stu代表一个结构体类型 
#define INT int		//4.这里是定义了一个宏名INT,只是在预编译阶段进行一些简单的字符串替换 
int main(void){
	Count a=3;		//1.定义一个 int 型变量 a 
	printf("%d\n",a);//3
	Num b={1,2,3};		//2.定义了一个含有3个 int 型元素的数组 b 
	printf("%d,%d,%d\n",b[0],b[1],b[2]);//1,2,3
	Stu m={12,45.6};		//3.定义了一个结构体类型变量 m 
	printf("%d,%lf\n",m.a,m.b);//12,45.600000
	INT c=10;		//4.在预编译阶段 该句被替换为 int c=10; 
	printf("%d\n",c);//10
	return 0;
}

单向动态链表
一般头结点不存放有效数据(当然你也可以根据情况而定),在其他节点存放有效数据。
在这里插入图片描述

共用体
(暂无整理)
枚举类型
(暂无整理)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

shi_jiaye

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

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

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

打赏作者

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

抵扣说明:

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

余额充值