C语言教程-1_1-什么是程序
C语言概述
首先,关于C语言的发展历史,您应该去书上找到答案,这里省略之。
如章节1_1
所述,C语言有着非常重要的历史地位,至今仍然久居高位而不下。尽管它并不是汇编之后的第一门高级语言,但是它
C语言是一门在高级语言中相对底层的编程语言。允许通过指针直接访问内存,并支持内联汇编等特性,使得C语言不仅具备了高级语言的便利性,还保留了较高的运行效率。然而,尽管C语言的高效性使其广受欢迎,但由于缺乏足够的抽象,C程序员往往需要关注计算机的运行逻辑对程序的影响。这种对底层细节的关注,虽然能够带来更大的控制力和自由度,却也增加了编程的复杂性和出错的风险。
学习C语言时需要注意:
- 并非“高级”:由于历史与设计原因,C的抽象度并没有Java、Python这些后起之秀高,在很多方面无法从语言层面提供便利(尽管从现代语言的角度来看是非常必要的功能);
- 设计缺陷:C语言有着许多
特殊设计设计缺陷,C代码往往隐藏着各种陷阱,它们的运行效果可能会出乎初学者的意料,感到迷惑,特别是如果您学习过其他现代语言,这一点需要您多加小心; - 不要太过深究:编程讲究融会贯通,初学时一味地探究原理并不是一件好事,特别是C语言中存在许多反直觉的陷阱,这往往会让您浪费掉大量时间,随着知识和经验的积累,这些所谓的原理会慢慢的变得看起来理所应当。
算法是什么
算法
是指解决问题的一种方法或一个过程。
算法
是若干指令的有穷序列,满足以下性质:
- 输入:有外部提供的量作为算法的输入
- 输出:算法产生至少一个量作为输出—算法必须有结果
- 确定性:组成算法的每条指令是清晰,无歧义的
- 有限性:算法中每条指令的执行次数是有限的,执行每条指令的时间也是有限的
无论是解决像“计算两个数的最大公因数”这样的简单数学问题,还是“规划一条导航路线”这样复杂的实际问题,都可以找出其解决方案,满足上面的性质,就是一个算法。
编程语言与算法
前面说,“编程语言是用于控制计算机执行特定任务的语言”,一般而言,这些特定任务就是各种算法。
我们学习C语言,是为了使用这门语言来描述各种操作,亦即算法,让计算机代为劳之。
因此,掌握基本的数学知识以及算法能力对编程开发是很有帮助的。
C语言的特点
- 简洁且紧凑:C语言一共只有32个关键字、9种控制语句,代码非常紧凑干练。
- 丰富的类型系统:C语言的数据类型非常丰富,包括整形、浮点型、字符型、数组类型、指针类型、结构体类型和共用体类型等,进而能够“氢崧”实现各种复杂的数据结构。
但是另一方面,C语言的类型系统并不是类型安全
的,这与C语言的设计初衷和思想有关。这个问题现在讨论还为时尚早。 - 自由且高效:C语言的
指针
是其灵魂所在,指针类型的存在让C程序可以自由地访问硬件、操作内存,因此C语言可以写出十分灵活且效率极高的程序,编写对性能有着极高要求的软件(例如操作系统)时有着极大的优势。 - 危险与效率并存:高效率和高自由度往往伴随着代价,C语言中,这种代价就是安全性问题。指针的自由与安全检查的缺乏让C代码有着极高效率的同时也伴随着安全问题,这往往会导致极其严重甚至异常昂贵的后果(例如第一个Internet蠕虫病毒)。
但是C语言的特点在某些程度上,也是其缺点所在,读者越是向后学习,就越能体会的到,这里也并不方便展开讨论。
C语言程序
C程序基本结构
我们以一个最简单,最经典的代码—Hello World!程序,作为经典的入门代码。
这个代码的效果是:向终端(命令行)输出一个“Hello,World!”字符串。
代码如下:
1 | /* |
下面将程序拆解为几块来分别进行讲解。
预处理指令
预处理指令用于在预处理阶段做一些操作,这些操作基本是纯文本操作,比如选择性地插入或替换一些文本。
预处理指令以一个 #
开头,C中有许多种预处理指令,上面这个程序只使用了 #include
指令。
文件包含-#include指令
一个完整的程序由若干操作共同完成,每一步操作都完成了整个程序流程的一小部分。这些操作中有许多现成的代码,也就是说别人已经提前写好了,我们没有必要自己重新编写,直接拿来使用即可。这种已经写好的,可以重用的代码被称为库代码
。
与其他语言类似,C语言也有许多已经写好的“库”可以直接使用,库中的功能往往以函数的形式导出,我们在使用它们之前,需要声明它们,即告诉编译器我们需要使用这个函数。
C语言中这些声明信息存在于头文件中,我们需要将特定库的头文件包含在我们的程序中。
例如 #include <stdio.h>
就是包含了stdio.h这个头文件,即我们需要使用stdio(standard In/Out)库中的函数。在上面这个程序中,printf
函数就存在于stdio中。
注:预处理指令会在后面章节讲解
主函数main()
有始有终,任何一个程序必须指定从何处开始执行,指定从何处结束执行。一个C语言程序必须从 main()
这个函数开始的( main()
也被称为主函数)。
无论一个C程序有多么庞大,整个程序必须有且仅有一个main函数,代码必定从main函数开始执行。
PS:这是对用户代码而言,实际上在运行用户代码之前,必须先将程序加载并初始化完成,这意味着有一些特定代码先于main函数执行。
尽管main函数具有唯一性,但是仍然属于一个函数。int main()
叫做main函数的函数头
,它包含了这个函数的所有基本信息—函数的名称、需要传递的参数和函数的返回值类型。
C语言的函数和数学意义上的函数基本等价,例如f(x)=x+1,其中x为整数. 这个函数就可以写为:
1 | int f(int x){ |
最后,函数头后面紧跟的就是函数体,函数体里包含了这个函数的一切操作,函数体以{}作为边界.
注:函数会在后面章节讲解!
函数内的语句
函数是C程序的基本组成单元,一个函数完成某个特定功能。例如 float sin(float x)
计算x的sin值。
一个函数中包含的所有内容包括:
- 函数要执行的所有运算步骤
- 运算中需要的一些必要的数据(局部变量或函数参数)
- 函数的运算结果以return语句返回,类似于函数值
函数中每一个操作都一条语句,语句必须由一个 ;
来结束。
一条语句可复杂可简单,一条语句由若干个表达式构成,表达式越多,越复杂冗长,这条语句就越复杂。
所以,如果可以,尽可能把一个复杂的操作分成几条语句(几步分开的操作)来运算。
例如 printf("Hello,World!\n");
这条语句就是执行了一个输出字符串的操作,其中只包含了一个表达式—函数调用表达式
—调用了printf()这个函数.
注意:很多入门教程都不会提到"函数调用表达式"这个概念,反而会使用"函数调用语句"这个名词,请注意"函数调用语句"这个东西并不存在,实际上函数调用是属于表达式的
C语言的大部分语句是由表达式构成的,即表达式语句
再例如 return 0;
这条语句指示函数结束,并返回一个值。该语句属于 跳转语句
。
任何函数,一旦执行到return语句,即意味着这个函数的执行立即结束,后面的代码无论多少都不会再继续执行,该函数立即停止执行并返回到上层。
return后面跟的值也是一个表达式,可以返回任意和函数类型符合的
,可以求值的
表达式,此处main函数默认返回一个0,0就是一个值为0的常量表达式,表示main函数正常退出。
注:语句和表达式将会在后面章节讲解。
总结
我们可以发现,一般情况下,一个完整c程序必须或应该包含以下几个部分:
- 使用
#include<>
命令进行头文件的包含,用以声明将要使用到的外部代码。
例如用于输出字符串的printf()
函数就在stdio库中,声明于stdio.h这个头文件内。 - 一个必须存在的函数,它是一切的开始—int main()函数
一个最规范正确(没有参数时)的main函数应该是这样:
1 | int main(void){ // 代表main函数的返回值为int类型,同时没有任何参数 |
我们最多可以把那个括号中的void省略,因为main中的void是在新标准中推荐添加的,我们基于C99版本进行学习即可。
关于 main()
函数,你还可能会在其他的地方看到下面这样更复杂的写法,不过我们暂时用不到他们,在遇到的时候不要奇怪:
1 | // 有2个参数的main函数,用来接收运行参数 |
上面这2种实际上都没有问题,但是我们目前用不到,特别是第2种,你几乎不会遇到他。
另外注意:一切教导你这样写main函数的资料,并且没有作为反例详细说明其问题的,请你扔掉它:
1 | main(){ |
-
其他过程,也就是其他的辅助函数,用于将功能独立出来
-
一些注释,用于标注这个程序是用来干什么的,或者某一段代码是干什么的
注意:一定要养成写注释的习惯,特别是程序越发复杂,更应该编写注释来以备日后回看,方便改进和维护。
C代码如何运行
使用C语言这样的高级语言编写的代码存储于一个源文件中,说到底依旧是一个纯文本文档,可以供人阅读,但无法让计算机运行。
源代码文本只是记录了一个程序的逻辑,并不是一个可用的程序。为了将其转换为计算机可以执行的程序,需要使用到专门的工具—C编译器(一切编译型语言都有自己专属的编译器,例如RUST语言有自己的RUST编译器,Go语言有自己的Go编译器)。
C语言最常见的编译器有以下3种:GCC编译器,MSVC编译器,Clang编译器。
作为学习者用途,使用GCC即可,对于学习阶段,各编译器大同小异,无需考虑其差异。
一旦使用编译器对代码文本进行编译,生成的二进制程序往往就和语言无关了,因为二进制程序是和系统架构严格相关的,任何语言的代码一旦编译成特定平台的程序,就难以恢复成原来的源代码。当然,逆向工程技术可以一定程度上做到代码重构,这部分内容与本教程无关。
我们学了C语言是要干什么
了解了C语言的过程,我们作为C这门技术的使用者,我们的职责就是:
设计算法,即程序的基本流程
->构思程序结构
->使用C语言进行程序的编写
->进行调试测试
->确认无误后生成正式的程序
->将程序用于实际的生产作业来发挥作用
->维护并改进
最关键的就是程序编写和调试测试.
---WAHAHA,2023.9.19
上一篇:写在前面
下一篇:C语言教程-1_2-关键概念