C语言基础学习

                                    **

1.2 C语言程序设计入门三步骤

程序设计入门三步骤:
(1)安装软件并开发HelloWorld程序。
(2)掌握基本的输入输出方法。
(3)理解该语言中程序的基本结构。

1.2.1 安装软件并开发第一个HelloWorld程序

学习任何一门语言入门首要安装Dev-C++ 5.3.0.4开发软件,开发出简单的HelloWorld程序。

在这里插入图片描述对于初学者来说,现在不必理解上面的代码,只要利用相应的开发工具软件将该程序输入到计算机中并调试运行出来即可。
学习程序设计时最有效的方法不是对什么都刨根问底,把遇到的每一点都弄明白,而是应该先不求甚解,努力实践,把它做出来,然后琢磨为什么这么做。这样的迭代过程可能充满疑惑,甚至可以说是跌跌撞撞的,但这非常重要!正是在跌跌撞撞的过程中,你才能体会更深,发现更多疑问,激发你主动分析问题和解决问题的热情,从而能主动地自主学习,收获更多,更大。学习应该讲究水到渠成,而不要做崂山道士,费力不讨好,因为崂山道士式的学习会打击你学习的兴趣和积极性,导致你坚持不了多久,最终以失败收场。严格来说,程序设计并不完全是科学,它更应该是工程。工程最大的特点就是重要大量地实践。记住,程序设计“无他,惟手熟尔”!
万事开头难,初学者如何安装Dev-C++5.3.0.4版本和配置好相应的开发环境,是学习程序设计的首要问题,选择Dev-C++5.3.0.4作为开发环境。它对C99标准的支持较为全面,同时支持中英文界面的选择,支持图形化菜单方式的开发调试;另外,它还可以外挂各种工具程序,便于命令编译、链接和运行。
Dev-C++的安装、配置非常简单,具体步骤如下。
(1)首先在Dev-C++官网下载Dev-C++安装文件。Dev-C++非常短小精悍,只有大约10~50MB(不同版本)。
(2)直接双击Dev-C++安装文件,开始安装,然后逐步往下即可,直至安装完毕。
(3)将Dev-C++的安装目录下的bin目录加入到环境变量path中,这样在命令窗口的任何目录下都可以执行gcc编译链接命令。
在这里插入图片描述(4)配置简单的外挂程序。为了在后面的学习开发中便于使用命令行的编译、运行命令,此处在“工具”菜单中添加了一个名为“DOS窗口”的外挂工具选项。配置步骤如下:
1.启动Dev-C++,选择“工具” “配置工具”选项。
2.在弹出的“工具配置”对话框中单击“添加”按钮。
3.在标题:直接输入“DOS窗口”。
程序:单击右侧的”浏览“按钮,在弹出的对话框中选择C:\Windows\system32目录下的cmd.exe文件,单击”确定“按钮;也可以在文本框中直接输入C:\Windows\system32\cmd.exe。
在这里插入图片描述在这里插入图片描述工作路径:首先将光标定位在"工作路径”文本框中(如果有内容则先直接清除),然后在左下角的“可用的宏”列表框中选择选项,单击“插入宏”按钮即可;也可直接输入“"。
提示:工作路径配置为,可以保证DOS命令行窗口在启动时自行进入到源程序文件所在目录。
4.单击”确定“按钮,即可完成配置。
以后如果需要用到DOS命令行,直接在Dev-C++窗口中选择”工具“ ”DOS窗口“选项即可。
有了相应的开发环境后,就可以进入正式的程序开发阶段。一般来说,程序编写好后,需要执行以下几步才能得到输出结果。
(1)输入源程序,保存为.c的源程序文件。
(2)编译。
(3)链接。
提示:步骤(2)和(3)在集成开发环境下通常自动合成一步完成。
(4)运行程序。
具体操作步骤如下:
1.启动Dev-C++,选择”文件”“新建”“工程”选项。
在这里插入图片描述2.在弹出的“新工程”对话框中选中“C工程”单选项,工程类型选择为Console Application(控制台应用程序,即命令行字符界面程序),并输入工程名称firstp(工程名称一般为小写,可以自己命名,也可以为汉字),然后单击“确定”按钮。
3.弹出Create new project对话框,从中选择适当的保存位置(对于初学者,一般推荐保存在桌面上这样容易找),然后单击“保存”按钮。
4.此时在Dev-C++窗口中可以看到,系统自动生成了一个名为firstp的工程。单击工程名firstp前面的“+”图标,在展开的工程文件中双击main.c,即可在右边的代码窗口中输入程序源代码(Dev-C++自动帮助用户生成了程序源码框架,可以在此基础上改写代码,也可以将它们全部删除后再从零写起)。
5.输入完程序代码后,选择“运行” “编译”选项。
6.由于源程序文件main.c未保存,所以弹出“保存文件”对话框。在该对话框中将文件名改为HelloWorld.c,然后单击“保存”按钮。
7.编译成功后,单击“关闭”按钮返回,如果输入的代码有误,则会提示相应的出错信息。此时应该返回重新修改代码,然后再次编译,直到编译无误时为止。
8.选择“运行”“运行”选项。
9.此时开始运行程序,输出结果并暂停,等待看清结果后按任意键返回,至此,利用Dev-C++开发第一个C语言程序HelloWorld完成。
对于初学者来说,学习任何一门程序设计语言都必须首先掌握如何利用特定的开发环境(如,Dev-C++。通常,这样的开发环境可以有多个,初学者可以选择学习最简单、最容易入门的,等学到一定程度后再去掌握比较复杂、高级的开发环境和工具)来开发该语言的HelloWorld程序,这是学习任何程序设计语言的入门三步骤中的第一个步骤。
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

1.2.2 掌握基本的输入输出语法
程序就是对输入的数据进行处理,得到我们感兴趣的输出。如果没有输入、输出,这样的程序是没有任何意义的。学习任何程序设计语言入门的第二步骤,就是掌握在该语言中如何进行最基本的输入输出------如何输出一个整数?如何输出一个实数?如何输入、输出一个字符数据或字符串等......有了它们,就可以进行最基本的程序设计。例如输入一个整数,可以编如下程序。
(1)判断它是否为偶数。
(2)计算它的绝对值。
(3)判断它是否为一个质数。
(4)判断它有几位等。
这些程序设计任务有简单的,也有复杂的,但是都遵循输入、处理、输出三步骤。
在C语言中如何进行基本的输入输出呢?C语言本身并没有提供输入输出的语句,它是通过相应的库函数来实现输入输出的。最常用的输入库函数为scanf,输出库函数为printf。两个函数中的f都代表的是格式化(format),即进行格式化的输入和输出。在此初学者只需掌握它们最常用和最基本的用法即可,复杂的用法留待以后逐步深入学习。
1.输入库函数scanf
调用scanf函数的语法格式如下:
scanf("格式控制字符“,接收输入的地址列表);
接收输入的地址列表指定了接收输入的若干个变量的地址,即从键盘输入格式控制符指定的数据,送到地址列表指定的内存位置存储。
格式控制字符串中有两类字符:普通字符,在输入时必须输入对应的字符;格式控制字符,由”%“开头的若干个字符组成,用于指示输入数据的格式控制。常用的格式控制符有;%d: 十进制带符号整数 ; %lf双精度浮点数(注意:f前面是小写的L字母,不是数字1)。%c:单个字符。 %s:字符串。
初学者现在只需要了解即可,有关其具体用法将在后续的程序示例中逐步学习。
基本输入任务的解决步骤如下。
(1)定义一个特定类型的变量,用于存储输入的某种类型的数据。如何定义一个特定类型的变量?什么是变量?
(2)利用scanf库函数进行输入。如何输入?现在是宏观地讲解一下输入的步骤,学习程序设计最好的方式就是在实际的代码中学习,下面的代码进行了具体的演示。
在进入代码之前,先来粗略地了解一下必备的基本知识-如何定义一个变量?
变量定义的语法格式如下。
变量的类型    变量名;
变量的类型有整形int、双精度浮点型double、字符型char等。”变量名“由程序员自己定义。其相应的语法规则为:变量名必须是以字母或下划线”—“开头的,后面可是字母、数字、下划线。数字包含0-9;字母大小写均可,即‘A'~'Z'或’a'~'z'(一般推荐用小写);下划线也可以看成是一个字母。需要特别提醒的是,为了程序更易读,在给变量取名时最好见名知义。例如,商品价格取名为price,商品数量取名为num等。如果是整型简单变量,一般可命名为i、j、k、m、n等;如果是浮点型简单变量,则一般命名为x、y、z等;如果是字符型简单变量,则一般命名为ch等。
利用scanf输入的示例代码如下。
(1)输入一个整数。
	int n;						//第一步,定义一个整型变量n
	scanf("%d", &n);   //第二步,从键盘读入一个整数,送到变量n中
(2)输入一个浮点数。
double x;					//第一步,定义一个双精度浮点型变量x
scanf("%lf", &x)          //第二步,从键盘读入一个浮点数,送到变量x中
()输入一个字符。
char ch;				//第一步,定义一个字符型变量ch
scanf("%c", &ch);  //第二步,从键盘读入一个单独的字符,送到变量ch中
scanf库函数要求从键盘输入数据到特定的内存单元(变量就是内存单元的抽象)中,“&”为取变量的地址。如果现在还理解不了什么是地址,不用管它,可把该句代码理解为“你好,请把我买的家具送到xxx路yyy号楼的zzz房间,谢谢”。
2.输出库函数printf
调用printf函数的语法格式如下:
printf("格式控制字符串“,输出项列表);
”格式控制字符串“和scanf的格式控制字符串大同小异,”输出项列表“包含要输出的零个或多个表达式(注意:一个格式控制符对应一个输出表达式,故有多少个输出表达式就应该有多少个格式控制符)。
基本输出任务的解决:直接用printf库函数输出相应的表达式的值。
有关基本输入输出的用法,完整的示例如下(读代码、理解代码、写代码,这是学习程序设计的最基本步骤)。
例1-2 一个完整的输入输出示例。

在这里插入图片描述注意:在上面的代码中,以“//"开头的到本行结束的所有字符,称为单行注释。另外,C语言还支持以“/”开头、以“"结尾的多行注释。编译器在编译时会忽略所有注释。注释只是给人看的,可以帮助我们更容易地理解程序设计的思路,使程序更易读、更易于修改和维护。因此,初学者在初学编程时就应该养成良好的编程习惯,适当地加上一些注释。
初步理解了上面的程序后,接下来就可以照猫画虎,编写各种程序。例如,输入一个整数,然后输出其平方、立方等的简单程序。完全可以充分发挥想像力,借鉴上面的这个完整的输入、处理、输出程序 ,看看还可以设计出什么样的程序。
注意:程序设计的核心是设计,既然是设计,就有创造的成分,所以学习者应该让自己的思维海阔天空,但又立足于可利用刚才的代码,举一反三,这样才能获得最大程度的进步。
特别要提醒的是在学习程序设计时绝对不能只是”纸上谈兵“,而必须及早动手,上机实践。
上面的程序演示了输入一个整数,进行最简单的处理(如加1等)后输出。也许也有读者会想:既然能输入一个整数,那当然也能照葫芦画瓢,输入两个、三个甚至更多个整数,然后进行各式各样的处理后输出。
例1-3 计算输入的两个整数的和的程序。
在这里插入图片描述上述程序中介于”/"和“/"之间的多行字符,就是多行注释,程序编译时会将其自动忽略。现在已经能够编程完成任意两个整数的和、差、积、商的运算。但是会遇到新问题:键盘上只有加号”+“,减号”-“,没有乘号”x"和除号“,在C语言计算机程序设计中,用”*“号表示乘积,用”/"号表示除号。就可以实现两个或者多个整数的和、差、积、商运算了。
接下来让我们完成计算输入的两个浮点数的乘积。什么是浮点数?其实就是日常生活中的实数,只不过在计算机中存储时,采用了统一的国际标准IEEE754(国际电子与电气工程师协会第754号标准)来存储表示实数。它将实数分为:单精度浮点数(float型),用32位二进制表示;双精度浮点数(double型),用64位二进制表示;临时浮点数,用80位二进制表示,只不过临时浮点数用于计算机CPU内部计算,程序员编程一般用不上。当然,在计算机中为什么取名为浮点数而不叫实数,需要看《计算机组成原理》里面弄明白,现在只需要了解不用深究。
在这里插入图片描述编译、链接、运行程序后,结果如上图所示。
看看输出结果,是不是还有点不太满意?怎么后面那么多0啊?能不能省略掉或者只保留小数点后面2位?要完成这样的功能也很简单,只需要把输出的格式控制符由%f改为%.2f即可(其含义为小数点后只保留2位。注意,一定是英文的小圆点)。修改的程序如下:
在这里插入图片描述注意:一旦修改了源程序代码,哪怕只是一个符号,都必须重新编译一次,然后再运行。

1.2.3 理解C语言程序的基本结构

在初学任何程序设计语言时,一旦掌握了如何利用基本的开发环境开发出HelloWorld程序,以及如何利用该种语言提供的各种基本输入输出方法,即说明已经能编写各种小程序了。接下来就必须掌握和理解该种语言书写的程序的基本结构,理解其蕴涵的程序设计思想和理念。
计算机和程序的本质都是要模拟客观世界。客观世界是由众多的对象相互联系和相互作用而形成的一个复杂系统。由于人类认知能力的局限性,人们不可能用一个程序来模拟整个客观世界(那是人类的终极理想),而是根据需要模拟客观世界的某个局部和方面。根据认识层次,也可以把这个局部或方面认为是一个小的客观世界。
各种程序设计语言提供了众多的方法和机制来模拟客观世界的对象及其间的相互联系和作用。根据对这个世界的认识理念不同,程序设计语言主要分为两大类。
1.以C语言为代表的面向过程的程序设计语言:它们利用函数、过程或者子程序(对数据进行部分处理的代码模块)来模拟某个参与协作的客观世界的对象,利用函数、过程或者子程序之间的相互调用来模拟对象间的相互联系和相互作用,最后形成整个程序。这类语言书写的程序基本就是由一个或多个函数、过程或子程序构成。用此类程序设计语言开发程序,基本要点就是需要确定整个程序需要哪些函数、过程或子程序以及确定它们之间如何相互调用协作。简而言之,就是函数及函数之间的相互作用。
以Java、C#等为代表的面向对象的程序设计语言:它们利用对象(一种封装了数据和数据处理的代码模块)来模拟客观世界的对象,利用对象间的相互联系和相互作用用来模拟客观世界对象间的相互联系和作用。这类语言后面蕴涵的理念更贴近于现实世界,理解起来也更为自然。用此类程序设计语言开发程序,基本要点就是需要确定整个程序需要哪些对象以及确定它们之间如何相互联系和相互作用。简而言之,就是对象及对象间的相互作用。
上述两类语言之间并不是“井水不犯河水”,实际上,面向对象的程序设计语言恰恰是在面向过程的程序设计语言的基础上发展而来的,它体现了人类对这个客观世界更进一步的认识。它们的区别仅仅是认识和模拟客观世界的角度和层次不同而已。落实到具体的代码编写上,后者的对象中包含的数据和数据处理的模块本质上就是前者的函数、过程或子程序,只不过作了相应的封装和使用上的某些限制而已。
为什么讲这些?目的是让程序设计的初学者明白,C语言是学习程序设计非常重要的基础,现在所学的内容在以后学习Java或C#时都能用得上。初学者现在也只需要对上面的思想有所了解,不用深究。推荐在积累一定的程序设计经验后再深入领悟这些思想。
接下来,就来看看使用C语言书写的程序的基本结构。
C程序的基本结构如下。
(1)由一个或多个函数构成。
(2)这些函数分布在一个或多个文件中。
(3)每个文件称为一个可编译单元。
(4)每个C程序都有且仅有一个main函数。
(5)main函数是程序的入口,它直接或间接地调用其它函数来完成功能。
(6)函数的基本结构如下:
返回值类型				函数名(形式参数列表)
{
						数据定义;
						数据加工处理;
             return  返回值;
}
()C程序结构中的其它成份:注释、头文件、编译预处理等。
需要补充说明的是,组成C语言程序的若干个函数的代码在整个程序中的位置十分灵活,谁在前、谁在后均可以。C程序的基本结构。
main()函数  函数1、函数2、函数n
函数的分类:(1)库函数:由系统提供,经过精心编写和反复测试及使用,可靠而安全,推荐多使用。
								使用时必须包含所需的头文件。
(2)用户自定义函数:用户自己编写的函数。
(3)main函数:每个C程序都有且仅有一个main函数。该函数是程序的组织者,它直接或间接地调用其它函数来辅助完成整个程序的功能,其它函数一般不直接用main函数,它由操作系统自动调用。
在C99标准中,main函数只有两种规范的写法:
int main(void){....}
int main(int argc, char *argv[ ]){......}
其中,第一种写法main函数不带参数(参数为空,即void); 第二种写法main函数带有两个参数,第一个参数为命令行参数的个数,第二个参数为命令行参数对应的字符串指针数组,后面的章节将详细介绍命令行参数及其用法。无论哪种写法,main函数都有一个整型返回值,该值用于编写操作系统的shell脚本程序。各种编译器一般也支持main函数的如下写法,但不推荐C语言学习者这样做,在此列出,只是为了方便学习者在阅读一些遗留的老旧不规范的C代码时不至于茫然不知所措。
int main(){.......}				//虽然与标准不符但也还较为规范的main函数写法
void main(){.......}			//不推荐的main函数写法
main(){......}					//不推荐的main函数写法
注意:C语言严格区分大小写,所以Main函数并不等同于main函数。
	了解了C程序的基本结构,我们的学习方向和目标就非常明确了。C程序员主要做以下两件事:
	(1)写自己的函数。
	 (2)使用别人的函数,特别是库函数。
	 函数里有什么?有数据组织(涉及常量、变量、数据类型、数据结构,如数组、结构体、指针、文件等概念)和数据处理(涉及运算符、表达式、语句与流程控制、函数、算法、系统架构等概念),特别重要的是数据处理逻辑的封装、即算法。函数间如何相互作用,从而构成整个程序,这涉及程序或软件的系统架构。
	 前面讲解了C程序的基本组成结构,初学者要想真正掌握和理解它们,需要积累相应的实践经验。建议初学者在阅读大量的C程序代码后再来理解和领悟它们,学习需要温故而知新,但现在只需了解它们,有个初步印象即可。
	 【例1-6】两个函数构成的C程序示例。
	 前面的第一个C语言程序HelloWorld由一个函数(main函数)组成,在main函数中调用了库函数printf来输出“Hello,World!"这个向世界问好的字符串。下面改造该程序如下 :


            ![在这里插入图片描述](https://img-blog.csdnimg.cn/6b6bfeb296fd4b0bac388c273d69a3f6.png#pic_center)

在这里插入图片描述 改造后的程序由main函数和sayHello函数构成。main函数调用sayHello函数来完成问候的输出,而sayHello函数又调用printf库函数来完成真正的“Hello,World!"字符串的输出。为什么要这样分解?这正好体现了现实社会中的分工协作。前面讲过,程序的本质就是模拟客观世界,而客观世界中的人们总是相互分工协作的。在编写C程序的过程中,推荐大量使用C函数库中的函数来完成需要的功能,而不必从头做起,这样能大大提高开发效率,降低开发的时间和成本;同时,由于库函数大都由专业高手开发并经过反复的测试和大量的实践考验,可靠性和运行效率方面都非常有保障。
本例中,将HelloWord程序分解成了由两个函数构成,实现了某种程序的分工协作,但它们仍然在同一个文件中,在代码编程时还是非常不方便。试想每个函数由一个程序员来完成,他们独立写好后还得把相应的函数代码复制到一个文件中再编译运行,这是多么的不方便。
接下来再次改造该程序,将构成该程序的两个函数,即main函数和sayHello函数分别放到两个不同的文件中。文件名自定义,但最好见名知义。例如,把main函数的代码放到文件HelloWorld3.c中,而把sayHello函数的代码放到sayHello.c中。这时,这两个文件合起来才构成一个完整的C程序。这样,每个程序员可以单独完成自己的源程序文件。但现在另一个问题产生了;如何才能运行由这两个文件构成的程序呢?答案是分别编译,然后再链接。在诸如Dev-C++之类的提供了集成开发环境的工具中,只需创建一个项目,然后在该项目下新建两个.c源文件,输入代码,最后编译、运行该项目即可;也可以自己用命令行分别编译、链接,然后再运行该程序。用命令行分别编译、链接、然后再运行该程序的过程如下。
(1)编译HelloWorld.c文件,命令为gcc -c HelloWorld.c -o Helloworld.o
(2) 编译sayHello.c文件,命令为gcc HelloWorld.o sayHello.o -o HelloWorld.exe
(3)链接两个.o文件,命令为gcc HelloWorld.o sayHello.o -o HelloWorld.exe
(4)在命令行下输入HelloWorld,然后按Enter键即可运行。
在上述命令中,gcc是编译器,对应的可执行文件为gcc.exe(可以在Dev-C++的安装目录的bin目录下找到它); -c选项表示只编译而不链接;-o选项指定输出的文件名。
注意:如何获取一个DOS命令行窗口?前面已经在Dev-C++中配置好,只要选择”工具“”DOS窗口“选项即可。在打开的DOS命令行窗口中,在命令行提示符下输入上述的编译、链接和运行命令。
当程序由简单的HelloWorld程序演变到复杂的实际系统时,一个完整的程序可能由数十个甚至数百个源程序文件构成。另外,由于它们之间存在相互的某种调用或依赖关系,编译时,必须遵循一定的先后顺序,这显然会非常复杂且不方便。为了提高开发效率,现代的集成开发环境都为用户提供了对程序项目进行管理的工具,只需简单地单击几个按钮即可编译、运行整个复杂的项目,这大大提高了程序员开发复杂程序的能力。当然,在早期没有集成开发工具时,人们普通使用makefile文件及自己开发的make工具来管理和编译复杂的软件项目。这有一定的难度,不过目前仍有一些程序员使用这种命令行的开发方式。
在Dev-C++集成开发环境下开发多文件项目步骤如下。
(1)新建一个C工程(工程就是上面所说的项目,其英文名project。对这两个词本书不加区分),选择Console Application(控制台应用程序,即命令行字符界面程序),选中”C工程“单选按钮,命名为secondp,然后单击”确定“按钮,如图1-21所示。
(2)输入main函数的代码,如图1-22所示。
在这里插入图片描述
在这里插入图片描述
注意:在Dev-C++环境下,系统自动生成main函数的代码框架,并且自动加上#include<stdlib.h>和system(“PAUSE”);这两条语句。其中system(“PAUSE”);是调用在头文件stdlib.h中声明的系统库函数system。system函数用于执行一个DOS命令行的命令。pause是一个DOS命令,用于暂停屏幕,这样就可以看清运行结果,然后按任意键返回。如果没有这条语句,则程序执行后立刻返回,我们只是感觉屏幕闪了一下,根本看不清运行结果。当然,如果程序最后编译、链接成.exe的可执行文件后再在命令行下运行,就可以把这条语句删掉后重新编译、链接。它本身不是程序的一部分,只是在Dev-C++集成环境下直接运行所需要的辅助功能-暂停,让我们看清运行结果。有兴趣的读者可以在Dev-C++环境下将这两行删除,然后再编译、链接、运行、看看是什么效果。
(3)输入main函数的代码后,选择”文件“”保存“命令,弹出对话框,更改源文件文件名为HelloWorld3.c,然后单击”保存“按钮。

![在这里插入图片描述](https://img-blog.csdnimg.cn/3c222b53541e42438cc3bfe024f67733.png#pic_center)

在这里插入图片描述在这里插入图片描述
(4)选择”文件“”新建“”源代码“选项,在弹出的Confirm对话框中单击Yes按钮。

(5)输入sayHello函数的代码。
(6)选择”文件“”保存“命令,在弹出的对话框中将文件改名为sayHello,然后单击”保存“按钮。
如果工程中有多个源程序文件,则重复步骤(4)(5)(6)多次,即可输入各个 源程序文件的代码并将它们加入到工程中。
(7)单击工程名secondp,选中该工程,然后选择”运行“”编译运行“命令,即 可完成整个工程的编译运行。
(8)工程运行结果。

1.2.4 C语言程序的简单调试

	程序在计算机上编译运行时,可能会出现各种各样的问题。
	  (1)编译出错,不能被运行。
	  (2)虽然能够运行,但结果不正确。
	  (3)能够运行,结果也正确,但在某些特定的情况下会出现问题。
	  上述第一种错误称为语法错误,初学者常犯此类错误。一般编译都能检查出相应的语法错误并给出较为准确的错误定位和定性,所以修正此类错误较为简单。
	  第二种错误称为语义错误或逻辑错误,此时程序能够运行,但运行结果不是设计者希望达到的结果。要想找出此类错误比较困难,需要相应的程序调试方法和工具。
	  第三种错误称为运行时异常,它们并不是经常发生,而是在特定的情况下发生,例如,内存耗尽、缓冲区溢出、相应的数据文件不存在、网络连接断开等,所以很难捕获,从而导致程序蕴涵了隐蔽很深的错误,要想修复它们需要耗费更多的资源(如人、财、物、时间等)。
	  下面演示如何利用Dev-C++调试程序。所谓调试程序,就是让程序在受控条件下运行,在运行过程中可根据各种条件暂停程序的运行,然后查看程序中各种对象的即时值或状态,从而更快和更容易地定位错误和纠正错误的过程。在Dev-C++集成开发环境中可以设置断点,当程序运行到该处代码时就会暂停。此时可以查看程序中各种变量的值,然后选中某种方式(如单步运行、运行到光标处等)继续受控运行和观察程序中变量值的变化。

在这里插入图片描述

在这里插入图片描述

            ![在这里插入图片描述](https://img-blog.csdnimg.cn/8dd0c9dffb074050959a1819489c0155.png#pic_center)

在这里插入图片描述
在这里插入图片描述在这里插入图片描述(1)新建一个C工程,并输入上述的利用循环语句求1+2+3…+10的和的程序。
(2)选择“运行”“编译”选项,编译该程序。
(3)在i=1; 这一行左侧的黑色框处单击鼠标,设置断点,该行整体变成了深色显示。
(4)选择“调试”“调试”选项。
此时刚才设置的断点处变成深色显示(注意,此时该行代码并未被执行)。
(5)单击右下角的“添加查看”按钮,为调试添加要查看的变量,在弹出的“新变量”对话框中输入要查看的变量的名称(如此处想查看变量i的值,则输入"i"),然后单击OK按钮。
此时在Dev-C++左侧窗口中显示出i=2008544178字样(因为只定义了i这个变量,并未为它赋初始值,所以其初始值是随机的,和变量i代表的内存单元的当时的值有关。注意,深色显示的i=1; 这条赋值语句现在还并未执行)。
(6)单击“下一步”按钮,往下运行一条语句。此时可以看到深色光栅条已经往下移动,并且前面添加的想要查看的变量i的值已经变为1(因为已经执行了i=1; 这条赋值语句,所以已将1赋值给了变量i)。
(7)按照步骤(5)的方法再次添加一个欲查看的变量sum。同理,由于sum并未初始化,所以此时其值也是随机的。
(8)再次单击“下一步”按钮,注意到深色光栅条又再次下移一条语句,同时sum的值已经发生了变化(已经执行了sum=0; 这条赋值语句),重复步骤(8)多次,每一次重复都可以查看变量的值发生了什么样的变化。当多次单击“下一步”按钮,程序执行到printf输出语句时,循环已经执行完毕。此时的i变为了11,sum的值已经为1+2+3…+10的和55。再次单步执行,即单击“下一步”按钮,即可执行printf输出语句,得到屏幕上的输出。至此,就完成了简单的调试过程演示。
在学习程序执行设计时,及早地掌握简单的调试手段能够有效地帮助初学者理解程序中出现的各种概念和程序的执行逻辑。现在应该掌握这样的基本调试方法:设置断点、查看变量的值、单步执行等。建议初学者在后面的学习中,要经常利用该方法来帮助自己理解整个程序的执行过程,逐渐地培养、提高调试程序的能力,这是每一个从事软件开发的程序员必备的基本功。

1.3 案例分析

1.3.1 动画效果的HelloWorld程序

能不能让HelloWorld程序的输出具有像打字机一样的动画效果呢?初学者肯定会觉得非常困难,不知从何下手。但有一条原则建议大家从初学时就一定要牢记。作为中国人,我们最为熟悉的编程语言永远是汉语!
因此,对于任何一个编程任务,我们总是应该先用汉语编程,即把一个编程任务用汉语来分析设计,把它分解为一个个更小更容易实现的小任务,然后再用某种语言来实现每一个小任务。
要实现具有打字机动画效果的HelloWorld程序,用汉语来设计就非常简单;
输出字符H,延时一段时间;输出字符e, 延时一段时间;输出字符l,延时一段时间;.......;输出字符d,延时一段时间;输出字符!。
显然,输出某个字符的任务我们已经能完成,如何实现延迟一段时间的任务呢?
这个延迟任务,对于初学者来说显然是非常困难的,甚至可以说是不可能完成任务。作为程序员,那该怎么办呢?这就要用到C语言入门的三要素的第三要素:C程序总是由一个或多个函数构成。C程序员的基本任务就是:1,写自己的函数;2,使用别人的函数。好了,既然自己写不出来,那就想办法用别人写的函数吧。此时你可以有如下几种策略来查找别人是如何完成这个任务的:1.百度搜索; 2.请教高手;3.看看手头的书或代码库里有没有类似的示例代码。你可以用任何一种方法来完成这个任务。记住,这并不丢人。虽说“天下文章一大抄”并不好,但在软件开发领域,我们遵循的原则却是“不要重复造车轮”,并且一个重要的软件开发原则就是软件重用。能重用,就重用。重用能极大地提高开发效率。另外,初学者一定要牢记一点:一般来说,你在学习和软件开发中遇到的任何问题,通过百度等搜索引擎都能解决,因为世界上有无数的人已经遇到过类似的问题。
那就直接百度吧,搜索关键字:C语言 延时(注意中间有个空格)。就能轻而易举地得到答案:Sleep函数,语法格式为Sleep(延时的毫秒数)。要用这个函数,一定要包含相应的头文件:#include<windows.h>。下面就可以直接完成打字机效果的HelloWorld程序(代码看起来很长,但其实非常简单,难道不是吗?!)。

在这里插入图片描述
编译运行,欣赏一下我们开发的第一个动画程序吧。有没有很激动,其实编程真的不难,难的是编出好的程序。什么是好的程序?算法精良,架构合理,运行的时空效率高、可维护性可移植性好等,这些只是一方面,也不全对,其实真正的好程序是你在给定的资源限制(如时间、空间、金钱、人力等)条件下,能做出正确的抉择,能按时按要求完成需要功能的程序。
再次深入一点,能不能对上面的打字机动画效果改进一下。刚才的效果是从左到右一个字符一个字符地延时出现,当出现完全后,能不能再从右到左,一个字符一个字符地消失掉(即先消失!,再消失d,再消失l,…,最后第一个字母H也消失掉)?
嗯,这?让一个字符消失其实很简单,就是用一个空格替换掉它就好。关键是怎么才能在特定的位置输出空格符呢?如果你在前面的上机调试运行中稍微细心点就会发现,一旦程序输出某个字符串,光标就会自动在最后一个字符的后面闪烁,如果再输出另外一个字符串,它就必然从刚才闪烁的位置开始输出。那如何让光标回到前面的某个位置呢?这是问题的关键。显然自己是不会的,那就赶紧去百度吧,但我估计即使是百度,你可能也会感觉比较头疼,百度结果一般都是什么控制台光标定位等一大堆对于你现在来说很头疼的问题(这个控制台光标控制,后面会大量用到,现在不用管这个东西)。
其实很简单,有一个字符------‘\b’,叫作退格键(有的读者肯定会嘀咕,明明是\和b两个字符,怎么是一个字符呢?老师是不是书中写错了?其实没有错,键盘上有这个字符对应键,叫作Backspace,但写在代码中怎么写呢,总不能写成字符b吧,所以就在前面加了个斜杠,告诉编译程序,我这个\b可是一个特殊的字符,而不是斜杠本身或字符b本身,这个概念叫作转义字符,后续章节会详细讲解到,咱们在这儿先用。其实前面已经接触到两种转义字符:\n换行符和\t制表符)。输出这个字符,会让光标回到前一个字符位置,输出两个这种字符,就会让光标回到本行当前位置的前两个字符位置处,如果此时用printf函数输出一个字符串,那么新的字符串的起始输出位置就是刚才重新定位光标的位置。OK了,赶紧写出程序吧。

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

1.3.2 带声音的HelloWorld程序

一看本节标题,大家立马就会想到,赶紧去百度吧,看看怎么利用C语言代码播放声音。结果一看,果然很简单,Windows下有PlaySound函数。该函数的语法格式如下: PlaySound(声音文件名,NULL,播放控制);
常用的播放控制有SND_FILENAME(播放指定文件的声音)、SND_ASYNC(异步播放声音,即声音没播完,函数就可以返回程序继续执行后面的代码,不用等声音播完再返回)、SND_LOOP(返回循环播放声音)。
例如:PlaySound("Boing.wav", NULL,SND_FILENAME|SND_ASYNC|SND_LOOP);这句是什么意思呢?就是异步、重复地播放声音文件Boing.wav对应的声音。那根竖线是什么意思?这个符号是一种运算符,叫作“或”,就是这几种控制可以同时起作用,后面的章节会详细讲解各种运算符的含义。其中的NULL,表示空,具体什么意思,现在不用管它,随着学习的深入,自然清楚明白。
那还等什么,赶紧百度下载一个声音文件,编写代码播放吧。注意,PlaySound播放的声音必须是wav格式的,并且声音文件要和程序同在一个文件夹(也叫目录)中。要播放别的格式,如MP3格式的音乐,那就要用另外的方法,感兴趣的读者可以自行百度一下。

在这里插入图片描述
编译运行吧。哎,怎么编译链接接通不过呢?!出来什么“undefined reference to ‘PlaySoundA@12’"之类的令人不愉快的错误信息。怎么办?其实是播放声音用到了Windows的多媒体函数库winmm,在链接时需要链接这个库的代码。方法很简单,对应的编译链接命令行如下(假设上面的程序存为HelloSound.c):
gcc HelloSound.c -o hs.exe -lwinmm
注意,-o选项表明生成的exe文件名为hs.exe(这个文件名可以自己随便取,但最好取短点,这样运行时输入文件名方便;另外,取名最好要见名知义,方便自己,不然过一段时间一看,这处程序是什么意思呢是?!),-l(不是数字1,而是字母L的小写)表明要链接对应的库代码(这个L的小写代表的是library库这个单词)。
用上面的命令行编译链接,再运行吧(直接在命令行提示符下输入hs后按Enter键即可)。
hs
成功了,终于看到了Hello,World!字符串的输出了,但,哎,怎么没有声音呢?!其实很简单,PlaySound函数采用异步播放,刚要播放,结果程序就已经结束了(执行return 0;语句返回,退出程序了,自然就会终止声音播放)。怎么办呢?很简单,在return 0; 这条语句前加上一句;getch();,等着用户输入任意一个字符后再退出程序,程序正好在这段等待的时间内播放声音。刚加的这个字符输入函数在后面的游戏编写中大量用于键盘的输入,如贪吃蛇游戏中用来接收上下左右光标键等,它在头文件conio.h中声明,所以先包含这个头文件;#include<conio.h>。试试吧。最终的程序如下 。
#include <stdio.h>
#include <conio.h>
#include<windows.h>
int main(void)
{
printf(“Hello,world!”\n);
printf("接下来请欣赏BoBo的声音,哈哈!”);
PlaySound(“Boing.wav”,NULL, SND_FILENAME | SND_ASYNC|SND_LOOP);
getch();
return 0;
}
恭喜你,终于能在你自己的程序中播放wav格式的声音文件了。
1.3.3 功能强大的system库函数
在头文件stdib.h中声明的库函数system功能强大,理论上能够执行操作系统的任何可执行程序。用法非常简单,语法格式如下:
system("可执行的程序命令“);
例如,下面的程序会在5s后强制关闭计算机。
【例1-12】利用system库函数实现关机。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf(“5s后关闭当前计算机!\n”);
system("shutdwon -s -t 5 -f ");
return 0;
}
其中shutdown是系统的关机命令,具体的各个参数的含义可以在命令行下用shutdown/?查看该命令的帮助信息,Windows下一般命令的具体用法都可以用类似的方法查看帮助信息,如查看显示或修改系统日期的命令date的帮助信息可以用:date/?。
上面的程序是定时5s后强制关机,通过查对应的命令帮助信息,你弄明白了-s,-t, 5和-f的具体含义了吗?如果会查帮助信息了,请改写上面的程序,让计算机在5s后重新启动,而不是关机。
还可以修改上面的程序,分别加入下面的一条或多条语句,看看能完成什么功能(具体的功能看//后面当行注释里的内容。但不能光看书,再简单,都一定要亲自动手输入代码到程序中编译运行出来,这样慢慢会培养起你和计算机之间的感情!)。
system(“date/T”); //查看系统日期,查查/T是什么意思
system(“notepad.exe”); //启动Windows自带的记事本程序
system(“calc.exe”); //启动Windows自带的计算器程序
system(“gcc hi.c -o hi.exe & hi.exe”); //编译运行c程序,前提是当前目录下有hi.c这个c程序。&是系统支持的一种运行逻辑:命令1&命令2。即先执行命令1,然后执行命令2(上面的命令是先执行编译命令gcc hi.c-o hi.exe,然后再执行运行命令hi.exe)
system(“start http://www.qqhru.edu.cn/”); //启动浏览器,打开指定的某个网页
system(“winwine.exe”); //启动Windows系统自带的扫雷游戏
system(“mspaint.exe”); //启动Windows系统自带的画图程序
system(“del hi.exe”); //删除当前目录下的文件hi.exe
system(“ipconfig | find \ “IPv4"”); //显示当前机器IP地址,ipconfig命令是查看当前机器的网络地址设置,|是管道命令,用法:命令a|命令b,含义是将命令a的输出作为命令b的输入;find命令是在字符串行中查找具有IP Address这个子串的行输出。另外在字符串(”和“间的若干字符)中如果要使用”字符本身,则必须使用转义字符”(斜杠加上一个“)来表示双引号本身。
system(“pause>nul”); //暂停等待,pause命令暂停,>是输出重定向,将pause命令输出的信息送到nul空设备中(顾名思义,空设备如同黑洞,对送入的任何信息一点都不显示,仿佛进入黑洞中消失得无影无踪了,如果没有进行输出重定向,则pause命令的输出会默认输出到屏幕上)更多的系统命令及组合用法(如输入/输出重定向、管道等)。
**

							******## 第2章 数据存储与运算******

	计算机能且只能做两件事情:执行计算与保存计算结果。C语言提供了大量的运算符,用于各种计算,参与计算的是数据,数据需要保存计算机内存中。数据是分类型的,如整数、实数、字符、字符串等。不同类型的数据需要的存储空间大小不同,支持的运算也不同。运算主要涉及算术运算、关系运算和逻辑运算等,通过这些运算可以解决很多实际问题。
	把数字、字符、字符串等输入计算机,就是希望程序利用这些数据完成某些任务,例如输入整数100,通过计算输出100以内的所有质数。
	无论是程序代码还是数据,计算机中存储的都是0、1串。虽然需要了解数据在计算机内部的二进制存储形式,但编程时我们一般会使用十进制表示数据。
	本章主要内容是定义变量使用内存,使用运算符进行计算。
					2.1   示例程序
		本章从一个简单程序开始,通过这个示例程序,让大家对后面要讲到的变量、常量、运算符、表达式、数据类型等有一个初步认识。试着编译运行该程序,看自己能理解多少。
		【例2-1】计算圆的面积。
		#include <stdio.h>
		int main(void)
		{
			double radius, area;
			printf("请输入一个圆的半径:\n");
			scanf("%lf", &radius);
			area = 3.14159 * radius * radius;
			printf("半径为%.2f的圆的面积是:%.2f\n",radius,area);
			return 0;
			}
			本程序可以通过键盘输入圆的半径,之后计算并输出圆的面积。
			程序运行结果如图2-1所示。

在这里插入图片描述下面对例2-1代码做简单的解析:
double radius , area;
这条语句定义radius和area是变量,并且是双精度的浮点类型,告诉计算机radius和area可以存储带小数的数字。一般情况下,一个double类型的变量占8个字节内存空间。
scanf(“%lf”, &radius);
scanf()函数用于读取来自键盘的输入。%lf说明scanf要读取用户从键盘输入的双精度浮点数,&radius告诉scanf(),把输入的浮点数放到变量radius中,radius前面的”&“符号是取地址运算符。相当于快递员通过邮寄地址找到你家,把快递送到你手里。每个内存单元都是有地址的。
area = 3.14159radiusradius;
赋值运算符(=)右侧是算术表达式,计算圆的面积,之后把值放到赋值运算符(=)左侧的变量area中。3.14159侧是字面常量,常量也是有类型的,后面详细介绍。
printf("半径为%.2f的圆的面积是:%.2f\n”,radius,area);
printf()函数把变量radius和area的值输出到屏幕上,其中%.2f说明输出的浮点数小数点后面有两位数字。
通过这个简单实例希望你已经对变量、运算符和表达式等有了初步认识,接下来详细学习变量、数据类型、常量、运算符与表达式等相关知识。
**

2.2 数据类型与变量

2.2.1 数据类型
C语言可以处理多种类型的数据,如整数、字符和浮点数。把变量定义为整型或字符类型或浮点类型,计算机才能正确地存储、读取和解析数据。
计算机内部对数据采用二进制数进行存储、传输和计算。而程序员在编程时,对不同的数据进行分类,符合人们对数据的理解,用户输入的各种信息则由计算机软件和硬件自动转换为二进制数,在数据处理完成后,再由计算机转换为用户熟悉的十进制数或其他信息。
对于C程序员来说,要熟悉各种数据类型及其相应的内部存储原理,这样才能更好地写出高质量的代码来,避免数据溢出等问题。
程序必须使用不同的方式来存储和处理不同类型的数据,如整数类型、浮点类型。为了达到这个目的,编译器需要知道某个特定值属于哪种数据类型。
C语言数据类型的分类方式如下。
(1)基本类型
标准整数类型,以及扩充的整数类型。
实数浮点类型,以及复数浮点类型。
(2)枚举类型
(3)void类型
(4)派生类型
指针类型
数组类型
结构类型
联合类型
(5)函数类型
函数类型描述了函数接口。这指的是,该类型既指定了函数返回值的类型,又指定了在调用该函数时,传递给函数的所有参数的类型。
本章只介绍基本类型、枚举类型和void类型。
数据在计算机内存中是以二进制的形式存储的,1个二进制数称为1位(bit),它是计算机存储中最小的单位。由于使用位做单位太小,所以计算机大多采用字节(byte)作为计算机存储单位,对于几乎所有的机器,1个字节由8个二进制位组成。字(word)是设计计算机时给定的自然存储单位。对于8位的微型计算机,1个字长只有8位。从那以后,个人计算机字长增至16位、32位,直到目前的64位。计算机的字长越长,其数据处理的速度越快,允许的内存访问也更多。
计算机中的数值计算基本上分为两类:整数和浮点数。例如,16个二进制如果用来表示非负整数,可表示的范围是0~65535,在这个范围内共有216个整数。采用32位表示非负整数则可以表示的最大整数达到大约40亿(232-1=4294967295),这个数虽然很大,但还是有限的。数学中的数有无限个,而计算机中通常用固定长度(二进制位数)的二进制数来表示,所以计算机内所能表示的数的范围是有限的,它们只是数学中所有实数的一个子集。任何数值计算,都必须把计算机仅有的固定数值表示范围这一个重要事实考虑在内。
除了非负整数,还要考虑负数在计算机内部的表示。计算机经常用一种具有符号位的“补码”表示。如果用16位二进制表示带符号的整数,若采用补码表示方法,则其表示范围是-32768-32767; 32位二进制表示带符号的整数,可以表示的范围是-231~231-1,-2147483648~2147483647。
数据类型可以让程序员清楚每种类型数据的数值表示范围。

2.2.2 常量

在C语言源代码中,有些类型的数据在程序运行前已经预先设定好了。在整个程序的运行过程中没有变化,这些称为常量。常量是一种标记,用来描述一个固定的值,可能是整数,浮点数、字符或者字符串。一个常量的类型由它的值和记数法(notation)决定,例如,例2-1中的3.14159就是一个双精度类型的字面常量,也可以使用关键字const定义一个符号常量。例如:
const double PI=3.14159;
PI就是一个符号常量,它在整个程序运行过程中值是不能改变的。
也可以使用预编译指令定义符号常量,例如:
#define PI 3.14159
关于预编译指令,第5章有详细介绍。推荐使用const定义符号常量,因为const定义的常量是有类型的,编译时可以进行类型检查。

2.2.3 变量

	程序处理的数据一般先放入内存,内存的值是可以变化的。编程的本质就是对内存中数据的访问和修改。程序员通过变量访问或修改内存中的数据,每一个变量都代表了一小块内存,而变量是有名字的,程序对变量赋值,其实就是把数据装入该变量所代表的内存区的过程,同样道理,程序读取变量的值,实际上就是从该变量所代表的内存区取值的过程。(对于变量可以理解为有名称的容器,该容器用于装载不同类型的数据)
	一个数据的类型决定了这个数据在内存中所占用空间的大小,以及它的值所采用的编码方式。例如,同样组合的二进制位可能代表完全不同的整数值,它取决于该数据对象是被解释成带符号(signed)的或者无符号(unsinged)的。
	先看一个实例来理解什么是变量。
	编程计算1到n的和。可以用数学求和公式s={(n+1)*n}/2,计算指定n值的1到n的和。n是一个变量,给n赋不同的值,求和结果就不同。
	【例2-2】计算1-n的和。
	#include <stdio.h>
	int main(void)
	{
			int s, n;								//定义变量
			n=10;								//给整型变量n赋整数10	
			s=(n+1)*n/2;						//利用求和公式计算1~10的和
			printf("s=%d\n",s);				//输出求和结果
			n=100;								//给整型变量n赋整数100
			s=(n+1)*n/2;					//利用求和公式计算1~100的和
			printf("s=%d\n", s);			//输出求和结果
			return 0;
			}
			变量是内存的一个区域,类型不同,分配的字节数不同。后面会对各种数据类型所占字节数及数的范围做详细分析。
			下面对例2-2代码进行解析。
			int s,n;
		这条语句定义了两个整型变量,变量都是有类型的。int为整型数据类型标识符,整型变量一般占4个字节。
		n=10;
		s=(n+1)*n/2;

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

manyoftenvictory

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

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

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

打赏作者

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

抵扣说明:

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

余额充值