![零基础趣学C语言](https://wfqqreader-1252317822.image.myqcloud.com/cover/763/25916763/b_25916763.jpg)
2.3 基本数据类型
前面讲过,在C语言中数据类型分为常量与变量两种,但是不论是常量还是变量都是有数据类型的,常量的数据类型在使用时由系统自动给出,变量的数据类型在定义变量时,由用户指定。系统会根据变量的数据类型,在内存中开辟对应的内存空间,用于存储数据。本章将介绍C语言中常用的数据类型。
2.3.1 数据类型引入
C语言中数据分为两种:变量和常量。但是不论是变量还是常量都必须有数据类型。常量的数据类型在引用时自动声明,如1、20、500表示整数类型常量,3.14、6.18表示浮点类型常量,'a'、'b'表示字符类型常量。而变量的数据类型在变量定义时,通过char、short、int、float、double等关键字指定。
C语言中,定义变量的一般形式为:
变量类型 变量名 = 变量值;
例如:
int a = 100;
说明: (1)变量类型就是变量可以保存的数据类型。
(2)int是关键字,表示变量类型为整数类型,用于修饰变量。
(3)a是变量名,必须是合法的标识符。
(4)这里的“=”并不是数学中的等号,而是赋值运算符,表示将“=”右侧的数据赋给“=”左侧的变量。
(5)100是赋给变量a的值。
现阶段,读者只需简单了解变量即可,后续章节中会详细介绍。
数据类型的意义
为了形象地理解数据与数据类型的意义,这里以水果与盒子为例,可以把数据比作各种水果,把数据类型比作盒子的型号。当存放樱桃时,需要小盒子;当存放苹果时,需要中等盒子;当存放哈密瓜时,需要大盒子,如图2-7所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0037-0046.jpg?sign=1739038359-aRjJN45Rv9c4trVrd7n7QxQmt3ZuAct5-0-61745c094c93c6f443b14f0fa733ab88)
图2-7 数据类型示意图
通过上述分析,可以看到水果的种类不同,对应盒子的规格也不一样,其实数据与数据类型也是如此。在C语言程序中,无论是常量还是变量,最终都存储在计算机内存中。不过由于常量或变量的类型不同,导致需要的存储空间大小不同。为了解决这种问题,C语言引入了数据类型,在程序编译期间,编译器会根据常量或变量的类型分配对应大小的内存空间来保存数据。
所谓的数据类型,指的是数据在内存中的组织形式,组织形式又可以分为2部分:
第一部分,数据存储格式:补码或阶码;
第二部分,数据存储所占字节数。
说明: 由于补码与阶码较为复杂,不在本书讨论范围内。本章只介绍第二部分,数据在内存中存储所占字节数。
C语言提供了丰富的数据类型,不过本章只介绍几种常用的数据类型:字符型、整数类型、浮点类型,后续章节中会详细介绍其他数据类型。
2.3.2 整数类型
整数类型简称整型,在C语言中整型有以下几种。
(1)基本整型(int)。
(2)短整型(short int或short)。
(3)长整型 (long int或long)。
(4)双长整型(long long int或long long)。
在实际编程中最为常用的是基本整型(int),本节将详细介绍,其他整数类型在后续章节中使用到时再作介绍。
基本整型(int)
在32位操作系统下,C语言编译器会给基本整数类型数据或变量分配4字节内存空间。int类型表示的范围为:-2147483648~2147483647。程序中在变量名前面加关键字int可以定义整数类型变量(简称整型变量),如int a。int类型数据在printf函数中一般采用%d格式进行输出,其中d表示十进制整数形式。
【示例2-5】 整型变量的定义与输出。
1 #include<stdio.h>
2 int main()
3 {
4 int a=200;
5 printf("%d\n",a);
6 getchar();
7 return 0;
8 }
运行结果如图2-8所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0038-0047.jpg?sign=1739038359-GVEV6jvb9YqIpXRyTRP1LWxl6xHSojAs-0-1cc9e4b7d66986af3006020879ef315c)
图2-8 运行结果
【程序分析】
1.在执行第4行程序时,程序会先在内存中开辟4字节空间,并标记为a,然后把整数200存储在变量a对应的内存空间中。
2.在执行第5行程序时,程序会先读取变量a对应内存空间中的数据200,然后替换printf中的%d。
2.3.3 浮点数类型
浮点数类型又称实数类型,在C语言中浮点数类型有以下几种。
(1)单精度浮点型(float)。
(2)双精度浮点型(double)。
(3)长双精度浮点型(long double)。
在实际编程中最为常用的是单精度浮点类型(float)、双精度浮点型(double)。本节将详细介绍,长双精度浮点型基本不会使用,本书不作讨论。
1. 单精度浮点型(float)
在32位操作系统下,C语言编译器会给单精度浮点型数据或变量分配4个字节的内存空间。程序中在变量名前加关键字float可以定义单精度浮点型变量,如float f;。float型数据能得到6~7位有效数字,取值范围为:-3.4×1038~3.4×1038,float类型数据在printf函数中一般采用%f格式进行输出,f表示“十进制小数”形式。
【示例2-6】单精度浮点型变量的定义与输出。
1 #include<stdio.h>
2 int main()
3 {
4 float f=3.14;
5 printf("%f\n",f);
6 getchar();
7 return 0;
8 }
运行结果如图2-9所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0038-0048.jpg?sign=1739038359-mJPZp8veAy8M9NyZkHRe04dCzRn0uHfc-0-dfa601669be4031145fac33f376985a8)
图2-9 运行结果
【程序分析】
(1)执行第4行程序时,先在内存中开辟4字节空间,并标记为f,然后把浮点数3.14存储在f标记的内存空间中,3.14后面的f表示这是单精度浮点数。
(2)执行第5行程序时,先读取变量f对应内存空间中的数据3.14,然后替换printf中的%f。
说明: 在VS2012中,不管是float还是double类型,默认情况下都只输出小数点后6位;如果不够6位,使用0进行填补。
2. 双精度浮点型(double)
在32位操作系统下,C语言编译器会给双精度浮点型数据或变量分配8个字节内存空间。程序中在变量名前面加关键字double可以定义双精度浮点型变量,例如:double d;。双精度浮点型数据能得到15~16位有效数字,取值范围为:-1.7×10308~1.7×10308,double类型数据在printf函数中一般采用%lf格式进行输出,lf表示“十进制小数”形式。
【示例2-7】双精度浮点型变量的定义与输出。
1 #include<stdio.h>
2 int main()
3 {
4 double d=3.14;
5 printf("%lf\n",d);
6 getchar();
7 return 0;
8 }
运行结果如图2-10所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0039-0049.jpg?sign=1739038359-xyjjLycnQ9rdAoaeCIK2NKJiOSwgClaw-0-1406320bf714e39601aaac8ce8bd0c48)
图2-10 运行结果
【程序分析】
(1)执行第4行程序时,先在内存中开辟8字节空间,并标记为d,然后把浮点数3.14存储在d标记的内存空间中。
(2)执行第5行程序时,先读取变量d对应内存空间中的数据3.14,然后替换printf中的%lf。
2.3.4 字符型
在C语言中,字符类型只有一种:字符类型(char)。
32位操作系统下,C语言编译器会给字符型数据分配1个字节内存空间。程序中在变量名前面加关键字char可以定义字符型变量,如:
char c;
char类型取值范围为:-128 ~127,char类型数据在printf函数中一般采用%c格式进行输出, c表示“字符”形式。
【示例2-8】字符型变量的定义与输出。
1 #include<stdio.h>
2 int main()
3 {
4 char c='A';
5 printf("%c\n",c);
6 getchar();
7 return 0;
8 }
运行结果如图2-11所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0040-0050.jpg?sign=1739038359-YmaEV7CQKjRQGRw5fzz6Srjc2OJbKK17-0-11a9267cedf8a5c6159cc4a1f5f18821)
图2-11 运行结果
【程序分析】
1.执行第4行程序时,先在内存中开辟1字节空间,并标记为c,然后把字符'A'对应的ASCII码97,存储在c标记的内存空间中。
2.执行第5行程序时,先读取变量c对应内存空间中的数据97,然后替换printf中的%c,由于%c表示字符格式,因此不能直接输出整数97,而是输出97对应的字符'A'。
字符在内存中是按照其对应的ASCII码进行存储,而ASCII码本质上也是整数。因此,字符型可以看作是整型的一种,当然也就可以按照%d格式输出。下面通过程序了解一下。
【示例2-9】输出字符对应的ASCII码。
1 #include<stdio.h>
2 int main()
3 {
4 char c='A';
5 printf("%c\n",c);
6 printf("%d\n",c);
7 getchar();
8 return 0;
9 }
运行结果如图2-12所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0040-0051.jpg?sign=1739038359-Z0Zcm45D92FuQ4bW0FBV8Uqz66YzRfa0-0-7342ef7456bedeb0f6092f0ccc47b5b2)
图2-12 运行结果
【程序分析】
1.根据输出结果可以看到,字符'A'对应的十进制为65,其实65就是字符'A'对应的ASCII码,在计算机内存中最终存储的就是整数65,而不是字符'A'。之所以会输出字符'A',是因为计算机中有一张ASCII码表,通过这张表就可以找到65对应的字符'A'。同理,根据字符'A',也可以找到该字符对应的ASCII码值是多少。
2.实际编程中,需要记住常见的3个字符对应的ASCII码。
大写字母'A'的ASCII码是65。
小写字母'a'的ASCII码是97。
数字字符'0'的ASCII码是48。
根据以上3个字符可以推算出,字符'A'~'Z'的ASCII码、'a'~'z'的ASCII码、字符'0'~'9'的ASCII码。
3.C语言中,常用字符与对应ASCII如表2-2所示。
4.对于字符型数据,如果采用%c就是按照字符形式输出,如果采用%d就是按照字符对应的ASCII码输出。
表2-2 ASCII码表
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0041-0052.jpg?sign=1739038359-bnM1M89jm17KjewwjzVyvr6QmXX7V1C8-0-94be234708d4e8b6ab7d6b9d8037417b)
2.3.5 转义字符
在C语言中,有一类特殊字符,该类字符是以字符“\”开头的字符序列。例如,前面在printf函数中多次使用的'\n',它代表一个“换行”符。这类字符有别于其他普通字符,无法在屏幕上显示,而且无法用一般形式表示,只能采用这种特殊的形式表示,这类字符被称为转义字符。
常用的转义字符及对应的ASCII码如表2-3所示。
表2-3 转义字符表
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0042-0053.jpg?sign=1739038359-0lmG4GdbS7Wfbp7Ul4DfTxr7sMvFzg2v-0-bd43a9644765d0d500fd645c1037915b)
可以看到,C语言提供了丰富的转义字符,不过本节只介绍常用的转义字符,后续章节中使用到其他转义字符时,再做详细介绍。
1.'\n' 代表回车换行
【示例2-10】'\n'字符的意义。
1 #include<stdio.h>
2 int main()
3 {
4 printf("www.rupeng.com\n");
5 printf("www.rupeng.\ncom");
6 getchar();
7 return 0;
8 }
运行结果如图2-13所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0042-0054.jpg?sign=1739038359-GS9VTl9VIPkBT1SrEtaTUvRLKUfPbafK-0-d123d320947b27eb560b5f3aeacb21eb)
图2-13 运行结果
【程序分析】
(1)第4行,先输出字符串"www.rupeng.com",然后遇到转义字符'\n', 将当前输出位置移到下一行开头。
(2)第5行,由于上一行程序中输出了回车换行符'\n',所以第5行程序从下一行开始显示。先输出字符串"www.rupeng",然后遇到转义字符'\n', 将当前输出位置移到下一行开头,最后输出字符串".com"。
(3)通过上述分析,可以看到,只要在printf函数中遇到'\n',就将当前输出位置移到下一行开头,然后输出余下的内容。
2.\'代表单引号字符(' )
由于在C语言中,单引号已经被用于作为字符的开始与结束,也就是说,单引号一般都是成对出现的。例如,普通字符:'A'、'#'、'1'等,或者是转义字符'\n'。但是,单引号(')也是字符,该如何表示呢?有些读者很自然的想到了下面的写法:
''' //错误写法
这是一种错误写法,前面已经讲过单引号(')有特殊意义:当编译器读取到第一个单引号时认为是字符的开始,读取到第二个单引号时认为是字符的结束,然后把两个单引号之间的内容当做字符解析。因此,'''会被编译器解析为图2-14所示形式。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0043-0055.jpg?sign=1739038359-dwF4W2hQkXm8hlpSKD4gIt8T03HpN434-0-2ce33881b620b3f56a5699c08700b344)
图2-14 单引号含义
由于编译器会把前两个单引号之间的内容当做字符解析,把第三个单引号当做字符开始标志对待,然后编译器会再去寻找下一个单引号当作字符的结束标志,如果找不到就报错。
为了解决这种问题, C语言使用“\”对单引号进行转义。例如,\',此时单引号就是普通字符,不再具有特殊的意义。
下面通过例子来了解一下\'的使用。
【示例2-11】 \'字符的意义。
1 #include<stdio.h>
2 int main()
3 {
4 printf("%c\n",'\'');
5 getchar();
6 return 0;
7 }
运行结果如图2-15所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0043-0056.jpg?sign=1739038359-AkJZvjtuTAdyRiiYyTn4ykhwPwXQv6hk-0-16e5ae453d80837a9a3fefd31b6c0581)
图2-15 运行结果
【程序分析】
第4行,使用“\”对单引号(')进行转义,此时单引号(')表示为普通字符,然后在printf函数中,按照字符格式输出,如图2-15所示。
除了转义之外,字符串中的单引号也会被当作普通字符进行解析,下面通过例子来了解一下。
【示例2-12】 字符串中的单引号。
1 #include<stdio.h>
2 int main()
3 {
4 printf("www.'rupeng'.com");
5 getchar();
6 return 0;
7 }
运行结果如图2-16所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0043-0057.jpg?sign=1739038359-fRKQz4W54LxtUPOoDQsUTFcSsVt7oj8d-0-be26bab3f0498d4b9a847338b7ebc314)
图2-16 运行结果
【程序分析】
根据运行结果,可以看到,字符串中的单引号没有被转义也照常输出,这是一种特殊现象,读者务必留意。
3. \"代表双引号字符(" )
由于在C语言中,双引号已经被用于作为字符串的开始与结束标志,也就是说,双引号一般都是成对出现的。例如,"ABC","#?*","123"等。但是,如果在字符串中显示双引号,该如何表示呢?有些读者很自然地想到了下面的写法。
"www.rupeng".com" //错误写法
这是一种错误写法,前面已经讲过双引号(")有特殊意义:当编译器读取到第一个双引号时认为是字符串的开始,读取到第二个双引号时认为是字符串的结束,然后把两个双引号之间的内容当作字符串解析。因此,"www.rupeng".com"会被编译器解析为图2-17所示形式。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0044-0058.jpg?sign=1739038359-yd304YUXPWsPsNeTgAC3Cw70wkeEgXKH-0-6bd415fa9889855aa0917b6d24b25c3d)
图2-17 双引号的使用
由于编译器会把前两个双引号之间的内容当做字符串解析,把第三个单引号当作字符串开始标志对待,然后编译器会再去寻找下一个双引号当作字符串的结束标志,如果找不到就报错。
为了解决这种问题, C语言使用“\”对双引号进行转义,例如,\",此时双引号就是普通字符,不再具有特殊意义。
下面通过例子来了解一下\"的使用。
【示例2-13】 \"的应用。
1 #include<stdio.h>
2 int main()
3 {
4 printf("www.rupeng\".com");
5 getchar();
6 return 0;
7 }
运行结果如图2-18所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0044-0059.jpg?sign=1739038359-CgcoyRzIRESKJ4KAonyh0ap9rsvglXGa-0-c8e65cf8d7fc586a403de07608316b3c)
图2-18 运行结果
【程序分析】
第4行,使用“\”将双引号(")转义,此时双引号(")为普通字符,和字符串中的字符w、g等共同作为字符串的内容。
4. \\ 代表单斜线字符(\)
通过前面几个转义字符的学习,读者已经看到字符(\)在C语言中有特殊意义:表示转义字符的开始标志。但是,单斜线(\)也是字符,该如何显示呢?有些读者很自然地想到了下面的写法:
'\' //错误的写法
很明显这是一种错误的写法,因为反斜线“\”会将后面的单引号转义,因此编译器会将后面的单引号当作普通的字符对待,导致字符没有正确结束,编译报错。
为了解决这种问题, C语言使用“\”对反斜线\进行转义,如:\\, 此时反斜线就是普通字符,不再具有特殊的意义。
下面通过例子来了解一下\\的使用。
【示例2-14】\\的应用。
1 #include<stdio.h>
2 int main()
3 {
4 printf("%c\n",'\\');
5 printf("www.\\rupeng.com");
6 getchar();
7 return 0;
8 }
运行结果如图2-19所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0045-0060.jpg?sign=1739038359-duooR7lo3OufNNq74UCvBtje8KDnO58j-0-5402364adc67d60926d881c3fea72d99)
图2-19 运行结果
【程序分析】
(1)第4行,使用“\”将反斜线(\)进行转义后,此时反斜线(\)表示普通字符,然后在printf函数中,按照字符格式输出,如图2-19第一行所示。
(2)第5行,使用“\”将反斜线(\)进行转义后,和字符串中的字符w、g等一起作为字符串的内容输出。
小贴士
程序中经常使用“\”表示系统路径分隔符,如图2-20所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0045-0061.jpg?sign=1739038359-DGcHZpuX0Bx7zXhwR2Rv1JbOBP6W9Lpr-0-57b8fb8560920017478013aacbfdaa01)
图2-20 路径分隔符
前面讲过,单独的“\”在C语言中有特殊意义,因此,要想在程序中输出该路径,必须使用“\\”,下面通过例子来了解一下。
【示例2-15】 打印系统路径。
1 #include<stdio.h>
2 int main()
3 {
4 printf("C:\Windows\System32\n");
5 printf("C:\\Windows\\System32");
6 getchar();
7 return 0;
8 }
运行结果如图2-21所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0045-0062.jpg?sign=1739038359-pP7MMiU12EjtviJkcxqbiBiwqv0loNGG-0-0939c92bae107f31a8b16f1c6de58a20)
图2-21 运行结果
【程序分析】
(1)根据输出结果,可以看到,第4行,没有对“\”进行转义,“\”仍然具有特殊意义,分别与字符W、S组成转义字符\W、\S。由于\W与\S在C语言中没有特殊意义,因此\W等价于W、\S等价于S字符原样输出;
(2)第5行,分别对两个反斜线“\”进行转义,字符串中的两个“\”会作为普通字符输出,如图2-21第2行所示。
2.3.6 字符与字符串的关系
在C语言中是没有字符串类型的,所谓的字符串本质上是由单个的字符构成。例如,"www. rupeng.com",可以看作由字符'w'、'w'、'w'、'.'、'r'、'u'、'p'、'e'、'n'、'g'、'.'、'c'、'o'、'm'组成。
下面通过例子来了解字符与字符串的关系。
【示例2-16】 字符与字符串的关系。
01 #include<stdio.h>
02 int main()
03 {
04 printf("www.rupeng.com\n");
05 printf("%c",'w');
06 printf("%c",'w');
07 printf("%c",'w');
08 printf("%c",'.');
09 printf("%c",'r');
10 printf("%c",'u');
11 printf("%c",'p');
12 printf("%c",'e');
13 printf("%c",'n');
14 printf("%c",'g');
15 printf("%c",'.');
16 printf("%c",'c');
17 printf("%c",'o');
18 printf("%c",'m');
19 getchar();
20 return 0;
21 }
运行结果如图2-22所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0046-0063.jpg?sign=1739038359-3xGGrXMmoZEHXGjaYbyH3qDEyzPrGLD9-0-ab45673a125e0e03f43302df39154b11)
图2-22 运行结果
【程序分析】
1.执行第4行程序时,先输出字符串"www.rupeng. com",然后执行\n,将输出位置移至下一行的开始。
2.执行第5~18行程序时,分别以%c的格式输出字符'w'、'w'、'w'、'.'、'r'、'u'、'p'、'e'、'n'、'g'、'.'、'c'、'o'、'm'。由于打印字符时,没有输出换行,因此输出结果与输出字符串"www.rupeng.com"效果是相同的。
3.其实在计算机底层,字符串是被拆分为单个字符进行存储的,输出时也按照存储的顺序连续输出。做个形象的比喻:如果把字符串当作一串糖葫芦,字符就是每一个山楂,如图2-23所示。
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0046-0064.jpg?sign=1739038359-wvp6ee4qug2FZfJHmBWwP9G1XGCFLS02-0-03b20d0b50d6fa8b547b9e77995d9750)
图2-23 字符串示意图
说明: 在C语言中,字符串末尾会隐式包含一个'\0',初学阶段不必深究。
2.3.7 printf与数据类型
为了方便查阅,在表2-4中分别列出了C语言中常用的数据类型在printf中对应的占位符。
表2-4 printf中常用的占位符
![](https://epubservercos.yuewen.com/4CF59A/14373745905390106/epubprivate/OEBPS/Images/figure-0047-0065.jpg?sign=1739038359-ZkuzA1JjinGhRvsYUJTbXRDRiufYh7Oe-0-c82fabf645438224d6ebf77eeb522f52)
printf中数据类型一定不能用错,float类型必须使用%f;int类型必须使用%d。如果使用错了就会产生错误的结果。如下面的错误代码:
printf("%f",3);
printf("%d",3.14);
从原理层面上分析,这涉及到数据在内存中表示格式的问题,初学阶段不用深入研究。另外,在printf中也可以同时使用多个占位符,只要前后和参数的类型、个数能够对得上就行,例如:
printf("name=%s , age=%d , height=%f" , "rupeng" , 18 , 3.14);