开始编程
编程不应该是枯燥的,而是有趣、有创造性的活动。所以,在学习编程的过程中,不应该死扣语法规则,以及各种诡异的语法代码,其实,那些诡异的语法代码都是给编译器看,甚至是钻编译器的漏洞。
在实际的开发中,不应该写晦涩、难懂的代码,而且是禁止写这样的代码;提倡写简洁、清晰明了的代码。毕竟大型的项目,不是个人独秀的表演,而是一个团队合作的结果。
例如Linux内核软件,是世界上许多优秀软件系统工程师的合作结果,如果写了晦涩的代码,肯定是不允许。linux内核中的DTS设备树的出现,就是抽象、屏蔽了繁杂重复的芯片配置代码,最终,通过DTS配置文件来代替。所以,优秀的软件系统,也应该是模块化程度高,代码模块之间耦合度低的系统。
OK,思路扯远了,总之,我们学习编程的过程应该是快乐、有趣的。最终,通过学习了Linux环境下的C语言编程,可以使用C语言开发有意义的软件系统。
在学习的过程中,不要死扣语法,遇到有疑问的语法和问题,直接编写测试例子来验证。例如,我们疑问double类型的变量占据多少个字节?碰到这个问题的时候,我们就直接编写一个测试例子。
#includestdio.h//包含头文件,为了使用printf()函数;
intmain()//定义程序的主函数,就是程序的入口地址;
{//主函数的开始标记;
intsize=sizeof(double);//获取double类型定义变量的容量;
printf("size=%d\n",size);//输出size变量的内容;
return0;//返回结束状态;
}//主函数的结束标记;
编译运行,输出的结果是:
gcctest.c-oout
mylinux
ubuntu:~/test./outsize=8
此时,我们就知道double类型的变量占据8个字节的容量。而且是自己通过测试例子来验证,理解更加深刻。通过编写测试例子来思路和验证遇到的疑问,是我们学习知识的一种有效途径。
毕竟我们学习是为了理解、获取到知识,而不是去死记硬背书本的知识;有时候书本和资料有误,自己去测试、验证的知识点才是正确的。最重要的是自己去测试验证过的问题才理解深刻。无论黑猫、白猫,抓到老鼠就是好猫;能够把问题讲清楚,讲明白;让大家学习到知识就是我们的宗旨。也是我们要学习的一种学习方法。
第一个例子获取系统时间
通过前面的学习准备,我们在VMware中搭建了一个Ubuntu系统,并且介绍了编程过程中需要用到的一个工具软件和计算机系统知识。那么,现在我们就可以开始学习LinuxC语言编程了。
现在我们来写第一个程序,要求实现一个比较有趣的功能,就是输出当前Ubuntu系统的时间。例如,你和朋友约好今天晚上点去干点坏事,但是,不知道现在几点了,那么,可以执行自己写的程序,查看当前的Ubuntu系统提供时间,以免误了你去干坏事。
打开Ubuntu系统,使用用户名和密码登陆系统之后,同时按下Ctrl+Alt+T按钮,就弹出一个终端,如下图3-所示。
图3-
这个终端就是我们工作的地方。OK,开始写程序,首先,我们新建一个工作目录,专门存放代码。例如你们把自己喜欢的电影,下载到某个目录一样。在终端中执行如下命令:
mkdirsrc
此时,新建有一个文件夹,名称是src;然后,再执行下面的命令,进入该文件夹。
cdsrc/
进入src文件夹之后,我们需要新建一个文件,存放编写的C代码。注意:存放C代码的文件,后缀是.c结尾,这样编译器就可以识别它是一个正确的C源码文件,然后,才可以编译源码。
新建一个test.c文件,用于存放源码,执行如下的命令。
gedittest.c
操作的步骤如下图:
此时,通过gedit命令,打开一个test.c文件,在末尾以“”结尾,表示在后台运行gedit软件工具,不阻碍继续使用当前的终端。使用gedit命令打开test.c文件之后,弹出如下图3-3对话框。
图3-3
此时,使用gedit工具打开一个test.c文件,然后,在文件中,输入如下的代码:
#includestdio.h//包含头文件,为了使用printf()函数;
#includestdlib.h//包含头文件,为了使用system()函数;
intmain()//定义程序的主函数,就是程序的入口地址;
{//主函数的开始标记;
printf("Nowtime=\n");//输出提示;
system("date");//输出系统时间;
return0;//返回结束状态;
}//主函数的结束标记;
注意,在程序中使用两个反斜杠“//”来做“注释”。在一行代码中,两个反斜杠“//”后面接着的数据表示注释数据,编译器不会编译这些数据。
那么,在讲解编程代码例子的时候,作者会尽量给出完整的注释,这样有助于读者理解代码。但是,读者自己在测试、验证代码的时候,可以不用把注释也敲打如代码中。测试例子如下图3-4。
图3-4
此时,我们在test.c文件中编写了程序的代码,但是,看起来还是缺少点什么!!!那就是“行号”,有时候编译代码出现异常,编译器会提示在哪一行出现问题,那么,我们需要定位到指定行数的代码,查找问题。
那么,我们可以配置gedit软件显示行号,步骤是:选择菜单Edit--Preferences,然后,在弹出的对话框中,找到“LineNumbers”属性,把下面的“Displaylinenumbers”复选框给勾选上,如下图:
配置完之后,在代码中就显示了行号,效果如下图:
编写完源码之后,按下Ctrl+s按键,保存编写的代码。然后,开始编译代码,编译代码格式是:
gccxxx.c-oyyy
使用gcc命令进行编译,在gcc命令后面,接空格,空格后面接xxx.c是需要编译的源码文件,然后接空格,空格后面接“-o”选项,表示编译出可执行程序;然后接空格,在空格后面接yyy表示编译出可执行程序的名称。
例如,在终端输入如下的命令:
gcctest.c-oexe
就是使用gcc命令编译test.c源码,产生exe可执行程序。最后,在当前终端输入./exe来执行程序,测试的如下图3-5所示。
图3-5
使用gcc编译产生了exe可执行程序,在执行exe程序的时候,在终端输入“./”表示执行当前目录下的程序,然后,接着exe,为“./exe”,表示执行当前目录下的exe程序。
最终,执行./exe程序,输出系统的当前时间,如下:
Nowtime=
WedJun70:3:36PDT08
我们可以连续执行多次,每次看到时间都有变化,测试如下:
mylinux
ubuntu:~/src./exeNowtime=
WedJun70:37:07PDT08
mylinux
ubuntu:~/srcmylinux
ubuntu:~/src./exeNowtime=
WedJun70:37:08PDT08
mylinux
ubuntu:~/src./exeNowtime=
WedJun70:37:0PDT08
mylinux
ubuntu:~/src./exeNowtime=
WedJun70:37:PDT08
mylinux
ubuntu:~/src./exeNowtime=
WedJun70:37:PDT08
可以看到,每次执行,都获取Ubuntu系统的当前时间,秒数显示的内容是有变化的。OK,有了这个获取时间的工具,再也不用担心耽误你去赶坏事的时间了。
3分析程序
我们学习了怎么样创建一个C源码文件(后缀是.c的文件,例如test.c),然后,编译程序,得到可执行的程序,最终执行程序。
现在,我们来分析C源码文件中的C程序,就是所谓的“代码”。这个C程序的代码如下:
#includestdio.h//包含头文件,为了使用printf()函数;
#includestdlib.h//包含头文件,为了使用system()函数;
intmain()//定义程序的主函数,就是程序的入口地址;
{//主函数的开始标记;
printf("Nowtime=\n");//输出提示;
system("date");//输出系统时间;
return0;//返回结束状态;
}//主函数的结束标记;
现在我们来分析一个C程序主要有3部分组成:
()包含头文件,引用系统提供的接口函数;
()程序的主函数,即程序的入口地址,程序从哪个地方开始执行;
(3)程序语句,实现程序功能的具体指令;如果把程序比作一栋大楼,那么,程序语句就是组成大楼的钢筋水泥;
3.包含头文件
举个例子,如果大家要起一栋大楼,会用到铁铲、推车之类的工具。这些工具会存放在某个指定的地方,一般称为“仓库”。同样,程序中使用到了printf()这样的函数,这些函数如同铁铲之类的工具,存放在C语言的“仓库”中。那么,在C语言中,这些仓库我们可以称为“头文件”。
C语言中定义的头文件,就是以.h为结尾的文件。例如stdio.h、stdlib.h文件,就是系统提供的头文件。如同C语言提供的“仓库”,里面存放了许多有用的铁铲、推车等工具,使用这些工具,我们就可以开发出一个程序。
要在代码中引用指定的头文件,格式如下:
#includexxx.h
其中xxx的头文件的名称。这个格式是固定的,前面必须是#include关键字,然后使用尖括号“”,中间是引用的.h头文件。
所以,我们知道了头文件的作用,就是一个仓库,存放很多编码使用的工具。我们必须使用仓库中的工具,才可以进行编码。随着学习的深入,我们可以定义自己的仓库,存放自己定义的函数模块。就是定义自己的.h头文件,然后,声明引出自己定义的函数,让其他模块使用。
3.程序的入口
读书的时候,每一个学校都有一个校门口,要合法、正规地进入学校,就只能够通过校门口进入。当然也可以通过翻墙等行为进出学校,但是都不是学校所允许的。同样的道理,每一个程序要能够操作系统上正常运行,都必须提供一个入口,让操作系统通过这个入口,加载程序中的数据,然后,运行程序。
C语言中定义了程序入口,就是main函数。在我们的测试例子中,有:
intmain()//定义程序的主函数,就是程序的入口地址;
{//主函数的开始标记;
printf("Nowtime=\n");//输出提示;
system("date");//输出系统时间;
return0;//返回结束状态;
}//主函数的结束标记;
这就是定义了main函数,这个main函数的定义是:
()函数的返回值类型是int类型,就是返回一个int类型的数据;
()函数名的名称必须是main关键词;
(3)函数名main后面接一个小括号(),括号里是空,表示不携带参数;
(4)在小括号()后面接一个大括号{},这个大括号{}中的代码就是main函数要执行的代码;
(5)执行代码的最后,通过return关键字返回0数值,就是为了符合main函数开始定义时,要求返回int类型的变量。
在这里,我们讲解了main函数的定义,主要是说明main函数是程序的入口地址,如同一个学校的校门口一样,要通过校门口,才可以进入学校。同样,main函数提供了程序的入口地址,所以,我们要写的程序代码,就是在main函数中编写,main函数被操作系统调用之后,我们写的程序代码也就被操作系统调用执行。
所以,在main函数中,我们就编写了需要执行的代码。操作系统把程序加载到内存之后,找到main函数这个入口,然后,就一条一条地执行我们编写的代码。
3.3函数体的代码
程序的入口是从main函数开始,所以,我们要实现的代码也就是在main函数的函数体中编写。main函数的定义格式是:
intmain()//定义程序的主函数,就是程序的入口地址;
{
}//主函数的结束标记;
那么,函数体就是在大括号{}中的代码。在测试例子中,函数体中的代码是:
printf("Nowtime=\n");//输出提示;
system("date");//输出系统时间;
return0;//返回结束状态;
这些代码的作用是:
()printf函数输出"Nowtime=\n"字符串中的数据,后面的"\n"表示回车换行;
()system函数执行参数"date"指定的动作,获取系统时间输出;
(3)return关键字返回一个值,表示退出main函数的运行;
注意:每一行代码必须以引号“;”结束。除了遇到如下几种特殊情况:
()使用#include包含头文件,不需要引号结束;
()函数的声明,在小括号()后面,不需要引号结束;
(3)函数体的大括号{}后面,不需要引号结束;
那么,当我们学习了变量,运算符,表达式,输入/输出函数等知识之后,就可以自由编写函数体中的代码,实现更加复杂的功能。我们可以把想要计算机实现的功能通过C语言来描述,然后,编译成可执行程序来运行。
3.4程序的注释
我们先来看看一个测试例子:
#includestdio.h//包含头文件,为了使用printf()函数;
intmain()//定义程序的主函数,就是程序的入口地址;
{//主函数的开始标记;
/*注释
可以注释多行
代码*/
printf("testabc!\n");
return0;//返回结束状态;
}
测试运行结果如下:
mylinux
ubuntu:~/src/testgcctest.c-oexemylinux
ubuntu:~/src/test./exetestabc!
在这个测试例子中,我们主要讲解C语言的“注释”。在代码中添加注释很有必要,例如,我们需要描述某一段关键的代码,描述某一个函数模块的时候,就需要在代码中添加注释,那么,当一个项目有多个开发人员在共同开发时,大家可以通过代码的注释来快速了解代码的构造和设计。
C语言提供了两种中注释方法:
()单行注释
在一行中,以两个反斜杠“//”开始,后面接着的数据就是注释。注释的数据不会被编译器编译,所以,注释里面写的东西可以中文或其他字符,不要求是C语言写的代码。注意:“//”注释符只能够在单一行中使用,不能够跨越多行。例如上面的例子中,有:
intmain()//定义程序的主函数,就是程序的入口地址;
这是合法的,因为注释符“//”后面接的数据都是在一行中。
()多行注释
“多行注释”也称为“块注释”,就是可以注释多行代码块。多行注释是以“/*”开始,以“*/”结束。例如上面例子中的代码有:
/*注释
可以注释多行
代码*/
printf("testabc!\n");
就是通过/**/来注释多行。注意,多行注释符/**/不能够嵌套,不能够编写/*abc/*3*/