第五节:数据类型(二)

blaze兄,实在久等。现在恢复更新了,你也要恢复加油哦_

一、 C语言基本数据类型

1. int类型

C语言提供了许多不同的整数类型,以便程序员恰当地针对不同的情况使用不同的整数类型。例如,在已知变量取值范围处于一个较小的区间(如-32767~32767)时,使用short int(每个变量占2字节)相比使用int(占4字节)明显要更省空间。

我们已经在前面了解过怎么声明int变量并为它们赋值

int num;//声明一个int变量
num=1;//为这个变量赋值
int i=1;//声明变量的同时赋值,这个操作也被称作“初始化”
int num1,num2;//一次声明多个变量
int num3=3,num4;//编译器不会报错,但容易引起混淆

我们可以使用printf()函数来打印int变量。这里写一个有问题的函数以演示printf()的特性

//printf.c 演示printf()函数的性质
#include <stdio.h>
int main()
{
    int num1=1;
    int num2=2;
    
    printf("%d减去%d等于%d\n",num2,num1,num2-num1);
    printf("%d加上%d等于%d",num1,num2);//占位符个数与变量个数不匹配
    
    return 0;    
}

程序的运行结果如下:

2减去1等于1
1加上2等于0

程序的输出结果有错误。这是因为,在printf("%d加上%d等于%d",num1,num2)这个语句中,占位符个数与变量个数不匹配。这导致最后一个占位符找不到与之相匹配的变量,于是就会匹配内存中的任意值并输出(这里是0);如果占位符个数比变量个数少,则不会有报错(同时你会发现中间有数字没有打印出来)

八进制与十六进制

程序由0和1组成。因此,我们会希望计算机采用的进制也是2的整数次幂,于是,八进制和十六进制应运而生(为什么?)。使用这两种进制可以使二进制数的表达更为紧凑。节省空间。八进制每一位可以表示3个二进制位,十六进制每一位可以表示4个二进制位

C语言默认整数为十进制。但是,使用特定的前缀可以表示八进制和十六进制数。十六进制数的前缀是0x/0X。因此,"0x16"事实上表示了十六进制下的16,也即十进制下的22;八进制的前缀是0。例如:”012“事实上表示的是十进制下的10。

必须要清楚的一点是:无论整数写成什么样子,存储这个数的方式都相同。16,0x10和020本质上是同一个数字的不同表达。、

那么,如何显示八进制和十六进制数呢?

在C语言中,我们用”%d“表示十进制数字,用”%o“表示八进制数字,用”%x/%X“表示十六进制数字

如果要显示诸如”0“,”0x/0X“之类的前缀,需要把占位符改写成”%#o“,”%#x/%#X“的形态**(转换说明中只能用小写)**。

下面以打印十进制整数100为例:

//bases,c 以不同进制打印同一个数字
#include <stdio.h>
int main()
{
    int num=100;
    printf("%o等于%x等于%d\n",num,num,num);
    printf("%#o等于%#x等于%d\n",num,num,num);
    return 0;    
}

输出结果如下:

144等于64等于100
0144等于0x64等于100

我们发现:输出的结果取决于占位符的类型。占位符告诉电脑该用什么方式打印数据,不同的打印方式呈现出来的结果不同,但并不会影响到原变量。在之后,我们会进一步探讨这个问题。

不同整数类型的问题

有符号/无符号:在C程序中,我们通常使用unsigned来表示 “无符号” 类型。无符号类型的数据一定是非负值。它的意义在于:能够用同样的存储空间储存更大的正数。例如,同样要储存一个16二进制位的正整数,使用int类型只能取值在032767的数(-32768-1被占据),而unsigned int类型则能存储取值在0~65535的数。

我们使用**“%u”**来提示系统打印unsigned int型变量。

整数溢出:当我们为变量赋的值超过了其类型的存储空间时,就会发生溢出。printf()函数会打印出**“最大值后重新计数”**的数。例如:

//flow.c 演示十六位系统下的整数溢出
#include <stdio.h>
int main()
{
    int num=32767;
    unsigned int num2=65535;
    printf("num+1=%d, num2+1=%u",num+1,num2+1);   
    return 0;    
}

代码的输出结果如下:

num+1=-32768, num2+1=0

当我们为变量赋予的值超过了它本身的取值范围时,变量的值就会”从头计起“,num的值被重置为-32767,num2被重置为0。在被打印的数超出了变量本身能够表示的范围时,就会发生这种情况。

不同类型整数打印时的占位符表

整数类型占位符
unsigned int%u
short/short int%hd
long/long int%ld
long long%lld
printf()函数的更多特性

我们看这个程序:

//flow2.c 演示printf()函数的另一些特性
#include <stdio.h>
int main()
{
    short small=200;
    long big=65537;
    printf("small=%hd, =%d, =%ld\n",small,small);
    printf("big=%ld, ≠%hd\n",big,big);
    return 0;    
}

它的输出结果如下:

small=200, =200, =200

big=65537, ≠1

自动转换首先看第一行:计算机在处理范围在*(-32768到32767,十六位系统下/-2147483648到2147483647,三十二位系统下)*的整数时,会优先转换成int类型的值进行处理。当我们使用%ld占位符时,计算机同样会把它转换成int类型处理。所以第一行的输出是没有问题的。

在第二行中,我们使用了%ld和%hd类型。在使用%hd占位符时,由于short类型本身只占有2字节的空间,所以计算机只会读取后十六位。我们把65537写成二进制形式,是00000000000000010000000000000001(三十二位数形式),而计算机对此进行了截断,只取后十六位数,也就是1。

因此,在使用printf()函数时,一定要使占位符与变量类型相匹配

2. char类型

char类型用于存储字符。但是实际上,char也是一种整数类型。计算机使用数字编码来处理字符。在C语言中,这套编码通常是**ASCII编码**。例如,在ASCII编码中,65对应大写字母A。存储字母A,实际上存储的就是整数65。标准ASCII编码的范围是0~127。

C语言把1字节定义为char类型占用的位数,所以char类型的变量占用1字节。

我们可以像生明int变量一样声明char变量,如果需要向一个变量赋初始值,可以这么做:

char letter = 'A';
char letter = A ;//错误,此时A是一个未声明的变量
char letter = "A";//错误,此时A是一个字符串而非字符
char letter = 65 ;//不会报错,但不建议这么做(易使得代码晦涩难懂)

注意:所有字符都必须用单引号括起来,否则计算机无法确认它们是否为字符。用单引号括起来的字符被称为字符常量。编程器一发现'A',就会把它当成65来储存。

扩展:字符常量的数据类型

在C语言中,字符常量被以int类型存储,而非char型。例如,对于char letter = 'B’而言,B对应的整数66原本是存储在32位的存储单元中的*(int形式)*,但是现在却能存储在8位的存储单元中。所以我们可以定义像如下类型的字符常量:‘BIRD’。它是把四个独立的8位ASCII码存储在一个32位的单元里。当把它赋给某个char类型的变量时,计算机只会读取后面8位数字,所以变量的值会是D。

非打印字符与转义序列

单引号只适用于字符,数字和标点符号。但是ASCII表上还有一些非打印字符。这些字符代表了一些行为(例如,“\n”代表换行),C语言提供了3种方法来表示它们。

第一种是直接使用ASCII码。例如蜂鸣字符的ASCII码是7,那么char beep = 7就可以把为变量beep赋值。当打印beep时,你的计算机会发出一声蜂鸣音。(需要计算机的硬件支持,如果没有扬声器可不行)

第二种是使用转义序列。通过使用特殊的符号序列表示非打印字符。如果我们要把转义序列赋值给变量,就必须把它用单引号给括起来

下面列出了一些常见的转义序列:

转义序列含义
\a警报
\b退格
\n换行
\r回车
\\反斜杠
\’打印单引号
\"打印双引号

关于转义序列的更多内容参考这里

我们来详细分析一下转义序列。我们将\b, \n, \r这类的转义序列称为设备控制输出字符。它们会影响活跃位置。什么是活跃位置?就是指下一个字符应该出现的地方。也就是屏幕光标所在的地方。例如:“\n”的实际含义是:把屏幕光标移到下一行的开始处。\r则会把光标移到当前行的开始处。

\\, \', \"之类的转义序列是为了打印\ ' "这样的字符用的。这些字符本身是printf()函数的一部分,强行使用它们会造成混乱。

例如,如果我们想要打印这个句子:

He said : "Can you hear me? "

就应该这么写:

printf("He said : \"Can you hear me? \"");
printf("He said : "Can you hear me? "");//错误的写法,你可以注意到:未处在两个双引号中间的部分不会被识别为打印内容

在字符串中(被两个双引号括起来的部分),我们无需再用单引号将转义序列括起来。而且,由于中文引号与英文引号不同,我们无需担心此问题。

打印字符

我们来看这个程序:

//charcode.c 根据用户输入显示字符的编号
#include <stdio.h>
int main()
{    
    char ch;    
        
    printf("请输入一个字符:\n");    
    scanf("%c",&ch);
    printf("%c的ASCII编码是%d。",ch,ch);  
           
    return 0; 
}

运行结果如下:

请输入一个字符:

A

A的ASCII编码是65。

在运行这个程序时,输入字符后要按下Enter键。随后,scanf()函数会将用户输入的字符赋给变量ch。由于一个字符变量事实上被存储为一个八位的二进制整数,所以在打印时,第一次打印对应的字符A(对应占位符%c),第二次打印一个整数(对应%d,也是A的ASCII码)。这说明:printf()函数中的占位符是转换说明。它决定了数据的显示方式,但不能决定数据的存储方式。

3.bool_类型

bool_类型用来表示逻辑值(布尔值)。它实际上也是一种整数类型,不过它只存储两种值:值0表示false,值1表示true。我们将在后面详细讨论这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值