return 语句
在入门例子程序中,return 语句是最后一条语句。int main(void)
中的 int 表明 main() 函数应返回一个整数。有返回值的 C 函数要有 return 语句,没有返回值的程序也建议大家保留 return 关键字,这是一种好的习惯或者说统一的编码风格。
分号
在 C 语言中,每一行的结尾都要用 ;
进行结束,它表示一个语句的结束,如果忘记或者会略分号会被编译器提示错误。
关键字
下面是 C 语言中的关键字,C 语言的关键字一共有 32
个,根据其作用不同进行划分
数据类型关键字
数据类型的关键字主要有 12 个,分别是
char
: 声明字符型变量或函数double
: 声明双精度变量或函数float
: 声明浮点型变量或函数int
: 声明整型变量或函数long
: 声明长整型变量或函数short
: 声明短整型变量或函数signed
: 声明有符号类型变量或函数_Bool
: 声明布尔类型_Complex
:声明复数_Imaginary
: 声明虚数unsigned
: 声明无符号类型变量或函数void
: 声明函数无返回值或无参数,声明无类型指针
控制语句关键字
控制语句循环的关键字也有 12 个,分别是
循环语句
for
: for 循环,使用的最多do
:循环语句的前提条件循环体while
:循环语句的循环条件break
: 跳出当前循环continue
:结束当前循环,开始下一轮循环
条件语句
if
:条件语句的判断条件else
: 条件语句的否定分支,与 if 连用goto
: 无条件跳转语句
开关语句
switch
: 用于开关语句case
:开关语句的另外一种分支default
: 开关语句中的其他分支
返回语句
retur
:子程序返回语句(可以带参数,也看不带参数)
存储类型关键字
auto
: 声明自动变量 一般不使用extern
: 声明变量是在其他文件正声明(也可以看做是引用变量)register
: 声明寄存器变量static
: 声明静态变量
其他关键字
const
: 声明只读变量sizeof
: 计算数据类型长度typedef
: 用以给数据类型取别名volatile
: 说明变量在程序执行中可被隐含地改变
C 中的数据
我们在了解完上面的入门例子程序后,下面我们就要全面认识一下 C 语言程序了,首先我们先来认识一下 C 语言最基本的变量与常量。
变量和常量
变量和常量是程序处理的两种基本对象。
有些数据类型在程序使用之前就已经被设定好了,在整个过程中没有变化(这段话描述不准确,但是为了通俗易懂,暂且这么描述),这种数据被称为常量(constant)
。另外一种数据类型在程序执行期间可能会发生改变,这种数据类型被称为 变量(variable)
。例如 int number
就是一个变量,而3.1415
就是一个常量,因为 int number 一旦声明出来,你可以对其任意赋值,而 3.1415 一旦声明出来,就不会再改变。
变量名
有必要在聊数据类型之前先说一说变量名的概念。变量名是由字母和数字组成的序列,第一个字符必须是字母。在变量名的命名过程中,下划线 _
被看作字母,下划线一般用于名称较长的变量名,这样能够提高程序的可读性。变量名通常不会以下划线来开头。在 C 中,大小写是有区别的,也就是说,a 和 A 完全是两个不同的变量。一般变量名使用小写字母,符号常量(#define 定义的)全都使用大写。选择变量名的时候,尽量能够从字面上描述出变量的用途,切忌起这种 abc 毫无意义的变量。
还需要注意一般局部变量都会使用较短的变量名,外部变量使用较长的名字。
数据类型
在了解数据类型之前,我们需要先了解一下这些概念 位、字节和字。
位、字节和字都是对计算机存储单元的描述。在计算机世界中,最小的单元是
位(bit)
,一个位就表示一个 0 或 1,一般当你的小伙伴问你的电脑是 xxx 位,常见的有 32 位或者 64 位,这里的位就指的是比特,比特就是 bit 的中文名称,所以这里的 32 位或者 64 位指的就是 32 bit 或者 64 bit。字节是基本的存储单元,基本存储单元说的是在计算机中都是按照字节来存储的,一个字节等于 8 位,即 1 byte = 8 bit。字是自然存储单位,在现代计算机中,一个字等于 2 字节。
C 语言的数据类型有很多,下面我们就来依次介绍一下。
整型
C 语言中的整型用 int
来表示,可以是正整数、负整数或零。在不同位数的计算机中其取值范围也不同。不过在 32 位和 64 位计算机中,int 的取值范围是都是 2^32 ,也就是 -2147483648 ~ +2147483647,无符号类型的取值范围是 0 ~ 4294967295。
整型以二进制整数存储,分为有符号数和无符号数两种形态,有符号数可以存储正整数、负整数和零;无符号只能存储正整数和零。
可以使用 printf 打印出来 int 类型的值,如下代码所示。
#include <stdio.h> int main(){ int a = -5; printf("%d\n",a); unsigned int b = 6; printf("%d\n",b); }
C 语言还提供 3 个附属关键字修饰整数类型,即 short、long 和 unsigned。
- short int 类型(或者简写为 short)占用的存储空间
可能
比 int 类型少,适合用于数值较小的场景。 - long int 或者 long 占用的存储空间
可能
比 int 类型多,适合用于数值较大的场景。 - long long int 或者 long long(C99 加入)占用的存储空间比 long 多,适用于数值更大的场合,至少占用 64 位,与 int 类似,long long 也是有符号类型。
- unsigned int 或 unsigned 只用于非负值的场景,这种类型的取值范围有所不同,比如 16 位的 unsigned int 表示的范围是 0 ~ 65535 ,而不是 -32768 ~ 32767。
- 在 C90 标准中,添加了 unsigned long int 或者 unsigned long 和 unsigned short int 或 unsigned short 类型,在 C99 中又添加了 unsigned long long int 或者 unsigned long long 。
- 在任何有符号类型前面加 signed ,可强调使用有符号类型的意图。比如 short、short int、signed short、signed short int 都表示一种类型。
比如上面这些描述可以用下面这些代码来声明:
long int lia; long la; long long lla; short int sib; short sb; unsigned int uic; unsigned uc; unsigned long uld; unsigned short usd;
这里需要注意一点,unsigned 定义的变量,按照 printf 格式化输出时,是能够显示负值的,为什么呢?不是 unsigned 修饰的值不能是负值啊,那是因为 unsigned 修饰的变量,在计算时会有用,输出没什么影响,这也是 cxuan 刚开始学习的时候踩的坑。
我们学过 Java 的同学刚开始都对这些定义觉得莫名其妙,为什么一个 C 语言要对数据类型有这么多定义?C 语言真麻烦,我不学了!
千万不要有这种想法,如果有这种想法的同学,你一定是被 JVM 保护的像个孩子!我必须从现在开始纠正你的这个想法,因为 Java 有 JVM 的保护,很多特性都做了优化,而 C 就像个没有伞的孩子,它必须自己和这个世界打交道!
上面在说 short int 和 long int 的时候,都加了一个可能,怎么,难道 short int 和 long int 和 int 还不一样吗?
这里就是 C 语言数据类型一个独特的风格。
为什么说可能,这是由于 C 语言为了适配不同的机器来设定的语法规则,在早起的计算机上,int 类型和 short 类型都占 16 位,long 类型占 32 位,在后来的计算机中,都采用了 16 位存储 short 类型,32 位存储 int 类型和 long 类型,现在,计算机普遍使用 64 位 CPU,为了存储 64 位整数,才引入了 long long 类型。所以,一般现在个人计算机上常见的设置是 long long 占用 64 位,long 占用 32 位,short 占用 16 位,int 占用 16 位或者 32 位。
char 类型
char 类型一般用于存储字符,表示方法如下
char a = 'x'; char b = 'y';
char 被称为字符类型,只能用单引号 '' 来表示,而不能用双引号 “” 来表示,这和字符串的表示形式相反。
char 虽然表示字符,但是 char 实际上存储的是整数而不是字符,计算机一般使用 ASCII
来处理字符,标准 ASCII 码的范围是 0 - 127 ,只需 7 位二进制数表示即可。C 语言中规定 char 占用 1 字节。
其实整型和字符型是相通的,他们在内存中的存储本质是相通的,编译器发现 char ,就会自动转换为整数存储,相反的,如果给 int 类型赋值英文字符,也会转换成整数存储,如下代码
#include <stdio.h> int main(){ char a = 'x'; int b; b = 'y'; printf("%d\n%d\n",a,b); }
输出
120
121
所以,int 和 char 只是存储的范围不同,整型可以是 2 字节,4 字节,8 字节,而字符型只占 1 字节。
有些 C 编译器把 char 实现为有符号类型,这意味着 char 可表示的范围是 -128 ~ 127,而有些编译器把 char 实现为无符号类型,这种情况下 char 可表示的范围是 0 - 255。signed char 表示的是有符号类型,unsigned char 表示的是无符号类型。
_Bool 类型
_Bool 类型是 C99 新增的数据类型,用于表示布尔值。也就是逻辑值 true 和 false。在 C99 之前,都是用 int 中的 1 和 0 来表示。所以 _Bool 在某种程度上也是一种数据类型。表示 0 和 1 的话,用 1 bit(位)表示就够了。
float、double 和 long double
整型对于大多数软件开发项目而言就已经够用了。然而,在金融领域和数学领域还经常使用浮点数
。C 语言中的浮点数有 float、double 和 long double 类型。浮点数类型能够表示包括小数在内更大范围的数。浮点数能表示小数,而且表示范围比较大。浮点数的表示类似于科学技术法。下面是一些科学记数法示例:
数字 | 科学记数法 | 指数记数法 |
1000000000 | 1 * 10^9 | 1.0e9 |
456000 | 4.56 * 10^5 | 4.56e5 |
372.85 | 3.7285 * 10 ^ 2 | 3.7285e2 |
0.0025 | 2.5 * 10 ^ -3 | 2.5e-3 |
C 规定 float 类型必须至少能表示 6 位有效数字,而且取值范围至少是 10^-37 ~ 10^+37。通常情况下,系统存储一个浮点数要占用 32 位。
C 提供的另一种浮点类型是 double(双精度类型)。一般来说,double 占用的是 64 位而不是 32 位。
C 提供的第三种类型是 long double ,用于满足比 double 类型更高的精度要求。不过,C 只保证了 long double 类型至少与 double 类型相同。
浮点数的声明方式和整型类似,下面是一些浮点数的声明方式。
#include <stdio.h> int main(){ float aboat = 2100.0; double abet = 2.14e9; long double dip = 5.32e-5; printf("%f\n", aboat); printf("%e\n", abet); printf("%Lf\n", dip); }
printf() 函数使用 %f 转换说明打印十进制计数法的 float 和 double 类型浮点数,用 %e 打印指数记数法的浮点数。打印 long double 类型要使用 %Lf 转换说明。
关于浮点数,还需要注意其上溢
和下溢
的问题。
上溢指的是是指由于数字过大,超过当前类型所能表示的范围,如下所示
float toobig = 3.4E38 * 100.0f; printf("%e\n",toobig);
输出的内容是 inf
,这表示 toobig 的结果超过了其定义的范围,C 语言就会给 toobig 赋一个表示无穷大的特定值,而且 printf 显示值为 inf 或者 infinity 。
下溢:是指由于数值太小,低于当前类型所能表示的最小的值,计算机就只好把尾数位向右移,空出第一个二进制位,但是与此同时,却损失了原来末尾有效位上面的数字,这种情况就叫做下溢。比如下面这段代码
float toosmall = 0.1234e-38/10; printf("%e\n", toosmall);
复数和虚数类型
许多科学和工程计算都需要用到复数和虚数,C99 标准支持复数类型和虚数类型,C 语言中有 3 种复数类型:float _Complex、double _Complex 和 long double _Complex。
C 语言提供的 3 种虚数类型:float _Imaginary、 double _Imaginary 和 long double _Imaginary。
如果包含 complex.h 头文件的话,便可使用 complex 替换 _Complex,用 imaginary 替代 _Imaginary。
其他类型
除了上述我们介绍过的类型之外,C 语言中还有其他类型,比如数组、指针、结构和联合,虽然 C 语言没有字符串类型,但是 C 语言却能够很好的处理字符串。
常量
在很多情况下我们需要常量,在整个程序的执行过程中,其值不会发生改变,比如一天有 24 个小时,最大缓冲区的大小,滑动窗口的最大值等。这些固定的值,即称为常量,又可以叫做字面量。
常量也分为很多种,整型常量,浮点型常量,字符常量,字符串常量,下面我们分别来介绍
整数常量
整数常量可以表示为十进制、八进制或十六进制。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。
330 /* 合法的 */ 315u /* 合法的 */ 0xFeeL /* 合法的 */ 048 /* 非法的:8 进制不能定义 8 */
浮点型常量
浮点型常量由整数部分、小数点、小数部分和指数部分组成。你可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。
3.14159 /* 合法的 */ 314159E-5L /* 合法的 */ 510E /* 非法的:不完整的指数 */ 210f /* 非法的:没有小数或指数 */
字符常量
C 语言中的字符常量使用单引号(即撇号)括起来的一个字符。如‘a’,‘x’,'D',‘?’,‘$’ 等都是字符常量。注意,‘a’ 和 ‘A’ 是不同的字符常量。
除了以上形式的字符常量外,C 还允许用一种特殊形式的字符常量,就是以一个 “\” 开头的字符序列。例如,前面已经遇到过的,在 printf 函数中的‘\n’,它代表一个换行符。这是一种控制字符,在屏幕上是不能显示的。
常用的以 “\” 开头的特殊字符有
表中列出的字符称为“转义字符”,意思是将反斜杠(\)后面的字符转换成另外的意义。如 ‘\n’ 中的 “n” 不代表字母 n 而作为“换行”符。
表中最后第 2 行是用ASCII码(八进制数)表示一个字符,例如 ‘\101’ 代表 ASCII 码(十进制数)为 65 的字符 “A”。‘\012’(十进制 ASCII 码为 10)代表换行。
需要注意的是 ‘\0’ 或 ‘\000’ 代表 ASCII 码为 0 的控制字符,它用在字符串中。
字符串常量
字符串常量通常用 "" 进行表示。字符串就是一系列字符的集合。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
常量定义
C 语言中,有两种定义常量的方式。
- 使用
#define
预处理器进行预处理 - 使用
const
关键字进行处理
下面是使用 #define 预处理器进行常量定义的代码。
#include <stdio.h> #define LENGTH 5 #define WIDTH 10 int main(){ int area = LENGTH * WIDTH; printf("area = %d\n", area); }
同样的,我们也可以使用 const 关键字来定义常量,如下代码所示
#include <stdio.h> int main(){ const int LENGTH = 10; const int WIDTH = 5; int area; area = LENGTH * WIDTH; printf("area = %d\n", area); }
那么这两种常量定义方式有什么不同呢?
编译器处理方式不同
使用 #define 预处理器是在预处理阶段进行的,而 const 修饰的常量是在编译阶段进行。
类型定义和检查不同
使用 #define 不用声明数据类型,而且不用类型检查,仅仅是定义;而使用 const 需要声明具体的数据类型,在编译阶段会进行类型检查。