文章目录
- 1 基本数据类型
- 2 数组,字符数组和字符串
- 2.1 数组
- 2.2 字符数组与字符串
- 3 枚举类型
- 4 结构体和共用体
- 4.1 结构体
- 4.2 共用体
- 5. 拓展
- 5.1 结构体内存分配
- 5.1.1 以结构体中占字节数最大的数据类型的字节数为单位开辟内存
- 5.1.2 字节对齐
- 5.1.3 结构体中嵌套结构体
- 5.2 联合体内存分配
- 5.3 数据类型转换
- 5.4 typedef
1 基本数据类型
C语言中,基本数据类型有整型(int),字符型(char)和浮点型(float,double)。在32位系统下的基本类型数据类型如下
类型 | 类型名 | 字节 | 表示范围 |
---|---|---|---|
int | 整型 | 4 | - 2 31 ~ 231 - 1 |
unsigned int | 无符号整型 | 4 | 0 ~ 232 - 1 |
short int | 短整型 | 2 | -215 ~ 215 - 1 |
unsigned short int | 无符号短整型 | 2 | 0 ~ 216 - 1 |
long int | 长整型 | 4 | - 2 31 ~ 231 - 1 |
char | 字符型 | 1 | - 2 7 ~ 27 - 1 |
unsigned char | 无符号字符型 | 1 | 0 ~ 28 - 1 |
float | 单精度浮点型 | 4 | 3.4E ± 38 (7 位有效数字) |
double | 双精度浮点型 | 8 | 1.7E ± 308(15 位有效数字) |
long double | 长双精度型 | 10 | 1.2E ± 4932 (19 位有效数字) |
除了上面列举的,还有long long int型,占8个字节,比long int表示的范围更大。很多时候,我们会在程序中见到下面这种定义
#define CODE 1024U
其中的“U”或者“u”,是指定为unsigned类型。
加“F”或“f”为float类型,“L”或“l”为long double类型。如果一个小数后面不加后缀,默认为double类型。
#define CODE 1.024 // 默认为double类型
#define CODE 1.024F // 为float类型
#define CODE 1.024L // 为long double类型
2 数组,字符数组和字符串
2.1 数组
数组是存储同一种数据类型多个元素的集合。数组有一维数组和二维数组。定义数组方法如下
数据类型 数组名[数组长度] // 一维数组
数据类型 数组名[数组行数][数组列数] // 二维数组
数组的索引(也可以叫做下标,序号)是从0开始的。比如定义数组时,数组长度为n,那么数组的索引是从0 ~ n - 1
。
给数组赋初始值时,只能一位一位地赋。
int a[4] = {1,2,3,4}
对于没有给出数组长度,但是给出了数组初始值的情况。编译器会根据初始值个数和类型,给数组自动分配存储空间。
可以用sizeof计算数组空间的大小,也就是字节数。进而可以求数组的长度。
比如求数组a的长度
#include<stdio.h>int main()
{int a[4] = {1,2,3,4};printf ("数组a的长度为%d",sizeof(a) / sizeof(a[0]));return 0;
}
输出结果为
数组a的长度为4
2.2 字符数组与字符串
一个数组中元素为字符的数组,称为字符数组。字符串是一串连续的字符序列。个字符串常量用一对双引号括起来,比如"Welcome",编译系统自动在每一字符串常量的结尾增加“\0”结尾符
。字符串可以由任意字符组成,一个长字符串可以占两行或多行,但在最后一行之前的各行需用反斜杠结尾
。比如
"STM32F103ZET6"
等价于
"STM\
32\
F103\
ZET6"
需要注意的是,"A"与'A'是不同的,"A"是由两个字符(字符"A"与字符"\0") 组成的字符串而后者只有一个字符。最短的字符串是空字符串"",它仅由一个结尾符"\0"组成。
3 枚举类型
枚举类型是一种用户定义的数据类型。枚举就是把可取的值一一列举出来。定义枚举类型的格式如下
enum 枚举类型名
{标识符1 = 整型常数1,标识符2 = 整型常数2,……标识符n = 整型常数n,
};
如果在定义时没有给枚举成员赋值,编译时,编译器会自动给每一个枚举成员赋一个不同的整型值。第一个成员为0,第二个成员为1,以此类推。枚举类型的某一个成员赋值后,它后面的成员会按照依次加1的规则,确定自己的整型值。
比如
enum temp
{temp1 = 2,temp2,……temp10 = 20,temp11,
};
其中temp2对应的整型值为3。temp11对应的整型值为21。
4 结构体和共用体
4.1 结构体
利用结构体类型可以把一个数据元素的各个不同类型的数据
项聚合为一个整体。结构体类型的声明格式为
struct 结构体名
{成员列表
}变量名列表;
定义结构体时,不能直接赋值。
这里给出一种赋值方法
#include<stdio.h>struct student
{char *name;char *number;int age;
}student;int main()
{// 给结构体成员赋值student.name = "ertu";student.number = "20230711";student.age = 23;printf("**************************\n");printf("姓名:%s\n",student.name);printf("学号:%s\n",student.number);printf("年龄:%d\n",student.age);printf("**************************\n");return 0;
}
运行结果如下
也可以定义结构体数组,存储多个相同结构的信息。
#include<stdio.h>struct student
{char *name;char *number;int age;
}student[10];int main()
{// 给结构体成员赋值student[0].name = "ertu";student[0].number = "20230711";student[0].age = 23;printf("**************************\n");printf("姓名:%s\n",student[0].name);printf("学号:%s\n",student[0].number);printf("年龄:%d\n",student[0].age);// 给结构体成员赋值student[1].name = "yingting";student[1].number = "20230711";student[1].age = 20;printf("**************************\n");printf("姓名:%s\n",student[1].name);printf("学号:%s\n",student[1].number);printf("年龄:%d\n",student[1].age);printf("**************************\n");return 0;
}
输出结果如下
4.2 共用体
共用体的定义方法为
union 共用体名
{成员列表
}变量名列表;
共用体与结构体类似,不再赘述。
5. 拓展
5.1 结构体内存分配
结构体在分配内存时,有以下规则(在不同的环境中可能不同,这里只针对VC6.0)
- 以结构体中占字节数最大的数据类型的字节数为单位开辟内存
- 字节对齐
5.1.1 以结构体中占字节数最大的数据类型的字节数为单位开辟内存
换句话说,也就是结构体所占大小是其内部占字节数最大的数据类型的整数倍。这里看一个例子
#include<stdio.h>struct temp
{int i;char j;}temp;int main()
{ printf("结构体所占字节数:%d\n",sizeof(temp));printf("i的地址:%p j的地址:%p\n",&temp.i,&temp.j);return 0;
}
输出结果如下
结构体中占字节数最大的数据类型是int,占4字节。因此,在开辟内存时,以4字节为单位。虽然char类型只占1字节,但是依旧为它开辟了4字节大小的内存。
如果结构体成员中出现了数组,并不把数组看作整体来计算字节数,而是看数组的数据类型。
也就是说,即使定义一个char j[5],在分配内存时,也不会把它看作一个占有5字节长度的数据类型。可以看一个例子
#include<stdio.h>struct temp
{short int i;char j[5];
}temp;int main()
{ printf("结构体所占字节数:%d\n",sizeof(temp));printf("i的地址:%p j的地址:%p\n",&temp.i,&temp.j[0]);return 0;
}
输出结果为
如果结构体成员中出现指针变量,那么会以8字节为单位,开辟内存。
可以看一个例子
#include<stdio.h>struct temp
{short int i;char *j;
}temp;int main()
{printf("结构体所占字节数:%d\n",sizeof(temp));printf("i的地址:%p j的地址:%p\n",&temp.i,&temp.j);return 0;
}
输出结果如下
5.1.2 字节对齐
简单来说,就是存储变量的地址必须是变量所占字节数的倍数。字节对齐是一种用空间换取时间的策略,能够提高CPU读取数据的效率。
5.1.3 结构体中嵌套结构体
我们先看一个例子
#include<stdio.h>struct temp1
{char m;char *n;
}temp1;struct temp
{int i;char j;struct temp1 k;
}temp;int main()
{printf("结构体temp1所占字节数:%d\n",sizeof(temp1));printf("结构体temp所占字节数:%d\n",sizeof(temp));printf("i的地址:%p j的地址:%p\n",&temp.i,&temp.j);printf("m的地址:%p n的地址:%p\n",&temp1.m,&temp1.n);return 0;
}
输出结果如下
由此可以看出,当有结构体嵌套时,两个结构体单独分配空间。分配空间时的单位是各自包含的结构体成员中占字节数最大的数据类型的字节数。最终的结构体所占内存大小为两个结构体所占内存大小的和。
5.2 联合体内存分配
共用体在分配内存时与结构体不同,共用体所占内存大小等于其成员中所占内存最大的成员的字节数
。可以看一个例子
#include<stdio.h>union temp
{int i;char j;
}temp;int main()
{printf("结构体temp所占字节数:%d\n",sizeof(temp));printf("i的地址:%p j的地址:%p\n",&temp.i,&temp.j);return 0;
}
输出结果为
可以看到,两个成员的起始地址相同
。i和j存储时如下
5.3 数据类型转换
强制类型转换的格式为
(目标数据类型)变量/表达式
数据类型转换除了在计算时可以统一数据类型,在LCD显示变量时,它也有重要作用。比如想在LCD上显示实时温度。
温度模块已经检测出了温度值,数据类型为float类型。需要将“Temper:26”显示到LCD。这是可以直接将“Temper:”和温度模块检测到的环境温度直接打包,利用sprintf函数转换成字符串,显示到LCD。
unsignde char string[20];sprintf((char*)string,"Temper:%.1f\r\n",temper);
5.4 typedef
利用typedef可以给数据类型起一个新的名字,比如我们在开发STM32时使用的一些u8,u16等,都是利用typedef定义的
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;