本文围绕C语言中可声明的常量数据类型及其可进行操作(如整型运算、字符串拼接等)展开介绍,并给出其声明代码和运算符速查表;考虑到篇幅有限,关于变量的可声明数据类型内容单独放到另一篇文章中讲解。本篇文章代码均已测试通过。
数据从总体来看可分为两类:常量和变量。常量和变量各自有可声明的数据类型,在本篇文章中,只讨论可声明的常量数据类型,变量数据类型请参考文章 【常量与变量】(一)C语言中可声明的变量数据类型。
C语言中的常量可分为:
整型常量科表示为十进制、二进制、八进制、十六进制的形式
整型常量 | 表示形式 | 示例 | 输出占位符 |
---|---|---|---|
十进制 | 以非0开始的数 | 220,-660 | %d |
二进制 | 以0B或0b开始的数 | 0b101, 0B100 | %b |
八进制 | 以o开始的数 | 06, 01002, 067 | %o |
十六进制 | 以0x或0X开始的数 | 0x10D, 0X4e, 0xFF | %x |
进制间的转换如下图所示:
代码实现:
// 其它进制数转换为十进制表示
#include
void convert(int x, int y)
{
if(x > 0)
{
convert(x/y, y);
if(y!=16)
printf("%d", x % y);
else
printf("%x", x % y); // 以十六进制输出
}
}
int main()
{
int x, y;//输入要转换的数值和转化进制数
printf("请输入要转换的十进制整数: ");
scanf("%d", &x);
printf("请输入要转换的进制: ");
scanf("%d", &y);
convert(x,y);
return 0;
}
也称实型常量,用十进制表示。一般地,它由整数部分、尾数部分和指数部分组成,对于绝对值小于浮点型常量,其小数点前面的零可以省略,如0.68可以写成.68。在编译环境中,默认的格式为浮点数时,最多可保留小数点后六位,不够的后面补0。科学计数时,字母E或e之前必须有整数数字。%6.2f
占位符表示整数部分右对齐输出6位数(不足的左边补0),小数部分输出2位数(不足的右边补0)。
#include
int main()
{
float a, b, c, d;
a = 1.3;
b = .23;
c = 1.5E-4;
d = 1.5E+4;
printf("a=%f, b=%f, c=%f, d=%f\n", a, b, c, d);
return 0;
}
/*
Output:
a=1.300000, b=0.230000, c=0.000150, d=15000.000000
*/
字符型常量通常用来表示单字符,用单引号 ''
括起来,若要表示 '
字符,则需加转义字符(反斜杠 \
)。在C语言中,字符是按其对应的ASCII码值来存储的,一个字符占一个字节,故可以用该字符的ASCII码值表示该字符,如十进制数65表示字符 A
(小写的a对应ASCII码值为97),十六进制数0x5d表示符号 ]
,八进制数0110表示 B
;另外,格式控制符是无法在程序中显式地表示,因此,这些格式控制符不能用其原符号表示,但可以用ASCII码值表示,如十进制数13表示回车符,八进制数033表示 esc
,十六进制0x0A表示换行符。以下为转义字符表
转义字符 | 含义 | ASCII码值(十进制) |
---|---|---|
\a | 响铃(BEL) | 007 |
\b | 退格(BS) | 008 |
\f | 换页(FF) | 012 |
\n | 换行(LF) | 010 |
\r | 回车(CR) | 013 |
\t | 水平制表(HT) | 009 |
\v | 垂直制表(VT) | 011 |
\ | 反斜杠 | 092 |
? | 问号字符 | 063 |
’ | 单引号字符 | 039 |
" | 双引号字符 | 034 |
\0 | 空字符(NULL) | 000 |
\ddd | 任意字符 | 三位八进制数 |
\xhh | 任意字符 | 二位十六进制 |
⚠️用单引号括起来的一个字符实际代表一个整数(对应于该字符在编译器采用的字符集中的序列值),用双引号括起来的一个字符串,代表的是一个指向无名数组起始字符的指针,该指针被双引号之间的字符以及一个额外的二进制值为零的字符 \0
初始化,如 printf("%s", "hello\n");
等价于 char hello[] = {'h', 'e', 'l', ' l', 'o', '\n', '\0'}; printf("%s", hello);
。
⚠️字符串数组的数组名就是字符串中的第一个元素的地址,可以通过引用其数组名来连续访问整个数组;而对于二维字符串数组来说,其数组名是第0行字符串的首地址(也即该行中第一个元素的地址),要连续访问该二维数组中所有行的元素,可通过字符串数组自增方式引用。注意:对字符串数组中的每个元素赋值时,需在字符串末尾添加结束标志 \0
。
关键字 const
声明该数据类型为常量,不可修改,声明语句如下:
const <类型说明符> <常量名> = <常量值;>
#include
const double PI=3.1415926;
int main()
{
int r;
double area, length;
r = 2;
area = r*r*PI;
length = 2*PI*r;
printf("半径为%d的圆的面积为%lf\n", r, area);
return 0;
}
用宏定义 #define <常量名> <常量值>
也可以实现同样效果,但const关键字定义的常量可以显式知晓其类型。(这里先留个问题给读者思考:赋值语句=
右边的常量值来自于计算机的哪里?左边的变量值又以什么形式存在于计算机的哪部分中?定义一个变量的计算机内部执行过程是怎样的?C源程序又是如何运行的?)
在学习语句时的第一条要义就是数据类型匹配,然而形如 9/4.0
这样的语句可通过编译而不会报错,这是因为编译器可以自动执行类型转换操作,而无需用户手动进行类型转换。在本节,我们可以了解到C语言自动进行类型转换的情况以及如何编写代码进行强制类型转换。
有如下情况时将进行自动类型转换:
⚠️此时存在潜在的数值转换问题:
注:鉴于使用printf()函数的结果显示方式会直接受到格式占位符的限制,因此改用C++中的 cout
输出结果,该函数被定义在头文件 ostream 类中。读者不必深究语法含义,只需根据定义的数据类型和实际输出的结果进行比对即可
#include
using namespace std;
int main()
{
cout.setf(ios_base::fixed, ios_base::floatfield); // 防止输出时将小数位的0省去
float height = 3; // int->float
float age1(23.44445384032); // double->float
int age2(23.44445384032); // double->int
short num = (int)4; // int->short
cout << "height = " << height << endl;
cout << "age1 = " << age1 << endl;
cout << "age2 = " << age2 << endl;
cout << "num = " << num << endl;
return 0;
}
/*
Output:
height = 3.000000
age1 = 23.444454
age2 = 23
num = 4
因为在计算机处理中,float和double的有效位数一致且整型数没有小数位,所以double->float和int->short两种情况下的打印结果与转换前无明显区别,但涉及取值范围的处理时两种情况会有很大的区别,已在另一篇文章中给出证明;而在double->int情况下,编译器会报出警告“将有隐式的从较高精度浮点数转换为整型数”,此时可以看到小数位被省去了。
*/
关于整型提升:除浮点型数以外,操作数在自动类型转换中均执行以下操作,小序号代表优先级高的:
①若无符号操作数级别比有符号操作数高(如unsigned long比int高),则将有符号操作数转换为无符号操作数所属的类型
②若有符号类型可表示无符号类型的所有可能取值(如int包含bool型所有取值),则将无符号操作数转换为有符号操作数所属的类型
③否则,将自身数据类型下的无符号类型向有符号类型转变(如unsigned short转变为short处理后,再转换为unsigned short输出)
关于整型和浮点型的不同取值范围请看文章 【常量与变量】(一)C语言中可声明的变量数据类型
请看下列示例代码:
#include
int main()
{
float height; // 浮点型数据,要转换成整型
(int) height = 1; // 去掉声明中的变量名和末尾分号,将要转换成的数据类型用括号封装
(int *) height = 1; // 转换成指向类型为整型数的指针类型
void (*mypFunc)(void); // 声明一个返回值为void、形参为void的函数指针 ,可以通过引用函数名访问该指针
return 0;
}
由此,我们可以得知,
去掉声明中的变量名和末尾的分号,再用括号将剩下的部分“封装”起来,例如,因为声明一个浮点型的函数指针: float (*h)()
,则 (float(*)())
表示“指向浮点类型的函数指针”的类型转换符。
再看例子, (*fp)()
是一个函数指针,调用时可直接通过其函数名调用,而 ANSIC标准允许程序员将 fp()
作为其简写形式,就好比 * (fp())
与ANSIC中的 *((*fp)())
一样。因此,要在计算启动时调用首地址位置为0的子例程——即数据类型为 (void(*)(void))
,含义是“返回值为void类型、参数为void类型的函数指针”,可以表示为 (*(void(*)(void))0)
,含义是“将常数0转化为指向void 类型的函数的指针”。
函数指针的另一种表示方法为 typedef void (*funcptr)()
。
详见文章:
【速查表】之C语言关键字、转义字符、运算符、占位符、数据类型占用空间等(持续更新中…)