C基本语法
语法是一门编程语言的核心,只有掌握了语法之后,才能编写出合法的程序语句,完成项目的要求。
C语言的基本语法知识。
- 标识符和关键字
- 最基本的数据类型
- 常量和变量的深入理解
- 整型数据
- 实型数据
- 字符型数据
- 初始化变量
- 整型、实型和字符型数据间的运算总结
标识符和关键字
在C程序中,使用的变量名、函数名、标号等被统称为标识符。在C语言中,除了库函数的函数名由系统定义外,其余都是由用户自定义的。C语言规定,标识符只能是字母(A~Z。a~z)、数字(0~9)、下划线(_)组成的字符串,并且其第一个字符必须是字母或下划线。 例如下面的标识符都是合法的。
a
x
_3x
BOOK_1
sum5
而下面的标识符是非法的。
3s 以数字开头
s*T 出现非法字符*
-3x 以减号开头
bowy-1 出现非法字符-(减号)
使用标识符时必须注意以下几点。
- 标准C不限制标识符的长度,但它受各种版本的C语言编译系统限制,同时也受到具体机器的限制。例如在某版本C中规定标识符前8位有效,当两个标识符前8位相同时,则被认为是同一个标识符。
- 在标识符中,大小写是有区别的。例如BOOK和book是两个不同的标识符。
- 标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号,因此,命名应尽量有相应的意义,以便阅读理解,作到“顾名思义”。
- 所有标识符必须由一个字母(a~z、A~Z)或下划线(_)开头。
- 标识符的其他部分可以用字母、下划线或数字(0~9)组成。
- 标识符只有前32个字符有效。
- 标识符不能使用C语言的关键字。
关键字
关键字是由C语言规定的具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C语言的关键字可以分为以下3类。
类型说明符:用于定义、说明变量、函数或其他数据结构的类型。 语句定义符:用于表示一个语句的功能。如例1.3中用到的if else就是条件语句的语句定义符。 预处理命令字:用于表示一个预处理命令。如前面各例中用到的include。
变量与常数
计算机主要的功能就是强大的运算能力,基本过程就是将从外界得到的数据输入计算机,并通过程序来进行运算,最后输出所要的结果。当程序运行时,外界的数据进入计算机后要有个栖身之处,这时系统会分配一个内存空间给这份数据。在程序代码中,我们所定义的变量(Variable)与常数(Constant)扮演的就是这样的角色。
变量与常数主要用来存储程序中的数据,以便程序进行各种运算。无论是变量还是常数,必须事先声明一个对应的数据类型(data type),并在内存中保留一块区域供其使用。两者之间最大的差别在于变量的值是可以改变的,而常数的值是固定不变的。
我们可以把计算机的主存储器(内存)想象成一个豪华旅馆、外部数据当成来住房的旅客,旅馆的房间有不同的等级,就像属于不同的数据类型,最贵的等级价格自然高,不过房间也较大,就像有些数据类型所占内存空间的字节数较多。
定义变量就像向C系统要房间,这个房间的房号就是内存中的地址,房间的等级就是数据的类型,当然这个房间的客人是可以变动的。而常数就像是被长期租用的房间,不可以再变更住客,除非这个程序运行结束。
认识变量
变量是程序设计语言中不可或缺的部分,代表可变更数据的内存空间。变量声明的作用在于告知计算机所声明的变量需要多少内存空间。C语言属于一种强类型(strongly typed)语言,当声明变量时,必须以数据类型作为声明变量的依据,同时要设好变量的名称。 基本上,变量具备4个形成要素
- 名称:变量在程序中的名字,必须符合C语言中标识符的命名规则及可读性。
- 值:程序中变量所赋予的值。
- 引用位置:变量在内存中存储的位置。
- 属性:变量在程序中的数据类型,如整数、浮点数或字符。
变量命名原则
在C语言的程序代码中所看到的代号,通常不是标识符(IDentifier)就是关键字(Keyword)。在真实世界中,每个人、事及物都有一个名称,程序设计也不例外,标识符包括变量、常数、函数、结构、联合、枚举等代号(由英文大小写字母、数字或下划线组合而成),例如helloworld范例中的no、printf、system都属于标识符。至于关键字,就是具有语法功能的保留字,所有程序员自行定义的标识符都不能与关键字相同,在ANSI C中共定义了32个关键字。
基本上,变量名称都是由程序设计者自行定义的,为了考虑程序的可读性,大家最好以符合变量赋予的功能与意义来给变量命名,例如总和取名为“sum”、薪资取名为“salary”等,程序规模越大越重要。 变量属于标识符的一种,必须遵守以下基本规则:
- 变量名称开头可以是英文字母或下划线,但不可以是数字,名称中间也不可以有空白。
- 变量名称中间可以有下划线,例如int_age,但是不可以使用-、*、$、@、…等符号。
- 变量名称长度不可超过127个字符,另外根据ANSI C标准(C99标准),只有前面63个字符被视为变量的有效名称,后面的64个字符会被舍弃。
- 变量名称必须区分字母的大小写,例如Tom与TOM会视为两个不同的变量。
- 不可使用关键字(Keyword)或与内建函数名称相同的名字。
为了程序可读性,建议对于一般变量进行声明时以小写字母开头,例如name、address等,而常数最好以大写字母开头并配合“_”(下划线),如PI、MAX_SIZE。
至于函数名称,习惯以小写字母开头,如果由多个英文单词组成,那么其他英文单词的开头字母为大写,如copyWord、calSalary等。
变量的声明
由于变量的值可以改变,因此不同数据类型的变量所使用的内存空间大小以及可表示的数据范围有所不同。在程序设计语言中,有关变量存储地址的方法有两种
- 静态内存分配 静态内存分配法变量内存分配的过程是在程序编译时(ComPihng Time)进行的,如 C/C++、Pascal 语言等。在编译时确定变量的类型称为“静态检查”(static Checking), 变量的类型与名称在编译时确定
- 动态内存分配 变量内存分配的过程是在程序运行时(Running Time)进行的,如BASIC、Lisp 语言等。运行时才’确定变量的类型称为“动态检查”(Dynamic Checking), 变量的类型与名称可在运行时随时改变
由于C语言属于“静态内存分配”(Static Storage Allocation,或称为静态存储器分配)的程序设计语言,必须在编译时分配内存空间给变量,因此C语言的变量必须先声明再使用。正确的变量声明由数据类型加上变量名称与分号构成,语法如下:
数据类型 变量名称1, 变量名称2, …… , 变量名称n;
变量名称1=初始值1;
变量名称2=初始值2;
……
我们知道在C语言中共有整数(int)、浮点数(float)、双精度浮点数(double)以及字符(char)四种基本数据类型可用于变量声明 例如,声明整数类型的变量var1如下:
int var1;
var1=100;
以上这两行程序代码类似于我们到餐厅订位,先预定var1的位置(具有4个字节的整数空间),但是不确定这个地址上的数值是什么,只是先把它保留下来。如果变量设置初始值为100,就会将100放入这4个字节的整数空间。
在声明变量的同时可自行决定是否要赋予初值。如果尚未设置初值就直接输出变量的内容,通常会打印出无法预料的数字。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a;
int b=12;
float _c=117.12345;
printf("变量a=%d\n",a); /*打印出未初始化的a值*/
printf("变量b=%d\n",b); /*打印出已初始化的b值*/
printf("变量_c=%f\n",_c);/*打印出已初始化的_c值*/
system("pause");
return 0;
}
- 声明了3个变量,其中a变量并未设置初始值。
- 输出a时会在屏幕上发现a=0。若显示的不是0也很正常,因为系统并未清除原先地址上的内容或值,出现的是先前存放的数值。因此,建议在声明变量后最好能同时设置初始值。
以上示范是声明变量后再设置值,当然也可以在声明时同步设置初值,语法如下:
数据类型 变量名称1=初始值1;
数据类型 变量名称2=初始值2;
数据类型 变量名称3=初始值3;
…
例如,声明两个整数变量num1、num2,其中int为C语言中整数声明的关键字:
int num1=30;
int num2=77;
这时C语言会分别自动分配4个字节的内存空间给变量num1和num2,它们的存储值分别为30和77。当程序运行过程中需要存取这块内存时,就可以直接使用变量名称num1与num2进行存取
如果要一次声明多个相同数据类型的变量,可以使用“,”隔开变量名称。为了养成良好的编写程序习惯,变量声明部分最好放在程序代码的开头,也就是紧接在“{”符号后声明(如main函数或其他函数)。例如:
int a,b,c;
int total =5000; /* int为声明整数的关键字 */
float x,y,z;
int month, year=2003, day=10;
变量的作用域
变量除了有可变动的特性,在程序中不同的位置声明也会有不同的生命周期。我们知道语句(statement,或称为指令)是C语言最基本的执行单位,每一行语句都必须加上“;”作为结束。 在C程序中,可以使用“{}”将多个语句包围起来,形式如下:
{
程序语句;
程序语句;
程序语句;
}
以上程序代码以大括号“包围”的多行语句称为程序区块(statement block,或称为语句区块)。变量作用域(或称变量的有效范围)是根据变量所在的位置决定的,也就是用来判断在程序中有哪些程序区块中的语句(Statement)可以合法使用这个变量。在C语言中,变量的作用域通常可分为三个层次:全局变量(Global Variable)、局部变量(Local Variable)与区块变量(Block Variable)。
全局变量
全局变量是指在主函数main()外声明的变量,在整个程序中任何位置的语句都可以合法使用这种变量。简单来说,声明在程序区块与函数外,且在声明语句以下的所有函数和程序区块都可以使用全局变量。通常全局变量用来定义一些不会经常改变的数值,不过初学者不应该为了方便而将所有变量都设置为全局变量,否则将来会发生变量名称管理上的问题,全局变量的生命周期始于程序开始之时,终于程序运行结束之后。
float pi=3.14; /* pi是全局变量 */
int main()
{
…
…
}
局部变量
局部变量是指在函数内声明的变量,或者声明在参数行中的变量,作用域只在声明的函数区块中,其他函数不可以使用这种变量。局部变量的生命周期开始于函数被调用之后,终止于该函数运行完毕之时。
void circle()
{
float pi=3.14; /* pi是circle()函数中的局部变量 */
}
int main()
{
…
…
}
区块变量
区块变量是指在某个程序区块中声明的变量,也是局部变量的一种,不过作用域更小。在某些程序代码区块中声明的变量有效范围仅在此区块中,此程序区块以外的程序代码都不能使用这个变量。
{
/*在此区块中声明一个变量sum,有效范围仅在此“程序区块”内*/
int sum ;
...
}
在这个范例程序中,我们在不同的位置声明salary变量,这个变量的生命周期有不同的意义,尤其当区块变量与全局变量同名时,以区块变量优先,大家可以仔细观察与比较。不过全局变量与区块变量同名很容易引起混淆,影响程序的可读性,大家在编写程序时最好避免这种情况。
01 #include<stdio.h>
02 #include<stdlib.h>
03
04 int salary=17500;/* 声明salary为全局变量 */
05
06 int main()
07 {
08
09 printf("salary=%d\n",salary);
10 {
11 int salary=22000;/* 在此声明salary为区块变量 */
12 printf("salary=%d\n",salary);
13 }
14 printf("salary=%d\n",salary);
15
16 system("pause");
17 return 0;
18 }
- 第4行:声明salary为全局变量,在整个程序中任何位置的语句都可以合法使用该变量。
- 第9行:输出全局变量salary的值。
- 第11行:声明salary为区块变量。
- 第12行:输出区块变量salary的值。
- 第14行:因为离开了程序区块,所以又将输出全局变量salary的值。
常数
前面谈的变量可以在程序运行过程中改变其值,常数在程序运行时会固定不变。例如,10、-568、0、5000等是整数常数,3.1416、0.001、82.51等是浮点数常数。如果是字符常数,就必须以单引号“’‘”括住字符(如’a’‘c’);如果数据类型为字符串,就必须以双引号“”“”括住字符串,例如”程序设计”“Happy Birthday”等。
常数命名规则
常数在程序中的应用也和变量一样,可以用一个标识符来表示,唯一的不同之处在于这个标识符所代表的数据值在此程序运行时是绝对无法改变的。例如,一个计算圆面积的程序,其中的PI值就可以使用常数标识符来表示。
通常有两种定义方式,标识符的命名规则与变量相同,习惯上会以大写英文字母来定义名称。这样不但可以增加程序的可读性,而且对程序的调试与维护有帮助。
#define常数名称常数值
使用宏指令#define来声明。所谓宏(Macro),又称为“替换指令”,主要功能是以简单的名称取代某些特定常数、字符串或函数,善用宏可以节省不少程序开发的时间。由于#define为一种宏指令,并不是赋值语句,因此不用加上“=”与“;”。例如,定义常数的方式如下:
#define PI 3.14159
当使用#define定义常数时,程序会在编译前先调用宏处理程序(Macro Processor),用宏的内容来取代所定义的标识符,然后进行编译的操作。简单来说,就是将程序中所有PI出现的部分都替换成3.14159,这就是使用宏指令的特点。
下面的范例程序说明如何以#define形式声明常数。与一般的指令不同,无须声明标识符的数据类型和使用“=”赋值符号,通常是将其加在程序最前端的预处理指令区。
01 #include<stdio.h>
02 #include<stdlib.h>
03
04 #define PI 3.14159 /*声明PI为3.14159*/
05
06 int main()
07 {
08
09 float radius =5.0,Area; /*声明与设置圆半径 */
10
11 Area=radius*radius*PI; /* 计算圆面积 */
12
13 printf("圆的半径为=%f ,面积为=%f \n",radius,Area);
14
15 system("pause");
16 return 0;
17 }
- 第4行:使用#define声明PI为3.14159,声明后程序中所有出现PI的部分都代表常数值3.14159,指令结束时也不用加分号。
- 第11行:计算圆面积的公式。
const数据类型常数名称=常数值;
使用const保留修饰词来声明与设置常数标识符名称之后的数值,其实还是将所声明的变量进行限制,即在运行中都无法改变其数值。如果声明时并未设置初值,之后也就不能设置数值了。使用const保留字定义常数的方式如下:
const float PI=3.14159;
在下面的范例程序中,我们要特别说明,在使用#define来定义常数时,其生命周期一直到这个程序运行结束,或使用到取消定义(undefined)为止。而const所定义的常数还有其生命范围的问题,例如在main函数中声明了一个const类型的常数salary,但如果在函数程序区块中也声明了一个const类型的常数salary,就可以改变其值。请大家注意,如果第10行中把const int拿掉,只有salary=17500,即要修改由const声明后的变量值,那么在编译时就会出现报错的信息。
01 #include<stdio.h>
02 #include<stdlib.h>
03
04 int main()
05 {
06 const int salary=25000;/* 声明salary为常数 */
07
08 printf("salary=%d\n",salary);
09 {
10 const int salary=17500;/* 在此程序区块中声明salary为常数 */
11 printf("salary=%d\n",salary);
12 }
13
14 printf("salary=%d\n",salary);
15
16 system("pause");
17 return 0;
18 }
- 第6行:声明salary为常数。
- 第10行:在此程序区块中声明salary为常数。
- 第11、14行:这两行输出的salary值并不相同,一个为局部常数,一个为全局常数。
C语言的基本数据类型
C语言属于一种强类型语言,在声明变量时必须指定数据类型。C语言的基本数据类型有整数、浮点数和字符3种。数据类型在程序设计语言的定义中包含两个必备的层次,即规范性(specification)和实现性(implementation)。规范性包括数据属性,代表数值与该属性可能进行的各种运算。实现性包括数据的内存描述、数据类型的运算以及数据对象的存储器描述。
认识基本数据类型
对于程序设计语言来说,不有基本数据类型的集合,还允许程序员定义更具有可读性的派生数据类型。由于数据类型各不相同,在存储时所需要的容量也不一样,因此必须分配不同大小的内存空间存储。下面分别介绍C语言中的整数、浮点数、字符3种基本数据类型以及转义字符。
整数
C语言的整数(int)和数学上的意义相同,存储方式会保留4个字节(32位,即32比特)的空间,例如-1、-2、-100、0、1、2、1005等。在声明变量或常数数据类型时,可以同时设置初值,也可以不设置初值。在设置初值时,这个初值可以是十进制数、八进制数或十六进制数。
在C语言中,表示八进制数时必须在数值前加上数字0(例如073,也就是表示成十进制数的59)。在数值前加上“0x”或“0X”是C语言中十六进制数的表示法。例如,将no变量设置为整数80可以采用下列3种不同进制的方式表示:
int no=80; /* 十进制表示法 */
int no=0120; /* 八进制表示法 */
int no=0x50; /* 十六进制表示法 */
此外,C语言的整数类型还可按照short、long、signed和unsigned修饰词来进行不同程度的定义。一个好的程序员首先应该学习控制程序运行时所占有的内存容量,原则就是“当省则省”,例如有些变量的数据值很小,声明为int类型要花费4个字节,但是加上short修饰词就会缩小到2个字节,能够节省内存,不要小看节省的2个字节,对于一个大型程序而言,能够积少成多。
short int no=58;
long修饰词的作用正好相反,表示长整数。我们知道不同的数据类型所占内存空间的大小是不同的,往往也会因为计算机硬件与编译程序的位数不同而有所差异。在16位的系统下(如DOS、Turbo C),int的长度为2个字节,不过当一个整数声明为long int时,它的数据长度为4个字节,为之前的2倍。
如果读者所选的编译程序为32位(如Dev C++、Visual C++等),int数据类型会占用4个字节,而long int数据类型也是4个字节。简单来说,在目前的Dev C++系统下,声明int或long int所占据内存空间的大小是相同的。类型所占内存空间的字节数越大,代表可表示的数值范围越大。
在C语言中,我们可以使用sizeof()函数来显示各种数据类型声明后的数据长度,这个函数就放在stdio.h头文件中。使用格式如下:
sizeof(标识符名称);
接下来介绍有符号整数(signed),就是有正负号之分的整数。在数据类型之前加上signed修饰词,该变量就可以存储具有正负符号的数据。如果省略signed修饰词,编译程序会将该变量视为有符号整数。这种修饰词看起来有些多余,在程序中的用途其实是为了增加可读性。声明整数类型变量的数值范围只能在-2147483648和2147483647之间,例如:
signed int no=58;
不过,如果在数据类型前加上另一种无符号整数(unsigned)修饰词,该变量只能存储正整数的数据(例如公司的员工人数,总不能是负的),那么它的数值范围中就能够表示更多的正整数。声明这种类型的unsigned int变量数据值,范围会变成在0到4294967295之间,例如:
unsigned int no=58;
此外,英文字母“U”“u”与“L”“l”可直接放在整数常数后标示其为无符号整数(unsigned)和长整数(long)数据类型,例如:
45U、45u /* 45为无符号整数 */
45L、45l /* 45为长整数 */
45UL、45UL /* 45为无符号长整数 */
我们知道整数的修饰词能够限制整数变量的数值范围,如果超过限定的范围就会“溢出”。下面的范例程序将分别设置两个无符号短整数变量s1、s2,请大家观察溢出后的输出结果。
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06
07 unsigned short int s1=-1;/* 超过无符号短整数的下限值 */
08 short int s2=32768; /* 超过短整数的上限值 */
09
10
11 printf("s1=%d\n",s1);
12 printf("s2=%d\n",s2);
13
14 system("pause");
15 return 0;
16 }
- 第7、8行:分别设置了s1与s2的值,并让s1超过无符号短整数的最小下限值,而让s2超过短整数的最大上限值。
- 第11、12行:输出数据时发现s1的值为65535、s2的值为-32768。事实上,必须将C语言的整数溢出处理看成是一种时钟般的循环概念:当比最小表示的值小1时,就会变为最大表示的值,如s1=65535;当比最大表示的值大1时,就会变为最小表示的值,如s2=-32768。
浮点数
浮点数(floating point)是带有小数点的数值,当程序中需要更精确的数值结果时,整数类型就不够用了,从数学的角度来看,浮点数就是实数(real number),例如1.99、387.211、0.5等。C语言的浮点数可以分为单精度浮点数(float)和双精度浮点数(double)两种类型,两者间的差别在于表示的数值范围大小不同
在C语言中浮点数默认的数据类型为double,因此在指定浮点常数值时,可以在数值后加上“f”或“F”将数值转换成float类型,这样只需要4个字节存储,可以节省内存空间。例如,3.14159F、7.8f、10000.213f。下面是将一般变量声明为浮点数类型的方法:
float 变量名称;
或
float 变量名称=初始值;
double 变量名称;
或
double 变量名称=初始值;
下面的范例程序用于展示C语言中单精度与双精度浮点数存储位数之间的差异,主要说明在程序中使用浮点数来运算会因为存储精度位数的差别带来的细微误差。
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06
07 float f1=123.4568357109375F;/* 声明单精度浮点数 */
08 float f2=21341372.1357912;/* 声明具有8个整数部分的单精度浮点数 */
09 double d1=123456789.123456789123;/* 声明双精度浮点数 */
10
11 printf("f1=%f\n",f1);
12 printf("f2=%f\n",f2);
13 printf("d1=%f\n",d1);
14
15 system("pause");
16 return 0;
17 }
- 第7~9行:声明了3个变量。其中,f1、f2分别声明为单精度浮点数,值设置为123.4568357109375F与21341372.1357912;d1声明为双精度浮点数,值设置为123456789.123456789123。
- 第11~13行:关于输出值的小数点部分,Dev C++都保留6位有效位数字。
此外,我们知道浮点数能以十进制或科学记数法的方式表示,以下示范是用这两种表示法来将浮点数变量num的初始值设置为7645.8:
double product=7645.8; /*十进制表示法,设置product的初始值为7645.8 */
double product=7.6458e3; /*科学记数表示法,设置product的初始值为7645.8*/
从数学的角度来看,任何浮点数都可以表示成科学记数法,例如:
M*10x
其中,M称为实数,代表此数字的有效数字,而X表示以10为基底的指数部分,称为指数。科学记数法的各个数字与符号间不可有间隔,其中的“e”也可写成大写“E”,其后所接的数字为10的次幂,因此7.6458e3所表示的浮点数为:
7.6458×103 = 7645.8
基本上,无论是float还是double,当以printf()函数输出时,所采取的输出格式化字符都是%f,这点和整数输出方式采用%d格式化字符类似。不过如果以科学记数方式输出,格式化字符就必须使用%e。
下面的范例程序用于示范浮点数的十进制和科学记数法之间的互换,只要我们在输出时以格式化字符%f或%e来显示,就可以达到互换的效果。
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06
07 float f1=0.654321;
08 float f2=5467.1234;
09
10 printf("f1=%f=%e\n",f1,f1); /* 分别以十进制数与科学记数方式输出 */
11 printf("f2=%f=%e\n",f2,f2); /* 分别以十进制数与科学记数方式输出 */
12
13 system("pause");
14 return 0;
15 }
- 第7、8行:声明并设置单精度浮点数f1与f2的值。
- 第10、11行:直接使用%e格式化字符输出其科学记数法的值。请注意第11行的输出结果,在第8行设置f2=5467.1234,但在输出时f2=5467.123535,产生变化的原因是存储精度的问题,输出时多出的位数保留为内存中的残留值。
字符类型
字符类型包含字母、数字、标点符号及控制符号等,在内存中是以整数数值的方式来存储的,每一个字符占用1个字节(8个二进制位)的数据长度,所以字符ASCII编码的数值范围在0~127之间。例如,字符“A”的数值为65、字符“0”的数值为48。
提示 ASCII(American Standard Code for Information Interchange)采用8个二进制位来表示不同的字符(8 bit或一个字节),即制定了计算机中的内码,不过最左边为校验位,实际上仅用到7个二进制位进行字符编码。也就是说,ASCII码最多只能表示27=128个不同的字符,可以表示大小英文字母、数字、符号及各种控制字符。
字符类型是以整数方式存储的,范围为-128~127,与整数一样也可以使用signed与unsigned修饰词。
当程序中要加入一个字符符号时,必须用单引号将这个字符括起来,也可以直接使用ASCII码(整数值)定义字符,例如:
char ch='A' /*声明ch为字符变量,并设置初始值为'A'*/
char ch=65; /*声明ch为字符变量,并设置初始值为65*/
当然,也可以使用“\x”开头的十六进制ASCII码或“\”开头的八进制ASCII码来表示字符,例如:
char my_char='\x41'; /* 十六进制ASCII码表示 A字符 */
char my_char=0x41; /* 十六进制数值表示 A字符 */
char my_char='\101'; /* 八进制ASCII码表示 A字符 */
char my_char=0101; /* 八进制数值表示 A字符 */
虽然字符的ASCII值为数值,但是数字字符和它相对应的ASCII码是不同的,如’5’字符的ASCII码是53。当然也可以让字符与一般的数值进行四则运算,只不过加上的是代表此字符的ASCII码的数值。例如:
printf("%d\n",100+'A');
printf("%d\n",100-'A');
由于字符’A’的ASCII码为65,因此上面运算后的输出结果为165与35。
printf()函数中有关字符的输出格式化字符有两种,使用%c可以输出字符,使用%d可以输出ASCII码的整数值。此外,字符也可以和整数进行运算,所得的结果是字符或整数。
下面的范例程序用于示范两种字符变量声明的方式,并分别进行加法与减法运算,最后以字符及ASCII码输出结果。
01 #include<stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06 /*声明字符变量*/
07 char char1='Y';/* 加上单引号 */
08 char char2=88;
09 /*输出字符和它的ASCII码*/
10
11 printf("字符char1= %c 的 ASCII码=%d\n",char1,char1);
12 char1=char1+32; /* 字符的运算功能 */
13 printf("字符char1= %c 的 ASCII码= %d\n",char1,char1);
14 /* 输出加法运算后的字符和ASCII码 */
15
16 printf("字符char2= %c 的 ASCII码=%d\n",char2,char2);
17 char2=char2-32; /* 字符的运算功能 */
18 printf("字符char2= %c 的 ASCII码= %d\n",char2,char2);
19 /* 输出减法运算后的字符和ASCII码 */
20
21 system("pause");
22 return 0;
23 }
- 第7、8行:声明两个字符变量char1、char2。
- 第12、17行:分别对字符变量char1与char2进行加法与减法运算。
- 第13、18行:分别输出运算的结果。
在本节有关字符的说明结束之前,我们还要学习字符串的概念。事实上,C语言中并没有字符串的基本数据类型。如果要在C程序中存储字符串,只能使用字符数组的方式来表示,因此字符串可看成是比基本数据类型更高一层的派生数据类型(Derived Data Types)。字符串的应用在C语言中相当广泛,在此我们先做个简单的介绍,后续会有专门的章节进行详细说明。
简单来说,’a’是一个字符,以单引号(‘)包括起来;”a”是一个字符串,用双引号(“)包括起来。两者的差别在于字符串的结束处会多安排1个字节的空间来存放’\0’字符(Null字符,ASCII码为0),在C语言中作为字符串结束时的符号。
在C语言中,字符串的声明方式有两种,都会使用到数组的方式:
方式1:char 字符串变量[字符串长度]="初始字符串";
方式2:char 字符串变量[字符串长度]={'字符1', '字符2', ...... ,'字符n', '\0'};
例如,声明字符串:
char str[]="STRING"; /* []内不用填上数字,系统会自动计算要预留多少数组空间给字符串STRING */
或
char str[7]={ 'S', 'T' , 'R', 'I', 'N', 'G', '\0'};/* 由于str字符串有7个字符,因此在[]内填入7*/
当使用printf()函数输出字符串时,必须使用格式化字符%s来输出字符串,例如:
char Str[]="World!";
printf("字符串 Str的内容: %s", Str); /* 显示 Str的内容 */
下面的范例程序主要用来说明字符与字符串的差别,其中声明了一个字符变量ch1与字符串变量ch2,两者都存储了小写字母a,最后分别输出两个变量的数据内容与所占的位数,读者可以比较两者的差异。
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06
07 char ch1='a';/* 声明ch1为字符变量 */
08 char ch2[]="a";/* 声明ch2为字符串变量 */
09
10 printf("ch1=%c 有%d 个字节\n",ch1,sizeof(ch1));
11 /* 输出ch1的值及所占的字节数 */
12 printf("ch2=%s 有%d 个字节\n",ch2,sizeof(ch2));
13 /* 输出ch2的值及所占的字节数 */
14
15 system("pause");
16 return 0;
17 }
- 第7~8行:分别声明字符变量ch1与字符串变量ch2,ch1以单引号括住字符,ch2以双引号括住字符串。
- 第10、12行:输出变量内的内容及所占的字节数,两者之间的差异是字符串多了一个空字符(\0)。
转义字符简介
“转义字符”(escape character)以“\”表示,功能是进行某些特殊的控制,格式是以反斜杠开头,表示反斜杠之后的字符将转义——改变了原来字符的意义而代表另一个新功能,所以也被称为转义序列(escape sequence)。之前的范例程序中所使用的’\n’就能将所输出的内容换行。
此外,也可以使用“\ooo”模式表示八进制的ASCII码,每个o表示一个八进制数字。“\xhh”模式表示十六进制的ASCII码,其中每个h表示一个十六进制数字。例如:
printf(''\110\145\154\154\157\n''); /* 输出Hello字符串 */
printf(''\x48\x65\x6c\x6c\x6f\n''); /* 输出Hello字符串 */
下面的范例程序展示了一个小技巧,就是将“"”(转义字符)的八进制ASCII码赋值给ch,再将ch所代表的双引号打印出来,最后在屏幕上显示带有双引号的”荣钦科技”字样,并且发出“嘟”声。
01 #include<stdio.h>
02 #include <stdlib.h>
03 Int main()
04 {
05 /*声明字符变量*/
06 char ch=042;/*双引号的八进制ASCII码*/
07 /*打印出字符和它的ASCII码*/
08 printf("打印出八进制042所代表的字符符号= %c\n",ch);
09 printf("双引号的应用->%c荣钦科技%c\n",ch,ch); /*双引号的应用*/
10 printf("%c",'\a');
11 system("pause");
12 return 0;
13 }
- 第6行:以八进制ASCII码声明一个字符变量。
- 第8行:打印出ch所代表的字符”。
- 第9行:双引号的应用,打印出了“荣钦科技”。
- 第10行:输出警告字符(\a),发出“嘟”声。
数据类型转换
在C语言的数据类型应用中,用不同数据类型的变量参与运算往往会造成数据类型间的不一致与冲突,如果不小心处理,就会造成许多边际效应问题,这时“数据类型强制转换”(Data Type Coercion)功能就派上用场了。数据类型强制转换功能在C语言中可以分为自动类型转换与强制类型转换两种。
自动类型转换
一般来说,在程序运行过程中,表达式中往往会使用不同类型的变量(如整数或浮点数),这时C编译程序会自动将变量存储的数据转换成相同的数据类型再进行运算。
系统遵循的类型转换原则是在表达式中选择类型数值范围大的数据作为转换的对象,例如整数类型会自动转成浮点数类型,字符类型会转成short类型的ASCII码。
char c1;
int no;
no=no+c1; /* c1会自动转为ASCII码 */
此外,如果赋值语句“=”两边的类型不同,就会一律转换成与左边变量相同的类型。当然在这种情况下,要注意运行结果可能会有所改变,例如将double类型赋值给short类型,可能会遗失小数点后的精度。数据类型的转换顺序如下:
Double > float > unsigned long > long > unsigned int > int
例如:
int i=3;
float f=5.2;
double d;
d=i+f;
当“=”运算符左右两边的数据类型不相同时,以“=”运算符左边的数据类型为主。以上述范例来说,赋值运算符左边的数据类型大于右边的,所以转换上不会有问题;相反,如果“=”运算符左边的数据类型小于右边的数据类型,就会发生部分数据被舍去的情况,例如将float类型赋值给int类型,可能会遗失小数点后的精度。另外,如果表达式使用到char数据类型,在计算表达式的值时,编译程序就会自动把char数据类型转换为int数据类型,不过并不会影响变量的数据类型和长度。
强制类型转换
除了由编译程序自行转换的自动类型转换外,C语言也允许用户强制转换数据类型。例如想让两个整数相除时,可以用强制类型转换暂时将整数类型转换成浮点数类型。
在表达式中强制转换数据类型的语法如下:
(强制转换类型名称) 表达式或变量;
例如以下程序片段:
int a,b,avg;
avg=(float)(a+b)/2;/* 将a+b的值转换为浮点数类型 */
double a=3.1416;
int b;
b=(int)a; /* b的值为3 */
请注意,包含转换类型名称的小括号绝对不可以省略,还有当浮点数转换为整数时不会四舍五入,而是直接舍弃小数部分。另外,在赋值运算符(=)左边的变量不能进行强制数据类型转换,例如:
(float)avg=(a+b)/2; /* 不合法的语句 */
在这个范例程序中,我们使用强制类型转换将浮点数转为整数,值得一提的是被转换的浮点数变量部分并不会受到任何影响。
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main()
05 {
06
07 int no1,no2; /* 声明整数变量 no1,no2 */
08 float f1=456.78,f2=888.333; /* 声明浮点数变量 f1,f2*/
09
10 no1=(int)f1; /* 整数强制类型转换 */
11 no2=(int)f2; /* 整数强制类型转换 */
12
13 printf("no1=%d no2=%d f1=%f f2=%f \n",no1,no2,f1,f2);
14
15 system("pause");
16 return 0;
17 }
- 第7、8行:声明整数与浮点数变量。
- 第10、11行:进行整数强制类型转换,注意这个包含类型名称的小括号绝对不能省略。
- 第13行:输出数据时发现no1与no2的值是f1与f2的整数值,而且f1与f2的值没有受到四舍五入的影响,因为直接舍去了小数值。