这章的内容多而复杂,不过我们还是可以抽丝剥茧,由表及里,融会贯通,多思考,多实践,比方说链接属性,还有变量的生命周期等。先看看本章的知识体系。
1 内容概览
程序对数据进行操作,那么对数据本身的了解就显得尤为重要。本章不仅介绍了各种类型变量的数据范围,还有声明方法等。另外本章还详细介绍了变量的三个属性——作用域、链接属性和存储类型。
2 详细内容
2.1 基本数据类型
2.1.1 整型
整型包括字符型、短整型、整型和长整型。然后每种又都可以分为有符号和无符号两种,所以细分应该是9种类型。
有一点非常重要:长整型不一定比整型长,短整型不一定比整型短,这是又编译器的设计者决定的。在设计中,短整型至少16位,长整型至少32位。
类型 | 最小范围 |
char | 0-127 |
signed char | -127-127 |
unsigned char | 0-255 |
short int | -32767-32767 |
unsigned short int | 0-65535 |
int | -32767-32767 |
unsigned int | 0-65535 |
long int | -2147483647-2147483647 |
unsigned long int | 0-4294967295 |
只需要记住:short至少16位,long int至少32位,然后char的类型也经常用到即可。
2.1.2 枚举类型
枚举类型意思就是值为符号常量,而不是字面值的类型,这样做的目的是非常轻松简单地去通过某些符号表示数据。比方说在某条程序中,性别用0表示男性,1表示女性,但是这样经常容易记混,对开发非常不友好,这个时候就可以采用枚举类型进行程序的编写。比如:
enum sex { man , woman }; int main() { int human_sex = 0; if (human_sex == man) { printf("该用户为男性\n"); system("pause"); } else if(human_sex == woman) { printf("该用户为女性\n"); system("pause"); } }
这样在定义了枚举类型之后,好处有两点:
- 可以直接用定义好的名称,而无需记住对应关系,这仅仅是两个变量,要是变量多的时候,信息就更加复杂,给编程带来了很多困扰,采用这种形式就可以很好地解决。
- 如果数据是连续的整型值,则无需编辑每个符号的值,默认从零开始,若不是从零开始,则只需要给第一个符号赋值,后面的符号自动连续赋值。
2.1.3 浮点类型
浮点类型,说白了就是该变量表示的数值带有小数点。浮点数包括float、double和long double三种类型。默认情况下是double类型。
2.1.4 指针
网上有很多说法,声称指针是C语言的灵魂,确实是这样,正因为指针的存在,可以使C语言有效地实现树和链表等高级数据结构。书上提到了指针常量和字符串常量。关于指针常量,会在后面的2.4小节进行详细介绍。而字符串常量,指的是一般我们定义了一个字符串,就不允许修改,当然这和具体的编译器有关系,一般现代的编译器都不允许修改。
2.2 基本声明
声明变量的基本形式是:
说明符(一个或多个) 声明表达式列表
2.2.1 初始化
所谓的初始化,是指在变量声明的时候,可以给变量一个初始值。而在有的编译器或者有的情况下,在变量声明的时候,必须要初始化,否则会报错。比如局部变量。
2.2.2 声明简单数组
数组的声明很简单,可以直接用元素类型+数组名称+元素数量的方法进行声明。
int a[20];
需要注意的有两点:
- 定义数组的时候,开辟的是连续的存储空间,这就意味着,我们常见的增删改查四种操作中,对于改和查比较方便,然而增和删相对来说比较复杂,对于频繁增删的一位数据结构,可以采用链表,不过C语言需要自己去创建。
- 定义了int类型的数组,意味着该数组中只能存储int类型的数值,而不是像python,内置的容器可以存储很多种类的数值。
2.2.3 声明指针
指针的声明方式和变量很类似,比方说,要定义一个指向int类型的指针p,就可以像这样。
int *p; int* p;
虽然两个语句的作用完全一样,但是比较建议采用第一种方式,因为第二种往往会引起歧义,比方说:
int* p,a,b;
感觉像是定义了三个指针p,a,b,而实际上只定义了一个指针,另外两个是int类型的变量。
2.2.4 隐式声明(不建议使用,了解即可)
隐式声明,意思是在某些情况下,类型名可以省略,比方说,函数的返回值,再比如,函数的定义中,如果不声明变量的类型,则会默认为整形。
不过一般情况下不建议省略,因为有的编译器会编译不通过。
2.3 typedef
这是C语言的一种机制,允许用户为各种数据类型定义新名字。这就相当于给某种类型的数据起“绰号”,其格式如下(一般情况下,新名称):
typedef oldName newName;
- int类型变量起别名
typedef int NEW; NEW a = 10;
相当于定义了一个int类型的变量a,并给它赋初值10。
2. 数组起别名
typedef char ARRAY20[20]; ARRAY20 a1, a2, s1, s2;
这里有定义了一个20个元素的数组,后面的定义就会方便一些。
- 结构体起别名
typedef struct stu{ char name[20]; int age; char sex; } STU; STU body1,body2;
这样在定义行的结构体变量的时候,同样比之前方便一些,此前的方法是:
struct stu body1, body2;
- 给指针起别名
typedef char *ptr_to_char;
这样就将ptr_to_char定义为了指向字符的指针。
2.4 常量
常量顾名思义,很容易理解,就是变量一旦定义,就不允许修改它的值。有四种类型的常量,分别是:变量常量化、指针常量、常量指针以及常指针常量(或者称作:指向常量的常指针)定义方式如下:
const int a; int const a; int const *p; int *const p; int const *const p;
- 第一行和第二行只是形式上的区别,都定义了一个常量a。
- 第三行定义了一个指向常量的指针,所叫做常量指针。
- 第四行定义了一个地址不可变的指针,所以叫做指针常量,也就是,指针本身是常量。
- 第五行则定义了一个常指针常量,意思就是指针指向的地址是不可变的,而且地址存储的值也是不可变的。
2.5 作用域
当变量在程序的某个部分被声明时,它只有在程序的一定区域才能被访问。这个区域由变量的作用域决定。
编译器可以确认的4种不同类型的作用域——文件作用域、函数作用域、代码块作用域和原型作用域。
- 文件作用域:代码块之外声明的标识符都具有文件作用域。
- 函数作用域:只适用于语句标签,语句标签用于goto语句,由于一般在编程中不提倡使用goto语句,所以这里只需要了解就行。
- 代码块作用域:一对花括号中间的的语句成为一个代码块,代码块的开头部分声明的标识符都具有代码块作用域。
- 原型作用域:函数原型作用域用于函数原型中的形参名,其范围从形参定义处到原型声明结束。也就是在函数的声明中使用的形参。参数的名字非必需。例如:
int * reverseStr(int * s, int k);
这样的函数声明,也可以写成下面这样的形式。
int * reverseStr(int * , int );
这样的做法很好理解,在函数声明的时候,形参没有具体的含义,只有在函数的定义中,才能凸显函数的形参的具体作用(虽然没有传入具体的值),所以此时只需要告诉计算机参数的类型即可。
2.6 链接属性
当标识符出现在不同的文件中的时候,当前文件的可否访问其他文件的变量呢?这个就是由变量的链接属性决定的。
链接属性有三种:external(外部)、internal(内部)和none(无)。
1.外连接:外部链接属性,可以在整个程序范围内进行链接,譬如函数和全局变量;
2.内链接:内部链接属性,也就是只可以在当前C文件内部进行链接,不能在当前C文件外的文件中进行访问、链接,如static修饰的函数、全局变量属于内部链接,因此可知static关键字的一个用法就是将变量或者函数的链接属性由外部链接为内部链接,使得被修饰的变量只能在当前文件中被使用;
3.无链接:标识符不参与链接,所有的局部变量都是无链接的。
如下图所示:
2.7 存储类型
所谓的存储类型,指的是变量根据存储位置进行分类,这样一来,变量可分为静态变量、自动变量和寄存器变量三类。
- 凡是在任何代码块之外声明的变量总是存储于静态内存中,也就是不属于堆栈的内存,这类变量被称为静态变量。静态变量在程序运行之前创建,在程序的整个执行期间始终存在。它始终保持原先的值,除非给它赋其他的值,或者程序运行结束。
- 在程序执行到该代码块时,自动变量才被创建,而当程序的执行流离开代码块时,这些自动变量便自行销毁。
- 关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器而不是内存,这类变量被称为寄存器变量。只不过编译器不一定会“理睬”该关键字。因此寄存器变量不是很常用。
2.8 static关键字
在不同的情况下,会有不同的作用,总共分两种情况。正如思维导图中提到的那样(见下图)。
3 本章总结
- 本章内容非常多,也有少部分不好理解,很多部分也是面试的必考题目,比方说,之前我面试某大厂的时候,就别问到static关键字的作用,等等等等。
- 关于数组和指针,这是C语言非常常见且重要的会在后续的章节展开讲解,一些细节没有完全理解也没有关系。
--------------------------------------------------------------------------END-------------------------------------------------------