目录
结构体与共用体
1、结构体(struct)
(1) 格式与用法
其中,标识符首字母必须大写(规定),最后一行的花括号后必须加分号“;”。用来定义新的数据类型,存放在声明部分中。
例如,创建一个 struct Student 数据类型:
struct Student
{
int id;
char name[20];
float score;
};
对新的数据类型定义变量的方法:
a. 在末行花括号( } )与分号( ;)中间写入所需变量的个数及名称,此时变量为全局变量,存放在静态区;
b. 在主函数中输入创建数据类型名,在其后输入变量名来定义变量,此时变量为局部变量,存放在栈区。例如:
注意:
在主函数 main 中,成员类型与 struct 中的成员类型一致。
“ . ”为结构体成员运算符,是一级运算符,自左至右。
例如:使用创建的 struct Student 数据类型定义变量 s ,定义类型成员内容,完成 “1,zhangsan,97.500000” 的输出效果
int main(void)
{
struct Student s;
s.id = 1;
strcpy(s.name, "zahngsan");//【1】
s.score = 97.5;
printf("%d,%s,%f\n", s.id,s.name,s.score);
return 0;
}
值得注意的是代码中的【1】位置,不能写为“ s.name = "zhangsan" ”,数组不能直接进行赋值。
(2) 结构体允许嵌套
创建一个 struct Date 数据类型,结构体成员信息如下:
struct Date
{
int year;
int month;
int day;
};
使用 struct Student 与 struct Date 两种数据类型,完成" 1, zhangsan, 97.500000, 2002-3-12 "的输出效果
struct Student
{
int id;
char name[20];
float score;
struct Date birthday;
};
int main(void)
{
struct Student s;
s.id = 1;
strcpy(s.name, "zhangsan");
s.score = 97.5;
s.birthday.year = 2002;
s.birthday.month = 3;
s.birthday.day = 12;
printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
return 0;
}
(3) 结构体成员初始化
a. 全初始化:结构体初始化与结构体成员声明顺序一致,例如:
struct Student s ={1, "zhangsan", 97.5, {2002,3,12}};
b. 部分初始化:只对部分成员信息做初始化,要修改的内容之间用逗号隔开
int main(void)
{
struct Student s = {
.id = 1,
.score = 97.5,
.birthday = {
.year = 2002,
.month = 3,
}
};
printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
return 0;
}
(4) 指针替换变量
通过指针可以对成员进行修改,效率更高,否则只是值传递
struct Student *p;
p = &s;
p->id += 10;
printf("%d %f\n", p->id, p->name);
//p->name 也可写为 (*p).id
//推荐 p->name
(5) 求结构体在内存空间所占字节
内存对齐:数据总线以数据类型的整数倍都数据(整除)。
1、默认按照CPU位数对其(8)字节,最终大小必须是8的整数倍;
2、在结构体成员中找到最长成员,最终按照该成员长度对其;
3、按照结构体声明的顺序,依次将成员保存到结构体内存中,保存的偏移量 / sizeof(成员类型)。
例如:struct Dome 中的成员数据类型依次为 char(黄)、int(蓝)、short(橙),存储如下,又因为要被最长的整除(int 的4个字节),所有该类型的 sizeof 为12。
(6) 应用
对于 struct Student 中的成员信息
struct Student
{
int id;
char name[20];
float score;
};
eg1. 单项输出(printStudent),全部输出(printStudents)
void printStudent(struct Student *p)
{
printf("%d, %s, %f\n", p->id, p->name, p->score);
}
void printStudents(struct Student a[], int len)
{
int i;
for(i = 0;i < len;++i)
{
printStudent(a + i);
}
}
eg2. 交换(swap),逆序(reverseStudents)
void swap(struct Student *a, struct Student *b)
{
struct Student t;
t = *a;
*a = *b;
*b = t;
}
void revserseStudents(struct Student *a, int len)
{
int i;
for(i = 0;i < len / 2;++i)
{
swap(a + i, a + len - i - 1);
}
}
eg3. 采用回调函数按名字长度(namecmp)、按成绩(scoreStudent)进行排序(sortStudent)
int namecmp(struct Student *p1, struct Student *p2)
{
return strcmp(p1->name, p2->name);
}
int scorecmp(struct Student *p1, struct Student *p2)
{
if(p1->score > p2->score)
{
return 1;
}
else if(p1->score == p2->score)
{
return 0;
}
else
{
return -1;
}
}
void sortStudent(struct Student *a, int len, int (*pfn)(struct Student *, struct Student *))
{
int i, j;
for(i = 0;i < len - 1;++i)
{
for(j = i + 1;j < len;++j)
{
if(pfn(a + i, a + j) > 0)
{
swap(a + i, a + j);
}
}
}
}
在主函数中的书写格式
int main(void)
{
struct Student a[3] = {
{1, "zhangsan", 97.5},
{2, "lisi", 98},
{3, "wanghu", 95}
};
int len = sizeof(a) / sizeof(*a);
sortStudent(a, len, namecmp);
printStudents(a, len);
return 0;
}
* 结构体之间不能进行比较排序,但结构体成员之间可以进行比较排序。
2、共用体(union)
(1) 格式与概念
其中,共用体名满足标识符要求,且首字母要大写,共用体成员的内存公用,该类型代码存放在声明中,
创建 union Demo 数据类型,说明共用体成员的内存是共用的
union Demo
{
int i;
short s;
char c;
};
int main(void)
{
union Demo d;
d.i = 1000;
d.s = 100;
d.c = 10;
printf("%u\n", sizeof(d));//输出结果为 4
printf("%d\n", d.i);//输出结果为 10
return 0;
}
说明:内存共用并且会进行覆盖,i 为int型占4个字节,short占2个字节,char占1个字节,相当于int 先占了第一二三四个格子,short 占第一二个格子,char占第一个格子,覆盖到最后只剩 char 的一个格子,输出。
可以运用指针作为类型变量
int main(void)
{
union Demo *p;
p = &d;
printf("%p %p %p\n", &d.i, &d.s, &d.c);
return 0;
}
(2) 应用
用来判断程序大小端存取
union Demo
{
int i;
char c;
};
int main(void)
{
union Demo d;
d.i = 1;
if(d.c == 1)
{
puts("little");
}
else
{
puts("big");
}
return 0;
}
3、枚举类型(enum)
(1) 格式与概念
枚举类型(enum),用来自定义一个数据类型,并将常参放入其中。
一般格式为:
其中,标识符首字母依旧要大写,该类型的所有可能取值称为“枚举类型常量”,各取值之间用逗号“,”隔开,最后一个取值后面不需要加任何东西,花括号后的分号“;”不能省略。也可以对其输出变量(eg1. 中的 w )进行偏移(加法)。例如:
创建 enum Week 类型,并将 Week 的所有可能放入其中,并对 w 的后一项进行输出(可以用 “%d” 进行输出),输出的值为变量 w 在枚举常量的位置,也可以对常量进行赋值,但不能重复(例如下图 Tue=7)
enum Week
{
Sun, Mon, Tue = 7, Wes, Thu, Fri, Sat
};
int main(void)
{
enum Week w;
w = Sun;
printf("%d\n", w + 1);//输出为 Mon
return 0;
}
(2) 应用
该类型可以做 switch 函数后面的表达式,例如:(可自行补充其他 case 情况)
enum Week
{
Sun, Mon, Tue, Wes, Thu, Fri, Sat
};
int main(void)
{
enum Week w;
switch(w)
{
case Sun:
puts("lol");
break;
case Mon:
case Tue:
puts("study");
break;
default:
break;
}
return 0;
}
4、typedef 类型
将已有类型的类型名换个名字,在全局区起名,将变量名变为类型的类型名。在全局区起名。可以在数据类型(int、char、short等后加,也可以在struct、union、enum后加),类型名可以是一个标识符,也可以是一个数组,例如:
typedef int INT;
typedef int ARRAY[10];
int main(void)
{
int i;
ARRAY a;
printf("%lu\n", sizeof(a));
return 0;
}
也可以运用指针作为类型名,例如:
typedef struct Demo
{
int i;
short s;
char c;
}Demo, *PDEMO;
int main(void)
{
Demo d;
PDEMO p;
p = &d;
return 0;
}
【END】
、