写本文,只是方便个人复习!!!

写博客本就很麻烦,如果你是大神,那就不用看了,这是针对小白的。如果你是杠精,那就只能屏蔽了。我写这个只是方便个人的基础上方便更多的人,你白嫖,你还鸡蛋里挑骨头?觉得不合适可以自行书写!!!

C语言教程Day01——数据类型

本教程参考B站王道训练营C语言教程,共计10天,内容有点多,但学编程还是建议多敲代码。学编程——每天坚持敲代码!很重要!


数据结构 + 算法 = 程序

数据 + 逻辑 = 程序


第一章 VS2017基本操作

VS2017安装教程:http://c.biancheng.net/view/456.html

使用VS2017编写C语言程序, 程序代码如下:

#include <stdio.h>
#include <stdlib.h>

int main() {
	int i = 10;
	printf("Hello World \n");
    system("pause");
	return 0;
}

1.1 创建项目(Project)

  • 在 VS 2017 下开发程序首先要创建项目,不同类型的程序对应不同类型的项目,初学者应该从控制台程序学起。
  • 打开 VS 2017,在菜单栏中依次选择 “文件 --> 新建 --> 项目”:

  • 或者直接按下 Ctrl+Shift+N 组合键,都会弹出下面的对话框:

  • 选择 “空项目”,填写好项目名称,选择好存储路径,同时对于初学者来说,可取消勾选 “为解决方案创建目录”,点击 “确定” 按钮即可。

注意:这里一定要选择 “空项目” 而不是 “Windows控制台应用程序”,因为后者会导致项目中自带有很多莫名其妙的文件,不利于初学者对项目的理解。另外,项目名称和存储路径中最好不要包含中文。

  • 点击 “确定” 按钮后,会直接进入项目可操作界面,我们将在这个界面完成所有的编程工作。

1.2 添加源文件

  • 在 “源文件” 处右击鼠标,在弹出菜单中选择 “添加 --> 新建项”

  • 或者直接按下 Ctrl + shift + A 组合键,都会弹出添加源文件的对话框,如下图所示:

  • 在此分类中,我们选择 “C++文件(.cpp)”,编写 C 语言程序时,注意源文件后缀名为 .c ,点击 “添加” 按钮,就添加上了一个新的源文件。

注意:C++ 是在 C 语言的基础上进行的扩展,所有在本质上,C++ 已经包含了 C 语言的所有内容,所以大部分 IDE 会默认创建后缀名为 .cpp的C++ 源文件。为了大家养成良好的规范,写 C 语言代码,就创建后缀名为 .c 的源文件。

1.3 编写代码并生成程序

  • 打开 Hello.c ,将本节开头的代码输入到该源文件中,如下图所示:

1.4 编译(Complie)

  • 在上方菜单栏中选择 “生成 --> 编译” ,就完成了 Hello.c 源文件的编译工作,如下图所示:

  • 或者直接按下 Ctrl + F7 组合键,也能够完成编译工作,这样更加便捷。如果代码没有任何错误,会在下方的 “输出窗口” 中看到编译成功的提示:

  • 编译完成后,打开项目目录下(本教程中是 F:\MC++\Work\CDemo\Debug)的 Debug 文件夹,会看到一个名为 Hello.obj 的文件,此文件就是经过编译产生的中间文件,这种中间文件的专业称呼是目标文件(Object File),在 VS 和 VC 下,目标文件的后缀都是 .obj

1.5 调试

  • 在VS2017界面的源程序中,添加 “断点”,鼠标点击行号左边灰色地带,再点击本地Windows调试器,如图:

  • 点击 “菜单栏” 的 “调试” ,选择 “窗口” 选择如图所示的三个选项:

  • 将调试界面固定成如下:

  • 逐步按键盘的 “F10” 进行调试,具体结果看界面。

1.6 如何调出行号

  • 选择菜单栏的 “工具” --> “选项” --> “文本编辑器” --> “C/C++” --> 打钩 “行号”。

1.7 链接(Link)

  • 在菜单栏中选择 “项目 --> 仅用于项目 --> 仅链接 CDemo” , 就完成了 Hello.obj 链接工作,如下图所示:

  • 如果代码没有错误,会在下方的 “输入窗口” 中看到链接成功的提示:

本项目中只有一个目标文件,链接的作用是将 Hello.obj 和系统组件(专业讲是静态链接库)结合起来,形成可执行文件。如果有多个目标文件,这些文件之间还要相互结合。

  • system(“pause”); 的作用就是让程序暂停一下。注意代码开头部分还添加了 #include <stdlib.h> 语句,否则 system(“pause”); 无效。

  • 编译错误:双击就可以定位到第几行。

  • 链接错误:看对应的函数符号,函数符号写错了。


第2章 数据类型、运算符与表达式

程序员编写程序就像裁缝做衣服,裁缝需要区分布料的类型,程序员需要区分数据的类型,裁缝需要各种工具对衣服进行加工,程序员需要用加减乘除等运算符对数据进行加工,从而得到自己想要的结果。

通过本章,你将掌握以下内容:

  • 数据类型有哪些
  • 常量与变量的差异
  • 整型,浮点型,字符型的原理及使用
  • Scanf的原理及使用
  • 运算符与表达式

2.1 数据类型

C语言的关键字,在今后的学习中我们将逐步学习这些关键字(不用去记!!!),这里只是列一下,让大家知道关键字有哪些,后面我们会逐个使用到,使用到时我们会详细讲解,这里列出避免大家后面命名变量名时,和我们关键字重名。下表只是列出:

2.2 常量

在程序运行过程中,其<mark>值不能被改变的量</mark>称为常量。
常量区分为不同的类型:

  • 整型:100,125,-100,365
  • 实型:3.14,0.125,-3.789
  • 字符型:‘a’,‘b’,‘2’
  • 字符串:“a”,“ab”,“lg15”
'' ————这种内部为空的,不是字符型!!!
"" ————这种哪怕内部为空,仍为字符串,它叫“空串”.

2.3 变量

变量代表内存中具有特定属性的一个存储单元,它用来存放数据,这就是变量的值,<mark>在程序运行期间,这些值在程序的执行过程中是可以改变的</mark>。
变量名实际上是一个以一个名字对应代表一个地址,在对程序编译连接时由编译系统给每一个变量名分配对应的内存地址。从变量中取值,实际上是通过变量名找到相应的内存地址,从该存储单元中读取数据。如下图:

变量命名的规定:C语言规定标识符只能由字母、数字和下划线三种字符组成,且第一个字符必须为字母或下划线

例如:
    strd,lout_2_3,BASDF,SU_li8		正确
    
    M.D.HH,145,3h8f,a>h			错误

注意:编译系统将大写字母和小写字母认为是两个不同的字符,要求对所有用到的变量作强制定义,也就是“先定义,后使用”,同时选择变量名和其它标识符时,应注意做到“见名知意”,即选有含意的英文单词(或其缩写)作标识符。注意变量名的命名不能与关键字同名!

2.4 整型数据

2.4.1 符号常量

  • #define指令可以把符号名定义为一个特定的字符串。

    #define 名字 替换文本
    
    eg:
        #define LOWERR 0
        #define UPPER 300
    
    符号常量通常用大写字母
    

在该定义之后,程序中出现的所有#define中定义的名字(既没有被引号引起来,也不是其他名字的一部分)都将用相应的替换文本替换。

先看一个例子:

#include <stdio.h>
#include <stdlib.h>

#define SUN 7 // SUN是常量
int main() {
	int i = SUN * 2;	
	printf("%d \n", SUN);
	printf("%d \n", i);
	system("pause");
}

这个很容易看出i的结果是7。那么,这个呢?

#include <stdio.h>
#include <stdlib.h>

#define SUN 4+3 // SUN是常量
int main() {
	int i = SUN * 2;	
	printf("%d \n", SUN);
	printf("%d \n", i);
	system("pause");
}

首先,SUN是符号常量,此值在主函数中不可修改,否则会出现:

这是为什么呢?先看这个 i 的结果是多少:

#include <stdio.h>
#include <stdlib.h>

#define SUN 4+3 // SUN是常量
int main() {
	int i = SUN * 2;	
	printf("%d \n", SUN);
	printf("%d \n", i);
	system("pause");
}

i最后结果是10。

上程序中整型变量i有自己的内存空间,所以可以存储整型常量4+3,也可以存储SUN * 2,也就是4 + 3 * 2,其实就是10,那通过define定义的Pl为什么是常量呢,接下来我们通过改变编译设置,来理解什么是预处理,理解了预处理,就明白为什么define的内容叫常量。右键点击项目,选择属性,设置预处理为“是”,如下图:

因为符号符号常量经预处理后,逐一被替换掉,所以不能放在等号左边,等号左边不是变量,即SUN=3语句被替换成4+3=3。成为常量,语句报错。所以,符号常量不可修改!!!

2.4.2 整型常量的不同进制表示

参考:http://c.biancheng.net/view/142.html

计算机中只能存储二进制,也就是0和1,对应的物理硬件上是高低电频。为了更方便观察内存中的二进制情况,除了正常我们使用的十进制外,还提供了十六进制,八进制,下面我们来看一下不同进制的对应关系,首先计算机中1个字节=8位,1位即二进制的1位,存储0或者1。

int型,大小为4个字节,即32位
    
二进制数 0100 1100 0011 0001 0101 0110 1111 1110 最低位是2的零次方,一直到最高位为230次方,最高位为符号位,具体到补码部分讲解。

八进制数 0114142533760开头标示,变化范围从0-7,对应2进制为每3位二进制变换为1位八进制,将上面的二进制每三位隔开,效果如下:
01 001 100 001 100 010 101 011 011 111 110,然后每三位对应0-7进行对应转换,就会得到八进制数 011414253376 ,因为实际编程时,识别八进制前面需要加0,所以需要在前面加了一个0。

十进制数 1278301950   直接赋值即可

十六进制 0x4C3156FE  以Ox开头标示,变为范围为0-9,A-F,A代表10,F代表15,对应2进制为每4位二进制转换为116进制。
1) r 进制转换成十进制
  • r 进制数 an an-1…a1 a0 对应的十进制数为:

  • an×rn + an-1×rn-1 + … + a1×rn-1 + a0×r0

举几个例子:

  • (1011011)2=1×26+0×25+1×24+1×23+0×22+1×21+1×20=64+0+16+8+0+2+1=91
  • (356)8=3×82+5×81+6×80=192+40+6=238
  • (2FB)16=2×162+15×161+11×160=512+240+11=763
2) 十进制转换成 r 进制
  • 方法:除 r 取余数,直至商为零,余数倒序排序
  • 举个例子:十进制 185 分别转换成二进制、八进制和十六进制。

  • 所以(185) 10=(10111001)2

  • 所以(185)10=(271)8

  • (185)10=(B9)16
3) 进制之间的转换
  • 上面讲了十进制和r进制之间的相互转换。可以说十进制是任意进制间相互转换的桥梁,任何进制都可以先转换成十进制,然后再转换成需要的进制。
  • 但二进制和八进制、二进制和十六进制之间的相互转换可以直接计算。二进制的运算首先要记住窍门:8421。 (1111)2=1×23+1×22+1×21+1×20=8+4+2+1,即二进制数 1111 从左到右每一位分别代表十进制的 8、4、2、1。
① 二进制转换为八进制

将二进制数从右到左,每三位组成一组,最左边不足三位的补零。然后对每组分别运用 8421 法则快速运算。如果二进制是 1 则保留,如果是 0 则舍去。比如:
(11112=8+4+2+1=1510102=8+0+2+0=1011002=8+4+0+0=1201012=0+4+0+1=5

所有的二进制转其他进制的运算都要记住这个法则。如果是二进制转十进制,且二进制数多于四位,那么其他位依次为 163264128……

只不过二进制转八进制时,因为是每三位为一组,所以就不存在第四位,这样 8 就都为 0 了,所以其实是 421 法则,但统一记为“8421”更顺口。

【练习】(110010112=(?)8

首先,从右到左分成三组,最左边不足三位的补零,即 011001011。然后对每组分别运用“8421”快速运算即 313。所以(110010112=3138。

② 二进制转换为十六进制

将二进制数从右到左,每四位组成一组,最左边不足四位的补零。然后对每组分别运用“8421”法则快速运算。

【练习】(10110010112=(?)16

首先,从右到左分成四组,最左边不足四位的补零,即 001011001011。然后对每组分别运用“8421”法则快速运算即 2 C B。所以(110010112=2CB)16。

③ 八进制转换为二进制

对于每一位八进制数,分别运用“8421”法则快速运算,逐位展开成三位二进制数,不足三位的补零,最后最左边的零可省略。

【练习】(37548=(?)238=0112,(78=1112,(58=1012,(48=1002,所以(37548=111111011002。

④ 十六进制转换为二进制

对于每一位十六进制数,分别运用“8421”法则快速运算,逐位展开成四位二进制数,不足四位的补零,最后最左边的零可省略。

【练习】(4B39F)16=(?)2416=01002,(B)16=10112,(316=00112,(916=10012,(F)16=11112,所以(4B39F)16=10010110011100111112

4) 不同进制的赋值
#include <stdio.h>
#include <stdlib.h>

#define SUN (4+3) // SUN是常量
int main() {
	int i = SUN * 2;
	i = 0x7b;	//赋值16进制
	printf("i=%d \n", i);	//十进制打印
	i = 0173;	//赋值8进制 
	printf("i=%d \n", i);	//十进制打印
	system("pause");
}
// 没人会闲的没事去赋值2进制!!!!

介绍一个小程序。这个程序的功能是将同一个十进制数以不同的进制显示出来。这个程序大家暂时还看不懂,没关系,等学到后面再来看这个程序就很简单了。

#include <stdio.h>
#include <stdlib.h>

int main() {
	int i = 221;
	printf("i = %d\n", i); //十进制输出
	printf("i = %o\n", i); //八进制输出
	printf("i = %x\n", i); //十六进制小写输出
	printf("i = %X\n", i); //十六进制大写输出
	system("pause");
	return 0;
}

其中:%d表示以十进制输出;%o表示以八进制输出,注意是字母 o 不是数字 0,而且一定是小写字母。这与前面讲的八进制数是数字 0 而不是字母 o 正好是相反的,千万不要弄混了。

%x%X表示以十六进制输出。那么它们有什么区别呢?

如果是 %x 那么字母就是以小写的形式输出,如果是 %X 那么字母就是以大写的形式输出。这也是八进制中只有 %o 没有 %O 的原因,因为八进制中根本没有字母,所以不需要区分大小写。

2.4.3 补码的作用

  • 计算机的CPU是无法做减法操作的,只能做加法,其实CPU中有一个逻辑单元叫加法器,计算机所做的减法,乘法,除法,都是由科学家将其变化为加法。
  • 那么减法是如何实现的呢?
  • 其实2-5,实际所使用的方法是2+(-5)进行的,而计算机只能存储0和1,我们编写程序如图2.4.3-1,来查看计算机如何存储-5,计算机是如何表示-5的呢,5的二进制为101,称为原码,计算机用补码表示-5,补码是对原码取反加1,也就是计算机表示-5是对5(101)的二进制进行取反加1,如图2.4.3-2,-5在内存中的存储是0xfffb,因为5取反得到的是0xfffa,然后加1就是Oxfffb,然后对其加2,最终得到的结果为Oxffffd,见图2.4.3-3,就是k的值,当最高位为1时,即代表负数,这个时候我们要得到其原码,才能知道0xfffffd的值,就是对其取反加1(当然你可以减一取反,效果是一样的),就得到3,所以其值为-3。

2.4.4 整型的变量

整型变量分为六种类型,具体对应不同类型变量可以表示的整型数范围如下表所示,如果超出数据范围就会发生溢出现象,导致计算出错。

  • 注意:括号表示其中的内容是可选的。
类型 类型说明符 长度 数的范围
基本型 int 4字节 -231~231-1
短整型 short 2字节 -215~215-1
长整型 long 4字节 -231~231-1
无符号整型 unsigned int 4字节 0~(232-1)
无符号短整型 unsigned short 2字节 0~(65535)
无符号长整型 unsigned long 4字节 0~(232-1)

来看一下溢出。

有符号短整型数可以表示的最大值为32767,当我们对其加1时,b的值会变为多少呢?

实际运行打印得到的是-32768,为什么会这样,因为32767对应的16进制为0×7ff,那么加1就变为0x8000,首位为1,就变为了一个负数,而我们对这个负数取其原码,就是其本身,值为32768,所以0x8000是最小的负数,即-32768,这就发生了溢出,因为我们对32767加1,希望得到的值是32768,结果得到的值为-32768,就会致计算结果错误,在使用整型时,一定要注意数值大小,不要超过对应整型数的表示范围,可能有的小伙伴会问,那我开发的系统,大于264-1怎么办,这个时候我们可以自行实现大整数加法,具体到后面数组会解决这个问题。

2.5 浮点型数据

2.5.1 浮点型常量

  • 浮点型常量的表示方法,有两种形式,如下表所示,e代表10的幂次,可正可负。
小数形式 0.123
指数形式 3e-3(为3*10-3,即0.003)
注意 字母e(或E)之前必须有数字,且e后面的指数必须为整数
正确示例 1e3、1.8e-3、-123e-6、-.1e-3
错误示例 e3、2.1e3.5、.e3、e

2.5.2 浮点型变量

我们通过float关键字或 double关键字进行浮点型变量定义,float类型占据4个字节大小的内存空间,double占据8个字节的空间,与整型数据的存储方式不同,浮点型数据是按照指数形式存储的。系统把一个浮点型数据分成小数部分和指数部分,分别存放。指数部分采用规范化的指数形式,指数也有符号位。

  • 数符占用1位,是0就代表正数,1就代表负数。

来看下浮点数的精度控制,浮点型变量分为单精度(float型)、双精度(double型)和长双精度型(long double)三类形式。如下表所示,因为浮点数使用的是指数表示法,所以我们不用担心数的范围,以及去看浮点数的内存(自己算起来麻烦),我们需要关注的是浮点数的精度问题,如图2.5.2-2,我们赋给a的值为1.23456789e10,加20后,应该得到的值为1.234567892e10,但是却是1.23456788e10,变的更小了,我们把这种现象称为精度丢失,原因就是float能够表示的有效数字为7位,最多只保证1.234567e10的正确性,如果要达到正确,我们需要把a和b均改为double类型。

类型 位数 数的范围 有效数字
float 32 10-37~1038 6~7位
double 64 10-307~10308 15~16位
long double 128 10-4931~104932 18~19位

今日作业