【常量与变量】(二)C语言中可声明的常量数据类型

前言

本文围绕C语言中可声明的常量数据类型及其可进行操作(如整型运算、字符串拼接等)展开介绍,并给出其声明代码和运算符速查表;考虑到篇幅有限,关于变量的可声明数据类型内容单独放到另一篇文章中讲解。本篇文章代码均已测试通过。


引入

数据从总体来看可分为两类:常量和变量。常量和变量各自有可声明的数据类型,在本篇文章中,只讨论可声明的常量数据类型,变量数据类型请参考文章 【常量与变量】(一)C语言中可声明的变量数据类型

C语言中的常量可分为:

  • 整型常量
    • 十进制
    • 二进制
    • 八进制
    • 十六进制
  • 浮点型常量
  • 字符型常量

一、整型常量

整型常量科表示为十进制、二进制、八进制、十六进制的形式👇

整型常量表示形式示例输出占位符
十进制以非0开始的数220,-660%d
二进制以0B或0b开始的数0b101, 0B100%b
八进制以o开始的数06, 01002, 067%o
十六进制以0x或0X开始的数0x10D, 0X4e, 0xFF%x
表1 C语言进制表示占位符

👉进制间的转换如下图所示:

在这里插入图片描述

  • 数电-计算机中的数制处理、二进制数的算术运算、基本逻辑运算
  • 计算机组成原理-程序执行过程

👉代码实现:

// 其它进制数转换为十进制表示

#include<stdio.h>

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<stdio.h>

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任意字符二位十六进制
表2 C语言的转义字符

⚠️用单引号括起来的一个字符实际代表一个整数(对应于该字符在编译器采用的字符集中的序列值),用双引号括起来的一个字符串,代表的是一个指向无名数组起始字符的指针,该指针被双引号之间的字符以及一个额外的二进制值为零的字符 \0 初始化,如 printf("%s", "hello\n"); 等价于 char hello[] = {'h', 'e', 'l', ' l', 'o', '\n', '\0'}; printf("%s", hello);

⚠️字符串数组的数组名就是字符串中的第一个元素的地址,可以通过引用其数组名来连续访问整个数组;而对于二维字符串数组来说,其数组名是第0行字符串的首地址(也即该行中第一个元素的地址),要连续访问该二维数组中所有行的元素,可通过字符串数组自增方式引用。注意:对字符串数组中的每个元素赋值时,需在字符串末尾添加结束标志 \0


四、const限定符

关键字 const 声明该数据类型为常量,不可修改,声明语句如下:

const <类型说明符> <常量名> = <常量值;>

#include<stdio.h> 

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语言自动进行类型转换的情况以及如何编写代码进行强制类型转换。


1. 自动类型转换

🌰有如下情况时将进行自动类型转换:

  • 将一种算术类型的值赋给另一种算术类型的变量,如整型数除以浮点型数时
  • 表达式中包含不同类型。多用于初始化赋值时
  • 将参数传递给函数。默认通过位置传参时,实参类型被强制转换为对应位置的形参类型

⚠️此时存在潜在的数值转换问题:

  • 将较大的浮点型数转换为较小的浮点型数,精度(有效位数)降低,值可能超出目标类型的取值范围
  • 将浮点型数转换为整型数,小数部分丢失,原来的值可能超出目标类型的取值范围
  • 将较大的整型数转换为较小的整型数,原来的值可能超出目标类型的取值范围,通常只复制右边的字节

注:鉴于使用printf()函数的结果显示方式会直接受到格式占位符的限制,因此改用C++中的 cout 输出结果,该函数被定义在头文件 ostream 类中。读者不必深究语法含义,只需根据定义的数据类型和实际输出的结果进行比对即可

#include<iostream>

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语言中可声明的变量数据类型


2. 强制类型转换

👉请看下列示例代码:

#include<stdio.h>

int main()
{
	float height;	// 浮点型数据,要转换成整型
	(int) height = 1;	// 去掉声明中的变量名和末尾分号,将要转换成的数据类型用括号封装
	(int *) height = 1;	// 转换成指向类型为整型数的指针类型
	void (*mypFunc)(void);	// 声明一个返回值为void、形参为void的函数指针 ,可以通过引用函数名访问该指针
	
	return 0;
}

由此,我们可以得知,

cast(类型转换)

去掉声明中的变量名和末尾的分号,再用括号将剩下的部分“封装”起来,例如,因为声明一个浮点型的函数指针: float (*h)(),则 (float(*)()) 表示“指向浮点类型的函数指针”的类型转换符。

再看例子, (*fp)() 是一个函数指针,调用时可直接通过其函数名调用,而 ANSIC标准允许程序员将 fp() 作为其简写形式,就好比 * (fp()) 与ANSIC中的 *((*fp)()) 一样。因此,要在计算启动时调用首地址位置为0的子例程——即数据类型为 (void(*)(void)) ,含义是“返回值为void类型、参数为void类型的函数指针”,可以表示为 (*(void(*)(void))0) ,含义是“将常数0转化为指向void 类型的函数的指针”

函数指针的另一种表示方法为 typedef void (*funcptr)()


六、速查表

👉详见文章:

【速查表】之C语言关键字、转义字符、运算符、占位符、数据类型占用空间等(持续更新中…)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Larissa857

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值