从这一节开始,我们就进入了《第四章 函数与程序结构》的学习。对于代码的易读性、程序结构的清晰等方面,函数都发挥着重要的作用。它可以把大的计算任务分解成若干个较小的任务,同时还可以做到代码复用,隐藏操作细节,大大降低程序修改的难度。
可以说,C语言程序一般都是由许多小的函数组成,而不是少量庞大的函数组成。
在前面的章节从头学C(8)函数中,我们已经学习了函数的一些基本知识。比如目前C语言允许在声明函数时同时声明参数的类型,这样编译器就有可能检测出声明与定义类型不一致等等错误;如果参数声明得当,程序还可以自动进行强制类型转换。
除了函数和程序结构,本章后续章节还会学习到名字的作用域规则以及预处理的功能,包括条件编译、宏扩展等等。
第四章 函数与程序结构 >> 4.1 函数的基本结构
首先来设计一个程序:给定多行字符串,从里面查找包含特定“模式”或特定“字符串”的行,并将找到的这些行打印出来。
因此,我们可以将程序按如下思路设计:
while(还有未处理的行) if(该行包含指定的字符串) 打印该行
虽然我们可以把所有代码都放到主程序main中,但更合适的做法是将上面三部分都设计成一个独立的函数,这样的程序结构显然更清晰简洁,而且这三个独立的函数还可提供给其他程序进行复用,方便开发其他类似的程序。
“还有未处理的行”可以用函数getline()来实现,这个函数可以从第一章中拿来借鉴。
“该行包含指定的字符串”用函数strindex(s,t)来实现,需要我们自己来编写。该函数返回字符串 t 在字符串 s 中出现的起始位置或索引( index )。当 s 不包含 t 时,程序返回 -1,因此可以用这个值来表示失败的情况。
“打印该行”可以直接用printf()函数实现,这个函数我们前面已经用了很多次了。
有了思路,程序实现就应该是下面这个样子了:
#include <stdio.h> #define MAXLINE 1000 /* maximum input line length */ int my_getline(char line[], int max); int strindex(char source[], char searchfor[]); char pattern[] = "ould"; /* pattern to search for */ /* find all lines matching pattern */ main() { char line[MAXLINE]; int found = 0; while (my_getline(line, MAXLINE) > 0) if (strindex(line, pattern) >= 0) { printf("%s", line); found ++; } return found; } /* my_getline: get line into s, return length */ int my_getline(char s[], int lim) { int c, i; i = 0; while (--lim > 0 && (c=getchar()) != EOF && c != '\n') s[i++] = c; if (c == '\n') s[i++] = c; s[i]= '\0'; return i; } /* strindex: return index of t in s, -1 if none */ int strindex(char s[], char t[]) { int i, j, k; for (i = 0; s[i]!= '\0'; i++) { for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++) ; if (k > 0 && t[k]== '\0') return i; } return -1; }
函数的定义形式:
返回值类型 函数名(参数声明列表) { 声明和语句 }
以上除了函数名,其他部分都可以省略。如果省略了“返回值类型”,则默认返回值类型是 int。
被调用的函数通过 return 语句向调用者返回值,return 后面可以跟任何表达式:
return 表达式;
有几个地方要注意:
- 必要时,表达式会被转换为函数声明的返回值类型。
- 调用函数也可以忽略返回值。
- return 语句中的表达式也可以忽略(如果 return 语句后面没有表达式,函数将不会向调用者返回任何值)。
上面的 main 函数返回了一个状态,即匹配的行数,该返回值可以给调用本程序的环境使用。