警院复试C程序设计学习笔记 第九章——用户建立自己的数据类型
1.结构体定义和初始化
代码如下:
#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, *P2;
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允许使用这种形式在定义一个结构体变量的时候对其某一个成员初始化,devcpp还不行
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);
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.可以通过指针->成员名 的方式访问一个结构体变量的成员
}
执行结果如下:
2.结构体变量所占的字节长度
代码如下:
#include <stdio.h>
int main(void){
//字节对齐:各种数据类型是按照一定的规则在内存当中排列的
short a;
int b;
double c;
printf("%d, %d, %d\n", (long long)&a%2, (long long)&b%4, (long long)&c%8); //基本数据类型变量的地址是能够被它们所占字节的长度所整除的
struct Stu1{
char a;
short b;
};
struct Stu2{
char a;
int b;
};
struct Stu1 A;
struct Stu2 B;
printf("%d, %d\n", (long long)&A%2, (long long)&B%4); //输出结果0,0 //1.结构体变量的首地址能够被其最宽基本类型成员的大小所整除
printf("%d, %d\n", sizeof(A), sizeof(B)); //输出结果4,8 //2.结构体成员对于结构体变量的首地址的偏移量(结构体变量的地址编号和结构体成员的地址编号所差的字节数)都是其成员大小的整数倍
printf("%d, %d\n", ((long long)&A.b-(long long)&A)%2, ((long long)&B.b-(long long)&B)%2); //输出结果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的长度能够被4整除(是8)
*/
printf("%d\n", sizeof(D)); //输出12 //4.如果结构体成员是复合数据类型的,那么它对于结构体首地址的偏移量,应该是其最宽基本类型成员大小的整数倍
return 0;
}
执行结果如下:
3.结构体数组和结构体指针
输入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); //与下面一句等价
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; ++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;
}
执行结果如下:
4.如何理解复杂的数据类型
5.用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.这里是定义了一个宏名IHT,只是在预编译阶段进行一些简单的字符串替换
int main(void){
Count a = 3; //1.定义一个int型变量a
printf("%d\n", a);
Num b = {1,2,3}; //2.定义了一个含有3个int型元素的数组b
printf("%d, %d, %d\n",b[0], b[1], b[2]);
Stu m = {12,45.6}; //3.定义了一个结构体变量m
printf("%d, %lf\n", m.a, m.b);
INT c = 10; //4.在预编译阶段,该句被替换为 int c = 10;
printf("%d\n", c);
return 0;
}
执行结果如下:
6.单向动态链表
代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node{
int data;
struct Node *pnext;
}N, *P;
P create(void){
P pheard = (P)malloc(sizeof(N));
if(pheard == NULL){
printf("分配内存失败,程序退出\n");
exit(-1);
}
pheard->pnext = NULL;
}
void input(P pheard, int value){
P last = (P)malloc(sizeof(N));
if(last == NULL){
printf("分配内存失败,程序退出\n");
exit(-1);
}
last->data = value;
last->pnext = NULL;
while(pheard->pnext != NULL)
pheard = pheard->pnext;
pheard->pnext = last;
}
void show(P pheard){
while(pheard->pnext != NULL){
pheard = pheard->pnext;
printf("%d\n", pheard->data);
}
}
int len(P pheard){
int i;
for(i = 0; pheard->pnext != NULL; ++i)
pheard = pheard->pnext;
return i;
}
bool del(P pheard, int index){
if(index <= 0 || index > len(pheard))
return false;
for(int i = 1; i < index; ++i)
pheard = pheard->pnext;
P ptail = pheard->pnext->pnext;
free(pheard->pnext);
pheard->pnext = ptail;
}
bool insert(P pheard, int index, int value){
if(index <= 0 || index > len(pheard)+1)
return false;
P pw = (P)malloc(sizeof(N));
if(pw == NULL){
printf("分配内存失败,程序退出\n");
exit(-1);
}
pw->data = value;
for(int i = 1; i < index; ++i)
pheard = pheard->pnext;
pw->pnext = pheard->pnext;
pheard->pnext = pw;
}
void invert(P pheard){
if(pheard->pnext == NULL)
return;
P p0 = pheard->pnext;
P p1 = p0->pnext;
P p_0 = p0, p2;
while(p1 != NULL){
p2 = p1->pnext;
p1->pnext = p0;
p0 = p1;
p1 = p2;
}
pheard->pnext = p0;
p_0->pnext = NULL;
}
int main(void){
P pheard = create();
input(pheard,1);
input(pheard,2);
input(pheard,3);
input(pheard,4);
// del(pheard, 2);
// insert(pheard, 2, 10);
invert(pheard);
show(pheard);
printf("%d\n", len(pheard));
return 0;
}
执行结果如下:
7.共用体
代码如下:
#include <stdio.h>
//共用体类型定义总结:共用体名和变量至少有一种。如果有变量,可以进行初始化。
union Data{
int i;
char ch;
double f;
};
union Data1{
int i;
char ch;
double f;
}w, *u;
union{
int i;
char ch;
double f;
}w1={234}, *u1;
int main(void){
union Data a;
// a = 3; //error 不可以直接用一个基本类型的数据对共用体变量赋值
a.i = 3;
printf("%d\n", a.i);
a.ch = 'A';
printf("%c\n", a.ch);
a.f = 3.14;
printf("%lf\n", a.f);
printf("%d, %c\n", a.i, a.ch); //输出垃圾值,因为共用体中所有成员所使用的内存的开头地址是一样的,所以当我们对其中一个成员赋值时,会把这个变量中原有的数据给覆盖掉
//定义共用体变量时的初始化
union Data b = {123}; //1.此种方式只能对这个共用体变量的第一个成员进行赋值
union Data c = {.f = 4.5}; //2.此种方式可以指定某一个成员进行赋值 这属于C99的功能
union Data d = b; //3.c99允许共用体变量可以互相赋值
//共用体变量的长度:
//1.共用体变量的地址和长度必须被其最宽基本类型成员的大小所整除
//2.其总长度必须大于等于最宽成员的长度
union Data2{
char a[10];
int b;
}g;
printf("%d\n", sizeof(g)); //输出12
return 0;
}
执行结果如下:
8.枚举类型
代码如下:
#include <stdio.h>
//枚举类型定义总结:枚举名和枚举变量至少有一个即可,如果有变量,可以对变量进行初始化,定义枚举元素时也可显示指定数值
enum A {a1,a2,a3,a4}; //1.只定义枚举名
enum B {b1=3,b2,b3,b4=2,b5,b6,b7}; //2.定义了枚举名,并给部分枚举元素指定一个值
enum C {c1,c2,c3}n; //3.定义枚举名和枚举变量
enum {d1,d2,d3}m; //4.只定义枚举变量而不定义枚举名
enum E{e1,e2,e3}k = e2; //5.定义了枚举变量并为其初始化
int main(void) {
enum A w = a2; //a2是enum A类型的常量
// a2 = (enum A)10; //error 因为a2是一个常量
// w = 1; //error 因为两者数据类型不同
w = (enum A)1;
printf("%d\n",w);
printf("%d,%d,%d,%d\n",a1,a2,a3,a4); //输出0,1,2,3 因为c语言在编译的时候会根据枚举元素定义的顺序分别给他们一个默认值0,1,2,......
printf("%d,%d,%d,%d,%d,%d,%d\n",b1,b2,b3,b4,b5,b6,b7); //输出3,4,5,2,3,4,5 定义枚举类型的时候可以为枚举元素指定一个值,未指定值的元素将是前一个元素+1的值
return 0;
}
执行结果如下: