Linux C编程实战之路
Linux下C编程概要
第一个问题,假设我是一个初学者,我需要学习的第一个知识并非C语言本身,而是可供我编辑、编译、验证乃至调试C语言程序的编程环境,如果你没有一个合适的编程环境,那么C语言的学习将是空中楼阁,无从谈起。
因此我们的第一个任务便是搭建一个属于自己的编程平台,由于针对Linux编程,我推荐大家直接使用Linux系统,Linux系统有许多发行版,选择一个易用的就行了,比如我比较推荐Ubuntu,RedHat也是一款很成熟的Linux操作系统,但是redhat作为服务器Linux加载的服务太多,我们拿着这么一台为服务器准备的系统当成PC来用不大合适,比如开关机时间就很长(服务器一般不会天天开关机)。
ubuntu操作系统的安装ISO镜像在网上到处都有,也可以通过ubuntu的官网下载:http://www.ubuntu.com/。下载下来之后可以安装在虚拟机里,也可以刻成光盘安装在硬盘上,随你喜好。
好了,下面来正式讲解C编程技术。这里,我们先不要着急去学习具体的语法点,而是来个统观全局,看看一个C程序是长成什么样子的,有哪些要注意的地方,撇开语法细节,注重整体的程序编写布局和规范,这是一个非常重要的步骤。就像厨师学厨艺,不是一来就马上学习每一道菜怎么做,而是先观察师傅做出来的菜是什么样的,从大的方面加以学习和模仿,学习如何将菜做的好看,摆放惹眼,然后再考虑好吃,营养丰富等方面,如果一盘菜看起来就让人倒胃口,即使再可口营养再丰富,也是大打折扣的。写代码也是一样的,一开始要学会如何组织你的代码,使人看起来舒服,样式规范,风格一致,然后再来讨论如何使得代码的性能更好,算法更紧凑。搞清写代码的总体要求,这样在后面的细节学习的时候,就有个总绳可以遵循。
下面是一个完整的C程序:
//example1.c
#include <stdio.h>
#include <string.h>
#include <strings.h>
int main(void)
{
char buf[100];
bzero(buf, 100);
fgets(buf, 100, stdin);
printf("you have input %d letters\n", strlen(buf));
return 0;
}
//example1.c
#include <stdio.h>
#include <string.h>
#include <strings.h>
int main(void)
{
char buf[100];
bzero(buf, 100);
fgets(buf, 100, stdin);
printf("you have input %d letters\n", strlen(buf));
return 0;
}
注意观察上面的程序,有这么几个要点需要谨记:
1, 写程序的时候,代码块内部的代码,一定要有缩进,注意到在main函数中,左花括号和右花括号分别各自独占一行,而里面的代码统统缩进8个空格。注意,一定要缩进而且最好统一缩进8个空格,这样做的好处是使得代码块逻辑清晰,结构分明。
2,注意适当的地方要有空格,就像英文文档的普遍书写习惯一样,一般在标点符号的右边都空一下。另外,如果程序中有赋值号“=”也最好在左右两边空格一下,不要让你的代码统统挤在一起。
3,要注意在适当的地方有空行,比如在不同的逻辑块之间,在上面的例子中,写完最开头的三行#include语句之后,是main函数,它们之间没有紧密的逻辑关系,可以空行一下。另外在程序代码中,也要适当空行,不然你的代码将会很快使人疲乏,适当的空行会使生活更美好,而且空行空格是免费的,不要吝啬它们。
上面几点是编程规范,下面再来看看example1.c中具体的代码:
1,最开始的一行是//example1.c 这是一个注释语句,因为它以两个正斜杠开头。凡是以两个正斜杠//开头的语句,在C语言中都将被视为注释语句,所谓的注释语句就是在编译的时候会被丢弃的语句,这样的语句用于开发者在程序中书写自然语言,来对复杂的代码加以解释,方便阅读。
另外,C语言中的注释还可以是这样的形式:
/* 这是一行注释,对代码的运行不起任何作用 */
/*
这样的注释是C语言的传统风格
可以同时注释多行,但是不能嵌套
这些注释语句在编译时都将被丢弃
*/
上面的注释语句是用/* ... ... */ 包含起来的。写注释是对阅读代码的人负责的表现,如果一个程序的实现逻辑非常复杂,并不能一眼能看懂,那么不加注释对于程序的阅读者和维护者而言将会是一场噩梦。那么注释写什么呢?答案是:写代码的功能,而不是写原理。比如你写了一个函数,这个函数用了高深的数学原理实现了求解某范围内的所有素数,那么你的注释写的就是它的功能:寻找素数。而不是写它是如何运用数学原理找到的。我们都是实用主义者,我们知道怎么用就行了,其他的不关心。
2,接下来的三行是预处理指令#include .... 所谓的预处理指令就是以#开头的语句。(除了黏贴符##之外,我们以后在讲解复杂宏的时候会讲解)预处理指令其实不是C语言的一部分,这些指令由专门的称之为预处理器的软件cpp来完成,而且#include <xxxxxx.h> 语句的作用就是将所指定的文件直接拷贝到当前行。这些文件的后缀是.h,h的意思就是head的意思,因此这些文件也被称为头文件,它们在哪儿呢?答案是系统的标准头文件路径中,一般是在/usr/include里面。
为什么要包含这三个头文件呢?我们就这个具体的例子而言,第一,我们用了库函数printf(),所以我们要包含stdio.h这个头文件,因为函数printf()的声明在stdio.h里面。同理,函数bzero()和函数strlen()的声明分别放在了strings.h和string.h里面,因此它们都需要被包含。关于函数的声明和使用,在后面详细讲解。
3,接下来是一个main函数:
int main(void)
{
.... ....
}
请注意,C程序中,必须包含这么一个东西。这个叫做main函数的东西是整个程序的入口,换句话讲,不管你的这个函数写在哪里,你的程序执行的时候,都是从这个函数开始的,所以它叫主函数。注意这个主函数的书写规范:int main(void) 前面的int表示这个函数的返回值类型是整型,不可写成void也不可不写,有些书籍上面介绍C语言的时候,主函数的返回值类型不是int,那不是因为书写错了,而是因为那些书所介绍的C语言不是LINUX下的C语言,LINUX是遵循GNU-C语法的,因此我们现在学习的其实是GNU-C,所谓的GNU-C其实是一套在标准C语言的基础上带增强功能的C规范,那些增强的功能需要编译器额外的支持,所以我们用的编译器是gcc,在gcc编译器下的主函数返回值类型必须是int类型。
另外,main函数的参数是void,这表示此程序不需要任何命令行参数。main函数的参数还可以写成这样:main(int argc, char **argv) 这个我们留到后面再讲。
在函数体中,首先是定义了一个数组buf,然后用bzero()将它清零,然后用fgets()函数等待用户的输入,并将用户输入的字符串放置到数组buf中,然后用strlen()函数计算用户刚刚输入了几个字符,然后再用printf()将结果打印到屏幕上。
再来观察一下,程序的最后一行是一个return语句:return 0; 首先,这个return关键字有两个作用,第一:出现在普通函数中的时候,代表返回调用者。第二,出现在主函数中的时候,代表退出整个进程。这里是第二种情况。一旦程序执行到这个return语句,我们的这个程序就game over了! 那么后面的那个0是神马呢?可不可以是1呢? 2呢? 答案是这样的:后面的那个数字就是main函数的退出值,这个退出值将会被传递给我们这个进程的“父进程”! 是的,这个进程是有爸爸的,就像每个人都���父母一样。我们的进程在退出的时候将会把自己的情况报告给它的父进程,一般规则是:正常退出返回0,非正常退出返回非0. 我们的进程寿终而寝,属于正常退出,因此返回了一个0,否则如果是碰到了权限不足、内存不够、参数有误等等异常情况,导致程序无法执行下去,这时可以返回一个非0值来告诉它的老爸。
好了,这就是example1.c 你学到了多少呢? 这个程序分析完了,我们想要来运行它,怎么运行呢? 很简单,我们使用一款名为gcc的编译器,来对它进行编译,编译的命令如下:
www.linuxidc.com@ubuntu:~$ gcc example1.c -o example1 -Wall
上面的命令,表示使用gcc编译器,将example1.c 编译生成一个叫 example1 的文件,-Wall的意思是将所有的Warning打开,也就是说如果我们写的代码有任何语法问题,都欢迎gcc帮我们显示出来,我们不会怪罪它啰嗦,因为我们要学习嘛。(有时gcc是很罗嗦的,会爆出很多无关痛痒的警告)
这样,你就拥有了一个可执行文件 example1 了,执行它:
上面的命令,表示使用gcc编译器,将example1.c 编译生成一个叫 example1 的文件,-Wall的意思是将所有的Warning打开,也就是说如果我们写的代码有任何语法问题,都欢迎gcc帮我们显示出来,我们不会怪罪它啰嗦,因为我们要学习嘛。(有时gcc是很罗嗦的,会爆出很多无关痛痒的警告)
这样,你就拥有了一个可执行文件 example1 了,执行它:
www.linuxidc.com@ubuntu:~$ ./example
hello
you have input 5 letters
www.linuxidc.com@ubuntu:~$
你输入了一个字符串 hello,程序帮你计算出来,你刚刚输入了 5 个字符。有趣吧? 如果这是你第一次编写程序,能跟你的程序进行交互将会是一个极好的开端,下一节我们继续征战LINUX下C语言编程。