一.C语言数据类型
只需要百度一下我们就可以知道:
C语言的数据类型分为三大类:基本数据类型、void类型、派生数据类型。
1.基本数据类型
首先了解定义:什么是基本数据类型?
在C语言中,基本数据类型的定义通常由编译器实现,并且它们的大小和范围可能会有所不同,取决于所用的编译器和计算机架构(32位或64位)。但是,C语言标准(如C89、C99、C11等)通常定义了基本数据类型的最小范围和属性。
那么如果我们去百度C语言基本数据类型大概率会得到一个很简短的答案:
C语言的基本数据类型为:整型、字符型、实数型。
或者是:
基本数据类型有三种:字符(char)、整数(int)和浮点数(float)
其实以上三种是最基本的数据类型,其他的众多类型都可以被这三种数据类型概括进去,初学可以借此帮助记忆。但是为了学术精神,我们还是要列出更多的基本数据类型:
关键字 | 类型 | 大小规范 | 默认值 |
---|---|---|---|
int | 整数 | 通常为32位,但至少为16位 | 0 |
short | 短整型 | 至少为16位 | 0 |
long | 长整型 | 至少为32位,且大于或等于int的大小 | 0 |
long long | 长长整型 | 至少为64位 | 0 |
float | 单精度浮点型 | 至少为32位,用于表示小数 | 0.0 |
double | 双精度浮点数 | 至少为64位,提高更高精度的小数 | 0.0 |
long double | 双精度浮点数 | 通常为double的扩展,提供更高的精度 | 0.0 |
char | 字符型 | 表示单个字符,至少为8位 | 未指定(编译器和平台决定) |
unsigned int | 无符号整数 | 省下了符号位,可存储范围比int大 | 0 |
unsigned short | 无符号短整型 | 同上,可存储范围比short大 | 0 |
unsigned long | 无符号长整型 | 同上,可存储范围比long大 | 0 |
unsigned long long | 无符号长长整型 | 同上,可存储范围比long long大 | 0 |
enum | 枚举类型 | 根据包含的枚举常量数量来确定 | 第一个枚举常量的值(一般为0) |
那么普通的数据类型只需要通用的语法格式进行定义即可:
//数据类型 变量名;
int num;//定义一个整型变量num
但这里额外说下不太一样的枚举类型的声明方式:
/*
enum 枚举类型名 {
标识符1 [= 整数值1],
标识符2 [= 整数值2],
...
标识符n [= 整数值n]
};
*/
enum Week { //声明一个枚举类型-星期,内含一周七天
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday =6,
Sunday =7
};
调用的时候只需要通过枚举常量的名称来访问:
//定义一个week类型的变量day,并赋值为1(Monday我们已经给值为1)
enum Week day = Monday;
另外关于基本数据类型这里还有一个容易误解的类型:void
有些人会因为它也属于规范定义的类型而将他也列为基本数据类型,但实际上void通常被认为是一种特殊的数据类型,但不被视为基本数据类型,下面会详细说明。
2.void类型:
国际惯例,先上定义:
类型说明符 void 表示没有值的数据类型,通常用于函数返回值。
那么void为什么不被算作基本数据类型当中呢?
因为它并不具有存储任何值的能力。相反,void 类型通常用作函数的返回类型,表示函数不返回任何值,或者用作指针类型的一部分,表示指针没有指向特定类型的数据。因此,void 类型通常被归类为一种特殊的数据类型,而不是基本数据类型。
3.派生类型:
先上惯例,国际定义(大雾:
由基本数据类型派生而来的,包括数组、指针、结构体和联合体。数组是相同类型数据的集合;指针是用来存储变量地址的变量;结构体是不同数据类型的集合;联合体是一种特殊的结构体,它可以存储多种不同类型的数据,但同一时间只能存储其中的一种
这个就相对很好理解了,把基本数据类型组合起来的类型,就叫派生类型。那我们来详细看一看吧:
1)数组(Array)
数组是一组相同类型的元素的集合,这些元素在内存中是连续存储的。
数组的定义格式:
//类型关键字 数组名称[数组大小];
int num[5]; //定义一个包含五个整数的数组num
2)指针(Pointer)
指针的内容较为复杂,考虑到本篇主要研究数据类型所以不做过多讨论
指针是一种特殊的变量,它存储的是内存地址,即指向另一个变量或数据的地址
指针的定义格式:
//类型关键字 *指针变量名称;
int *num; //定义一个指向整数的指针num
int* num; //也可将*写在前面,这两种是同样的执行结果
这里可以简单来描述一下指针:
每一个变量的名字都对应着它自己的一块存储空间的地址,我们给变量赋值的过程就是把值写入它对应的存储空间地址里面,而指针它直接在自己的存储地址里面存了另一个变量的存储地址,那么这个时候就建立了一个链式的关系。比如我们给A存进去一个数字6,然后给B存入了A的地址,那我们就可以通过读取B的值来得到A的地址,再读取这个A的地址得到数字6。
实际应用:
//首先要知道&是获取后面变量的内存地址,*是获取后面指针存下来的其他变量地址的值
int a = 6; //定义一个整型变量a并初始化值为6
int* b = &a; //定义一个整型指针b,并使用&符号取出变量a的内存地址并赋给指针b
printf("%d", *b);//使用*对b指针里的内存地址进行追溯并打印输出到控制台
//结果为6
当然我们也可以使用指针进行套娃操作:
int a = 6; //定义一个整型变量a并初始化值为6
int* b = &a;//定义一个整型指针b,并使用&符号取出变量a的内存地址并赋给指针b
int** c = &b;//再定义一个二级的指针c,并使用&符号取出指针b的内存地址并赋给二级指针c
printf("%d", **c);//第二个*取出了指针c里面存的b的地址的值(也就是a的地址),
//第一个*取出前面取出的b的地址里存的a的地址的值(也就是6)
//结果为6
3)结构体(Structure)
结构体是一种用户自定义的数据类型,它可以包含多个不同类型的成员变量,这些成员变量在内存中是依次存储的
结构体的定义格式:
/*
struct 结构体名称{
类型关键字 成员变量名称1;
类型关键字 成员变量名称2;
//...可以拥有很多的成员
};
*/
struct Point { //定义一个表示坐标的结构体point
int x; //x坐标
int y; //y坐标
};
4)联合体(Union)
联合体是一种特殊的数据类型,它可以存储不同类型的数据,但同一时间只能存储其中的一个成员
联合体的定义格式:
/*
union 联合体名称{
类型关键字 成员变量名称1;
类型关键字 成员变量名称2;
//...可以拥有很多的成员
};
*/
union Value {
int i;
float f;
char str[20];
};
可以注意到联合体和结构体的定义格式很像,似乎看起来也差不多,但他们有一个本质的区别:
结构体里的成员变量是可以同时存储内容的,而联合体的成员变量同一时刻只能有一个在存数据。也就是说,结构体是实打实的在内存里声明了这些成员的空间,而联合体是所有成员共享一个内存空间的。联合体的作用更多的是借助不同类型的成员实现存入不用类型的值。
4.数据类型别名:
定义:
在C语言中由程序员根据自己的需求定义的基本数据类型的别名,在C语言中,可以使用 typedef 关键字来定义数据类型的别名。
那么定义别名有什么用呢?
举个栗子:可能有人发现了,上面列举的基本数据类型里面并没有大家耳熟能详的布尔类型(就是那个true和false的),因为C99标准才引入了 _Bool 类型,并且需要引入头文件 <stdbool.h>才能使用。所以在不支持C99标准的C语言编译器中可以使用int类型用数字1 代表true数字0代表false
那么我们能不能就在C语言里面用布尔类型呢?
1)定义基本数据类型的别名
//自定义基本数据类型别名的格式
//typedef 基本数据类型 新数据类型名;
typedef int BOOL;//为int类型定义一个名为bool的别名
这样就可以比较简易的通过给int类型取别名的方式搞出来一个虚假的布尔类型。虽然使用bool定义出来的变量依然是int类型的,但对于代码阅读却有很大的帮助。
既然基本数据类型可以自定义别名,那么其他类型呢?
2)定义结构体的别名
typedef Person {
int age;
char name[20];
} PersonAlias;
//或者先定义好一个普通结构体再定义别名
typedef Person {
int age;
char name[20];
};
typedef struct Person PersonAlias;
这样我们就给结构体person一个别名PersonAlias,之后我们只需要使用PersonAlias来声明结构体就可以直接获取到Person结构体了:
PersonAlias p1;//直接使用PersonAlias进行结构体声明
二.常量与变量
1.变量
变量的本质就是程序将可操作的存储区域划分出区域并且给命上名字。
所以程序想要操作存储区域就要先划分出区域并且给命名之后再用,简单说就是:想用变量要先声明。
①变量的声明方式:
1)普通变量声明
int num;
float flo;
char str;
2)多个变量一起声明
int a,b,c;
3)外部变量声明
extern int num;//这种是导入其他源文件里面声明的变量,实现多个源文件之间的通信
4)静态变量声明
static int num;
②变量的命名规则:
比如上面举的例子就是反面教材(
1)名字的字符构成:
●变量名必须以字母或下划线 _ 开始。
●变量名可以由字母、数字和下划线组成。
●变量名区分大小写。
●不能使用C语言的关键字(如 if、while、for等)作为变量名。
这是必须严格遵守的,否则程序执行大概率会遇到问题
2)命名约定:
●使用有意义的变量名,能够清晰地表达变量的用途和含义。
●变量名应该尽可能简洁,但又不至于过于简单以至于难以理解。
●在多个单词组成的变量名中,通常采用驼峰命名法(camelCase)或下划线分隔命名法(snake_case)等命名风格,以增加可读性。例如:firstName、totalAmount、user_id。
●避免使用单个字母作为变量名,除非在循环索引等特定情况下。
●避免使用缩写或简写,以免造成歧义和理解困难。
●使用一致的命名风格,保持代码的统一性和可读性。
虽然这些即便不遵守执行程序也不会遇到问题,但面对庞大的工程时,良好的命名习惯可以让工作效率大大提高。所以养成良好的编码习惯是提升个人上限重要的一环。
③变量的初始化
所谓初始化其实就是在定义变量的同时为他赋上一个初始值。另外既可以在变量声明之后进行初始化也可以在变量声明时一并初始化。
举例:
//先声明再初始化
int num;
float flo;
char str;
num = 0;
flo= 3.14;
str= "别忘了点赞哦";
//变量声明时一并初始化
int num = 0;
float flo = 3.14;
char str = "别忘了点赞哦";
但如果不进行初始化直接对声明后的变量进行调用的话,你将会得到不同类型变量的默认值。除了我们上面基本数据类型表格中列举的默认值外,还有以下默认值:
类型 | 默认值 |
---|---|
布尔 | 0 |
指针 | NULL(空指针) |
数组 | 数组元素的默认初始化值(通常为0或空字符’\0’) |
结构体 | 结构体成员的默认初始化值(通常为成员变量的默认值) |
联合体 | 联合体成员的默认初始化值(通常为第一个成员的默认值) |
④C语言中的左值和右值
左值(lvalue):
左值指的是可以出现在赋值语句左边的表达式,即可以被赋值的表达式。
具体来说,左值是指那些具有地址的表达式,也就是说,它们可以出现在赋值运算符(=)的左边,表示将右边的值赋给左边的变量。
左值可以是变量、数组元素、结构体成员、指针等,这些表达式都可以取得地址。
例如,a、*ptr、array[0] 都是左值。
右值(rvalue):
右值指的是表达式的结果值,即可以被赋给左值的表达式。
具体来说,右值是指那些没有地址、不能被赋值的表达式。
右值可以是常量、变量、函数返回值等,它们可以用于计算表达式的结果。
例如,6、x、func() 都是右值。
2.常量
常量是指在程序设计过程中就确定的值,在执行过程中不会再次发生变化,这些固定值也称为字面量。常量可以是任何基本数据类型。简单来说,常量是只读的。
常量的命名规范与变量大体一致,只有以下为保证代码可读性的约定有些区别:
●常量名通常使用大写字母命名所以不区分大小写。
●一般约定常量名使用下划线分隔单词,以增加可读性。
●在多个单词组成的常量名中,通常采用下划线分隔命名法(snake_case)来增加可读性。例如:MAX_SIZE、PI_VALUE。
常量大致上可以分为:直接常量(字面常量)、符号常量、常变量、枚举常量四种类型
①直接常量
直接的一个值,比如一个1或者一个0,或者是一个字符’a’,一个字符串"abc"等等直接给出一个值不需要用名称定义的就是直接常量。
②符号常量
像定义变量一样使用一个名称来表示一个常量的值,称之为符号常量。
举例:
使用#define定义符号常量
#define NUM 666
#define STR "点赞收藏"
#define NUM2 888
#define S NUM*NUM2 //使用已定义的常量来定义新的常量
③常变量
经过const修饰的变量拥有不可更改的特点,因此符合常量的定义。但const修饰的是一个变量,即使它不可更改了本质上依然是个变量,所以称之为常变量。
举例:
const int pi = 3.14
但const声明的常变量只能在声明的同时进行初始化,一旦声明完成就存在了默认值,再次进行初始化就相当于修改它的值了,程序将会报错
const int pi;
pi = 3.14;
//这样写是不行的!会报错!
④枚举常量
上文已经对枚举类型进行过说明,不过多赘述。
枚举常量在程序中可以像普通变量一样使用,例如用于赋值、比较和作为函数参数等。它们提供了一种方便的方式来表示有限的、离散的取值范围,提高了代码的可读性和可维护性。
格式:
enum 枚举类型名 {
枚举常量1,
枚举常量2,
...
};