一、共用体union
共用体有时候也称联合体,用法类似结构体struct,区别在于结构体所占内存大小等于所有成员占用内存总和。而共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新成员赋值,就会把原来成员的值覆盖掉。
1 格式
union 共用体名 { 成员列表; };
2 定义共用体union变量
#include <stdio.h> union val { int a; char ch; }; union val v;
int main(int argc, char const *argv[]) { v.a=10; v.ch='c';
printf("%d\n",v.a);
return 0;
}
得出共用体变量共用一块空间
3 特性
(1)共用体成员共同使用一块内存空间 (2)赋值顺序以最后依次赋值为准 (3)共用体的大小为成员中数据类型最大的数据为大小
使用共用体测试大小端:
#include <stdio.h>
union val
{
int a;
char ch;
};
union val v;
int main(int argc, char const *argv[])
{
v.a=10;
if(v.ch == 10)
printf("small\n");
else if(v.ch == 0)
printf("big\n");
printf("%d\n",v.ch);
return 0;
}
二、枚举enum
1 定义
用户自定义数据类型,可以用于声明一组常数。 在实际编程中,有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都起一个名字。
例如以每周七天为例子,我们可以使用宏定义#define来为每天命名: #define MON 1 #define TUES 2 ... 虽然能解决问题但是宏名过多导致代码看起来很松散,所以C语言提供了一种枚举enum,能够列出所有可能的取值,并给它们起一个名字。
2 格式
enum 枚举名 { value 1, value 2, value 3, ... }; 未赋初值时,第一个常数会默认为0,然后下面的依次加一。每个元素都可以赋值,如果有元素没有赋值则默认值为上一个元素加一。 例子:
#include <stdio.h>
enum week
{
MON,
THES = 2,
WED,
};
int main(int argc, char const *argv[])
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case MON:
printf("%d\n", MON);
break;
case THES:
printf("%d\n", THES);
break;
case WED:
printf("%d\n", WED);
break;
default:
break;
}
printf("MON:%d\n", MON);
printf("THES:%d\n", THES);
printf("WED:%d\n", WED);
return 0;
}
三、数据类型总结
(1)基本数据类型:基本数据类型主要的特点是其值不可以再分解为其他类型,也就是说,基本数据类型是自我说明的。如: short int long float double signed unsigned (2)构造数据类型:构造数据类型是根据已定义的一个或多个数据类型用构造的方法来定义的。也就是说一个构造型的值可以分解成若干个“成员”或者“元素”。每个“成员”都是一个基本数据类型或者又是一个构造型。struct结构体、union联合体、enum枚举和数组。 (3)指针类型:指针是一个特殊的数据类型。其值用来标识某个变量再内存中的地址。虽然指针变量的取值类似于整型,但这两个类型完全不同,不能混淆。定义时要加*。 (4)空类型:空类型void用来定义任意类型的指针和无返回值的函数。
四、存储类型
存储类型有:auto static extern register
1.auto 自动型
修饰变量,一般省略存储类型会默认为auto。
2.static 静态
可以修饰变量或函数
2.1 修饰变量
1.变量的存放位置在全局区(静态区) 如果静态变量有初值,存放.data区,没有初值存放在.bss区域 2.生命周期为整个程序 3.限制作用域: 修饰局部变量,和普通局部变量作用域没有区别,但是生命周期被延长为整个程序。 也就是在作用函数外有生命但是不能被操作,变成了植物人。 修饰全局变量,限制在本文件中使用。 4.值初始化一次,初值赋值为0。
举例对比用static和不用的局部变量在函数中自加操作
#include <stdio.h>
void fun()
{
static int a; //初值为0
int b=0;
a++;
b++;
printf("in fun:%4d %4d\n",a,b);
}
int main(int argc, char const *argv[])
{
fun();
fun();
fun();
return 0;
}
打印结果: in fun: 1 1 in fun: 2 1 in fun: 3 1 因为a用static修饰,所以会保留上一次调用函数后留下的值。此时a放在静态区。
2.2 修饰函数
static修饰函数,限制在本文件中使用。 总的来说,使用 static 定义的变量存储在静态存储区中,具有静态持续性,即使函数返回,它的值也会保留。而且,static 变量只能在当前文件中访问,不能被其他文件访问。 配合extern举例
3.extern
外部引用: 通过extern可以引用其他文件中的全局变量或函数 举例对比引用外部变量和函数,如果加static和不加的区别。
解释:因为变量b和函数fun2()被static修饰,所以限制在fun.c内不能被其他文件调用。
4. register寄存器类型
register是寄存器类型,顾名思义,是把修饰的变量放到寄存器中,目的是为了提高程序的运行效率。但要记住,不管是单片机也好,计算机也罢,任何CPU的寄存器资源都是有限的,如果寄存器满了,被修饰的变量就会默认回到auto类型。 寄存器相当于皇帝身边的小太监,离皇帝近。而内存就相当于大臣,离皇帝比较远,但是地位高。
练习:
创建一个结构体数组,数组名为lolHero,成员包含名称, 位置, 血量和价格。给出每个lol英雄信息,封装函数实现按价格从低到高打印英雄信息。(用冒泡排序)