C 语言教学——从 Hello World 讲起
先直接上一份 C 的代码:
#include <stdio.h>
int main(void)
{
printf("Hello world!");
return 0;
}嗯,这就是一份比较简单的 C 代码了。代码的效果,是在屏幕上打印出 “Hello world!” 的字样。功能非常简单,但是究竟这些代码是什么含义,为什么组合在一起就能够产生这样的效果呢?我们来一点一点解释。
先来个简单版的解释:
int main(void)
{
return 0;
}这部分代码是一个固定搭配。它表示的是程序的入口,是整个程序的大门。程序运行的时候,首先找到的就是这么一个地方。
而 printf("Hello world!"); 这一行呢,是借用一个叫做 printf 的工具,这个工具是系统自带的,作用呢,就是往屏幕上打印。那么究竟打印什么内容呢?这便由括号里的东西来决定了。在这份实例代码中,我们括号里写着"Hello world!",就是让屏幕上打印出 Hello world! 这句话。
再回过头看第一行 #include <stdio.h> 。前面讲到,printf 是一个系统自带的工具,但是系统自带的工具有很多,放在很多地方,程序怎么知道上哪儿找 printf 这个工具呢?这便是第一行代码的作用了。stdio.h 可以理解为一个工具包。通过 include 语句,把这个工具包引入到程序里,程序才能使用它里面的工具。而 printf 正是在这个工具包中的。
通过上面的解释,相信你应该已经有了一个大体的了解。下面,我们更加仔细地解释一下。
首先我们说说 int main(void) 是什么。
每一个在我们的操作系统上运行的程序,说到底其实都是由操作系统打开的。但是我们有没有想过,操作系统是怎么知道打开一个程序之后应该先做什么再做什么?就比如我们打开 QQ 的时候,总是会先进入登录界面而不是打开什么个人资料卡的窗口之类的,这告诉我们,每个程序的执行,都是有一个既定的顺序的。那么,既然存在顺序,就势必有一个“开始”。没错,这里的int main(void)标识的便是我们程序的入口,它的名字,叫做 main 函数(main fuction) ,也有人用纯中文的方式,管它叫“主函数”或者“主方法”。
在 C 语言中,函数(function)语法上的定义,就是
返回值类型 函数名(函数参数列表)
{
函数体
}
这样的形式。其中函数参数列表可以为空,就是什么都不写。函数体,就是这个函数的主体,也就是这个函数实际要做的事情。那么返回值类型,返回值又是什么呢?
大家对于数学中的函数应该都比较熟悉了。数学中我们常常会写 y = f(x) 。C 语言里的函数其实跟数学函数在外观上是非常相近的。数学中定义某函数 f ,自变量为 x ,函数值就是 f(x) 。对应到 C 语言的函数中,我们可以简单地认为,函数参数,就是这个函数的“自变量”(不同的是 C 语言的函数可以没有“自变量”),而返回值类型,就是定义的这个函数的函数值是什么类型,或者,用数学的方式讲,就是类似于“值域”的概念。
有了返回值类型,那么返回值也就是“函数值”究竟是什么呢?回到我们一开始的代码中,大家应该不难猜到,return 语句,就是决定这个函数的返回值的。
我们再看一眼 main 函数,函数名是 main ,这是标准中规定的,入口函数就叫这个名字。函数返回值类型为 int ,这里的 int 是 integer 的缩写,也就是整数的意思,限定了这个函数的函数值只能是整数。函数参数列表为空,意味着无论这个函数的返回值,完全是这个函数自己决定的,不随外界条件变化。而函数体中最后的return 0;一句,则给出了这个函数的返回值为整数 0 。
C 语言中,main函数由于身份特殊,按照标准,它的返回值类型必须是 int ,而函数参数列表要么是空,也就是main(void)的形式;要么是带着两个参数,main(int argc, char* argv[])。对于初学者而言,第一种形式最为常见。第二种形式由于比较复杂,我们这里按下不表。另外,main 函数的返回值,习惯中大家在程序正常退出的情况下,会给出返回值为 0 。main 函数的返回值是给程序的调用者(比如系统)看的,以方便调用者知道程序是否正常执行正常退出。
接下来再谈谈printf("Hello world!");这一行。
用 C 语言的行话,printf 是一个标准库函数,叫做“格式化输出函数”( f 表示的是 format 的含义)。这里的“标准库”,指的是 C 语言的标准中规定的一个函数库。为了方便使用,C 语言标准中规定了一系列函数,包括这些函数的函数名、参数列表、返回值类型、以及这个函数的作用,都进行了明确的规定。printf 就是这样的一个标准库里的函数。它被规定,作用是往“标准输出流”中输出字符序列,或者在大部分情况下,用更直白的话说,就是在屏幕上显示一些文字。
printf 具体显示什么,是由函数的参数决定的。我们的示例代码中是 printf 最简单的一种参数形式。"Hello world!"在 C 语言中称为一个“字符串”,也就是由字符组成的序列,由一对半角英文双引号包起来进行表示。(如果没有双引号,程序将无法编译通过。)
printf这一行的作用,便是调用(invoke) printf 函数,并指定参数为字符串 “Hello world!” 。
细心的读者将会发现,printf 这一行和 return 一行,都用了分号结尾。这是为什么呢?
这里涉及到了 C 语言的另外一个概念:语句(statement)。每个函数都由一系列的语句构成。C 语言规定,语句必须由半角英文分号作为结尾。printf 一行被称为函数调用语句,而 return 一行被称为控制语句。
最后我们再谈谈#include <stdio.h>一行。
C 语言中,以 # 开头的都叫预编译指令,与语句不同的是,它们不需要以分号结尾。预编译指令的作用,是在程序编译阶段,为编译器提供一些信息。
对于 #include 指令而言,它的作用,是告诉编译器应该去引入那些“头文件(header file)”。在本例中,引入的头文件便是 stdio.h 。用 <> 括起来,表示这个头文件存在于系统环境变量中包含的文件夹(目录)里。
头文件 stdio.h ,是 C 语言标准库中与标准输入输出(standard input and output)相关的函数的声明存放的位置。程序要使用相关的函数,就必须在程序文件中 include 这个头文件,编译器才能在编译阶段定位到对应的标准库函数,并将其用到程序中来。
至此,我们把最简单的一个 C 语言入门程序讲解完了。最后罗列一下本文涉及到的计算机术语,并附上对应的英语。
- 函数,function
- 主函数,main function
- 返回值,return value
- 函数参数,function parametre(US. parameter)
- 标准输出流,standard output stream
- 语句,statement
- 字符串,string
- 头文件,header file
- 调用,invoke
- 预编译指令,pre-compiled instruction
如有不明白的,欢迎留言提问。想进一步了解上述术语,可以自行在网上或相关书籍中查阅资料。
注:
C99 标准中对 main 函数的可接受形式有两种:
int main(void)int main(int argc, char* argv[])
C99 标准中规定的 main 函数形式,是 main 函数的声明。而我们程序中写的 main 函数,是对它的一个定义(关于声明和定义的差别,后面讲到函数专题的时候会介绍)。
理论上,定义只要满足声明的要求即可。因此,我们常见的int main()以及int main(int argc, char** argv)这两种形式也是可以接受的。但是从代码的一致性上考虑,我们建议声明与定义保持一致。
而我们在各种其他地方的代码中,事实上还经常见到另外的两种写法:void main() 和 main()。
需要明确的是,第一种写法即返回值类型为 void 的写法,是不被规范所认可的,属于某些早期程序员的陋习,是绝对需要摈弃的。
而第二种写法,即不写返回值类型的写法,是利用了 C 语言中“函数缺省返回值类型为 int ”的规定做的省略。但是,从代码可读性上考虑,我们并不推荐省略返回值类型。