从现在开始我们将一起开始我们的C语言之旅:
我对C语言的直观印象:
首先我们来了解C语言。首先就我个人而言我觉得C语言是强大的(C语言是所有的高级语言里唯一一个可以直接操作硬件的语言,虽然他只是能通过指针来操作
计算机的内存,C语言的强大还在于其他很多语言对C的依赖性,无论是简洁强大的Java还是优秀的脚本语言Python或者是在游戏脚本占统治地位的Lua....等等
他们运行所依赖的虚拟机都是由C语言编写的,还有支撑起全球软件工业的操作系统UNIX、Linux也都是由C语言编写的)其实C语言是低级的,他既不支持面向对
象也不支持象接口、协议、块、模板、容器、多返回值.....等等一系列的高级操作。但是无论如何C语言都是全球软件工业的基础!
C语言的历史:
20世纪60年代,美国AT&T公司贝尔实验室的研究员Ken Thompson,想玩一个他自己编的,模拟在太阳系航行的电子游戏——Space Travel。他找到了台空闲的机器
——PDP7。但这台机器没有操作系统,而游戏必须使用操作系统的一些功能,于是他着手为PDP-7开发操作系统。后来,这个操作系统被命名为——UNIX。(现代操作
系统的基础)他以BCPL语言为基础,设计出很简单且很接近硬件的B语言(取BCPL的首字母)。并且他用B语言写了第一个UNIX操作系统。1971年,Dennis M.Ritchie
为了能早点儿玩上游戏,加入了Thompson的开发项目,合作开发UNIX。他的主要工作是改造B语言,使其更成熟。1972年,美国贝尔实验室的 D.M.Ritchie 在B语
言的基础上最终设计出了一种新的语言,他取了BCPL的第二个字母作为这种语言的名字,这就是C语言。1973年初,C语言的主体完成。Thompson和Ritchie迫不及
待地开始用它完全重写了UNIX。此时,编程的乐趣使他们已经完全忘记了那个"Space Travel",一门心思地投入到了UNIX和C语言的开发中。随着UNIX的发展,C语
言自身也在不断地完善。直到今天,各种版本的UNIX内核和周边工具仍然使用C语言作为最主要的开发语言,其中还有不少继承Thompson和Ritchie之手的代码首先我们看一下示例代码:
首先我们看到内容的第一行:#include<studio.h>
什么意思呢?
1、首先#include是C语言的预处理主要用于引用C工程的头文件,前面一句话出现了三个词“C工程”、“头文件”、“引入”他们分别是什么意思?下面我们来分别讲解
“C工程”:我们知道绝大多数功能完善的程序都不只是有一个文件构成的,他们通常分为“代码文件”和“数据文件”,而我们仅关心代码文件,由于几乎每个软件
都有若干个功能,我们未来编程时方便管理以及完成后便与维护,我们通常根据各个功能将程序划分为若干个模块,每个模块有可能分为若干个子模块,于是我
就会将代码分别在不同的文件中编写,我们为了统一管理这些文件,我们就将这些文件组成一个工程。
2、头文件:我们的每一个源文件都隶属于同一个工程,那么他就有可能使用其他源文件所定义的一些功能,我们为了能让每个源文件都能够独立编译,所以我们就
要声明我们所要使用的一些方法,于是就有了头文件,其实头文件就是一系列的变量与方法的声明。
3、引入:引入就是拷贝,将头文件中的内容拷贝到我们的源文件或另一个头文件中。
---------------------------------------------------------------------------------
接下来我们看一下头文件的定义:
首先文件的后缀名为 .h 文件名一定要符合命名规则。我们看到我们声明了一个名为Test.h的头文件
好了接下来我们就要完成头文件的编写我们写一个方法
首先我们看到了一个器官的结构:
#ifndef __TEST__
#define __TEST__
..........
..........
#endif
其实他是一个宏定义,如果将它“翻译”一下的话就是:如果没有定义__TEST__那就定义__TEST__最后。当然如果系统检测到我们已经定义过__TEST__的话就不会再向下
执行直接跳到#endif。那么我们为什么要使用这么一个结构呢?其实是为了防止该头文件在同一个源文件中重复引入。就是说如果有一个头文件引用了这个头文件,而
在某一个源文件中,同时引入了这两个头文件,那么问题来了我们之前讨论过引入就是拷贝,本来第二个头文件中就拷贝了头文件一的内容,而现在源文件将头文件一
头文件二都有拷贝了一遍,那结果就清楚了,源文件中存在两份头文件一的拷贝,这是不允许的(这个后面讨论),就会引发错误。所以我们引入上述机制,当头文件二
引入头文件一是,就会执行上述机制,因而环境中就会存在__TEST__当在源文件中再次引入头文件一时,因为检测到了__TEST__的存在就不会继续执行,因此不会重复
引入。
我们继续向下看
#include<stdio.h>
我们使用引入了一个系统的头文件(我是怎么知道他是一个系统头文件,而不是自定义头文件?这个问题我们稍后再讲),其实这个头文件里面定义了标准输入输出,还有其他一些我们常用的库函数,不知各位想不想一睹它的风采(由于此文件过长,我们仅展示部分):
我们说过引入头文件其实就是讲头文件的拷贝。
下面的一行就是函数的定义:void say();
我们首先说明函数的作用,其实函数就是一个代码块,将一个具有独立功能的代码库封装为一个函数。如果要让这个功能块起作用那么我们首先需要给他
一部分数据,这部分数据就是函数运行时需要对这部分数据进行处理,那么问题来了,既然我们要对一些数据进行处理那么处理的结果如何?(其实这个
结果分为两种:其一是函数有没有正确的运行,其二就是当函数正确运行后对数据处理的结果。这个涉及到C语言的一些高级特性,我们先假设我们现在
的函数都是可以正常运行的)那么我们就需要函数给我们一个返回值(广义上来讲就算一个函数告诉你他返回结果,其实也是一种返回值)。当然我们之
所以要定义一个函数,就是为了使用这个函数,那么我们如何使用一个函数呢?突然发现函数还应该有一个名称---函数名
经过上述讨论,我们得知一个函数分为四个部分:函数返回值、函数名、参数列表、函数体。而我们既然是要声明一个函数,那么就是说我们只要声明函
数的唯一标示无需定义函数体那么就是上面所写的啦:
void代表函数没有返回值,say代表函数名,而空括号代表函数的参数列表随意个数、每个参数随意类型(注意空括号不代表没有参数,这个问题我们到
讲解函数时再细细讨论)。最后加一个分号,一个函数的声明就完成了。
好了下面我们看文件的定义:
首先我们看到文件的定义,使用了和文件声明一样的文件名,只是将文件的后缀名有.h变为了.c我们在文件的定义中首先需要引入头文件以及系统的头文件
我们看到我们在引入系统头文件是在#include后面使用的是一对<文件名>而我们在引入自定义的文件时使用的是"文件名"。还记不记得我们上面是我说
看到一个文件的引入我们就知道他是一个自定义的还是系统定义的,规定:当我们引入系统头文件时使用尖括号而在引入自定义文件时使用英文双引号
我们继续向下看到的就是函数的定义了,我们看到这个函数和我们声明的一模一样,只是将最后的分号替换为一对大括号,而大括号的中间有了一些代
码而这些代码就函数体。我们看到我们在我们的函数中调用了一个叫做printf的函数,别的不说让我们先来看看他的定义代码吧。好,请看下面:
以上代码我们不做过多的解释,只是为了让大家能有一个直观的印象。其实他的作用就是格式化打印一个字符串。
好,下面我们来看本工程的最后一部分,主函数:
最先我们还是看代码:
我看到我们引入了两个头文件下面我们就定义了一个函数名为main返回值为int参数列表为任意参数。首先我们看main函数的最后一行有一个return 0;
这其实就是函数的返回值。还记得我们的main函数的返回值类型为int那就说明此函数有可能返回一个int类型的返回值。那么定义函数的返回值类型就
一定要有返回值吗?其实不然,C语言是一种弱语法语言,函数的返回值不必一定返回,就像是假设你定义的函数的参数列表有3个参数,你既可以给他
2个实参也可以给他4个实参,事实上你可以给他任意多个参数,就像你声明的参数列表为空一样的。那么假如你想你的函数不允许参数怎么办?简单,
需要在参数列表所在的括号内添加void关键字。
好,一个完整可以运行的C工程就这样完成了,下面我们来看函数的运行结果:
第一行是我们调用say函数的打印结果
第二行是我们的printf函数的打印结果。
最后我们在讨论一下,一个程序为什么必须有main函数,main函数究竟起到了什么样地作用,一个程序究竟是怎样开始运行的:
首先为什么函数必须要有main函数?
任何一个程序都要很多的代码,要运行就要有一个开始运行的地方,那么这个main函数就是每个函数运行的首地址。
main函数究竟起了什么样地作用:
其实他就是函数的入口函数,我们的一个工程很可能含有很多很多个函数,而函数一旦运行首先会运行main函数内的代码,而其他的函数都是在
main函数内或其他函数内被调用。
一个函数究竟是如何运行的?
熟悉UNIX的读者都知道,UNIX有一个叫做程序加载器的东西。我们要运行一个程序,就是告诉我们系统的程序加载器将我们的程序加载到内存中去,然后
在分配给他进程,他就可以运行了。
Ok,今天我们就学习到这里啦,拜。