网资酷

用户名  找回密码
 立即注册
帖子
热搜: 活动 交友 discuz
查看: 58|回复: 0

C语言编程之旅--3基本数据类型

[复制链接]

1

主题

4

帖子

7

积分

新手上路

Rank: 1

积分
7
发表于 2023-1-23 01:35:57 | 显示全部楼层 |阅读模式
千里之提,溃于蚁穴;百尺之室,以突隙之烟焚。
本节目标

看完本节可以:

  • 掌握C语言基本数据类型的使用:整数和浮点数;
  • 掌握C语言标准输入的基本用法和标准输出的进阶用法;
  • 掌握C变量声明语句和赋值语句;
  • 理解代码编码风格;
本节主要是进一步完成『命令行贪吃蛇』选择页面到游戏页面的过渡,会在选择页面等待用户的选择。具体用户选择或者输入是什么不做判断,待后面章节进行完善。



源码解析

本节代码在名称为3.1的控制台程序工程中,源码在2.1工程的基础上继续完善游戏选项。



声明语句

在源码第33行处有如下形式的代码:
int select;这是声明语句基本结构。它的作用是告诉程序,需要声明一个变量select用于存储数据,int表明变量存储数据类型,也被称为变量类型。int是英文integer的缩写,表示整数的意思。因此,变量select可以存储0, 1, 2 ...这样的正整数,也可以存储-1, -2, -3 ...这样的负整数。
值得注意的是,生活中的整数是没有边界的,但程序中的变量存储数据是存在边界。就像用桶装水,不管桶还是小桶总会存在容量上限,这些将会在变量类型小节中进行介绍。
赋值语句

变量select表示的意思是它存储的值可以发生改变。若需要改变select的值,就需要像第34行处:
select = 1;这是赋值语句基本结构。它的作用是告诉程序,需要将select赋值为整数1。在这条语句执行后,select中存放的值为1。
需要知道的是,声明和赋值语句可以合并为一条,可以使得代码更简练:
int select = 1;基本输入

代码第36行调用了一个新函数:
getchar();当程序执行到此处时,会一直等待用户输入后才能继续执行。此处没有处理函数返回值,后面才会真正将其利用起来。
高级输出

代码第37行调用了标准输出函数:
printf("\n默认的选择是%d,指定游戏难度为简单!\n", select);当程序执行到此处时,屏幕中显示为「默认的选择是1,指定游戏难度为简单!」。前面讲过,字符串中转义字符\n会让光标换行,而%d被替换为1是因为select存储的值为1。此处的%d被称为printf函数的格式控制符。
当程序在解析字符串时,遇到%d的地方就会从后面参数列表中读取一个变量存储的值并替换%d的位置。
需要注意格式控制符需要与变量一一对应,可以试着多声明两个变量:
int v1 = 5;
int v2 = 9;
printf("v1=%d, v2=%d\n", v1, v2);当程序执行完会输出「v1=5, v2=9」。字符串中有两个格式控制符%d,第一个对应v1,而第二个对应v2。除了位置和数量有匹配关系,变量类型与格式控制符也需要匹配,比如此处变量类型为int,匹配的格式控制符%d。当出现类型不匹配时,屏幕会出现异常值。更多变量类型和格式控制符可以参考补充表格。
扩展说明

若没有计算机组成相关的预备知识,这一部分会比较困难,若实在看不懂别着急跳过,可以暂时留一个印象。毕竟C语言的作者就是用它来操作硬件的,这也是这门语言最大的强势点。
变量类型

最基本类型只有char和int,而short、long、long long都是修饰int类型的长度的,一般修饰符可以省略就产生非常多的变量类型。程序所有数据都是存储在内存中的。而内存就像一个一个大小一致的房间,每个房间可以存放或读取1字节的数据,都有独立的编号。



补充说明:1字节等于8比特,比特是硬件电路的知识。1比特可以存储0或1两种状态,8比特就可以存储2^8=256种状态。对应的二进制表示0000 0000 ~ 1111 1111,十六进制表示00~FF。
因为1字节可以存放的数据大小有限0~255,当需要存放更大的数据就很麻烦。就像单个房间只能放一张床,将多个房间拼在一起做一个套三,就可以放下三张床。同理,int就表示这是一个套四的房子,可以存储4字节的数据,那范围扩展到了[-2,147,483,648 ~ 2,147,483,647]。
因为直接使用房间编号很麻烦,因此就用套房的方式重新包装。因此变量名其实本质就是代表一块4字节的内存,对变量的赋值即对内存的赋值。



char就表示套一的房子,可以存储1字节的数据,范围为[-128 ~ 127]。为了更高效的利用内存,就产生了修饰int整数的扩展变量类型。short表示套二的房子,可以存储2字节的数据。long可以存储4字节,long long是别墅级的,可以存储8字节。其中int可能会因平台的不同而改变,就像房产开发商一般,标准不一样能存储的数据大小会变化。
简单探测各类型数据占用字节数,可以使用内置函数sizeof获得,它返回的数是long long型需要使用%lld与它匹配:
printf("char占用字节数:%lld\n", sizeof(char));
printf("int占用字节数:%lld\n", sizeof(int));
printf("long long int占用字节数:%lld\n", sizeof(long long int));

/*
执行结果:
char占用字节数:1
int占用字节数:4
long long int占用字节数:8
*/字符类型

char类型的变量在C语言还有一个作用是可以存储单个字符,比如字符A。字符编码比较通用的为「ASCII码」,它使用整数来表示字符,比如字符A对应的ASCII码为65。字符输出通过使用%c来完成:
char v1 = 'A';
char v2 = 65;
printf("字符赋值v1为:%c\n", v1);
printf("字符赋值v2为:%c\n", v2);

/*
执行结果:
字符赋值v1为:A
字符赋值v2为:A
*/细心的读者会发现ASCII码只有英文字母,那中文怎么表达式的呢?其实中文字符是通过其他编码来实现的,比如常见的UTF-8、GB2812、GB28181等,整个编码标准非常复杂,这里暂时不详细讨论。
符号修饰

基础变量类型可以指定符号修饰unsigned和signed,前者修饰的类型就是无符号类型,后者为有符号类型。若没有显示指定的变量类型都是signed,因此int与signed int都是等价的。
与整数扩展不同的是,符号修饰并不能改变变量存储数据的占用空间,而是改变取值范围。比如:char类型变量取值范围为-128~127,而unsigned char类型变量取值范围为0~255。
unsigned char和signed char两种类型的变量,在0~127范围内的数用二进制表示都是一致的。比如:127都对应二进制0111 111。而二进制1111 1111对应的无符号类型变量值为255,有符号类型值为-1。可以通过简单的测试观察到两种符号修饰的不同:
char v1 = -1;
unsigned char v2 = -1;
printf("两者赋值为-1后\n");
printf("有符号char值为:%d\n", v1);
printf("无符号char值为:%u\n", v2);
v1 = 255;
v2 = 255;
printf("两者赋值为255后\n");
printf("有符号char值为:%d\n", v1);
printf("无符号char值为:%u\n", v2);

/*
执行结果:
两者赋值为-1后
有符号char值为:-1
无符号char值为:255
两者赋值为255后
有符号char值为:-1
无符号char值为:255
*/值得注意的是,赋值语句右侧值(也被称为右值)-1和255在程序中都是以二进制表示的。第一次赋值-1后,能看到无符号char对应变量值为255。因此,当变量赋值超过边界时,就会发生溢出的情况。第二次赋值255后,能看到有符号char对应变量值为-1,也发生溢出的情况。
非正常溢出情况需要在实际编程中避免,它会给程序逻辑带来致命的影响。因此,在声明变量前需要根据变量取值范围来选用合适的变量类型。对初学者存储整数,int的范围基本够用,一般不用特别考虑。
补充说明:硬件电路存储数据本身不区分数据符号,而要表示整数的负数部分就需要新的方式来表达。而二进制补码的引入就可以表达有符号型的整数,其中最高位为符号位,正数不变,负数为其正数的补码。比如:5的8位二进制表示为0000 0101,其补码为1111 1011,即所有为取反再加1,这就是-5的二进制表示。可能有人会问「为什么要用补码,直接正数最高位置1表示负数不行吗?」可以但比较麻烦。在实现整数减法时,就是将减数取补码与被减数相加即为结果。而减法又可以看做正数与负数相加,因此使用补码正好满足这些特性。
编码风格

C语言对代码格式要求比较宽松,可以将语句分散到多行中。比如下列语句:
int
     select2
= 9;
  select2    =
5;声明语句分散在1~3行,赋值语句分散在4~5行,分隔符空格的使用比较随意。虽然这样写编译一切都正常,但阅读起来非常困难,很不利于代码的交流。因此,为保持代码清晰的结构,编码风格需要保持一致。
语义明确的语句尽量写在一行中,并且不同逻辑代码段之间推荐使用空行分割,这样的代码更易阅读。比如:3.1工程源码第24和31行的空行,就很容易找到「打印游戏选项」代码段,不用理解26~30行代码也清楚代码逻辑。当然,这个示例比较简单,当有复杂逻辑时这种风格将会有非常重要的作用。
补充表格

基础类型表

表格中signed均被省略,short int均简写为short。
类型存储大小值范围
char1 字节-128 到 127 或 0 到 255
unsigned char1 字节0 到 255
int2 或 4 字节-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647
unsigned int2 或 4 字节0 到 65,535 或 0 到 4,294,967,295
short2 字节-32,768 到 32,767
unsigned short2 字节0 到 65,535
long4 字节-2,147,483,648 到 2,147,483,647
unsigned long4 字节0 到 4,294,967,295
long long8 字节-(2^63) 到 (2^63)-1
unsigned long long8 字节0 到 18,446,744,073,709,551,615
printf格式控制符表

格式控制符说明
%c输出一个单一的字符
%hd、%d、%ld、%lld以十进制、有符号的形式输出 short、int、long 、long long类型的整数
%hu、%u、%lu、%llu以十进制、无符号的形式输出 short、int、long 、long long类型的整数
%ho、%o、%lo、%llo以八进制、不带前缀、无符号的形式输出 short、int、long、long long 类型的整数
%#ho、%#o、%#lo、%#llo以八进制、带前缀、无符号的形式输出 short、int、long 、long long类型的整数
%hx、%x、%lx 、%llx、%hX、%X、%lX、%llX以十六进制、不带前缀、无符号的形式输出 short、int、long 、long long类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。
%#hx、%#x、%#lx 、%#llx、%#hX、%#X、%#lX、%#llX以十六进制、带前缀、无符号的形式输出 short、int、long 、long long类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。
%f、%lf以十进制的形式输出 float、double 类型的小数
%e、%le %E、%lE以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。
%g、%lg %G、%lG以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。
%s输出一个字符串
关于本系列





本系列的相关文章
幺零幺零:C语言编程之旅--0前言
最后,希望大家能喜欢这系列,若喜欢也请不要吝惜点赞和收藏o( ̄▽ ̄)d,我们回见。
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|网资酷

GMT+8, 2025-3-15 14:32 , Processed in 0.090482 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表