1.9 字符数组
字符数组是C中最常见的数组类型。下面编程说明字符数组及操作字符数组的函数的用法。该程序读入一组文本行,并打印最长文本行。算法框架:
while(还有未处理的行)
if (该行比已处理的最长行还长)
保存该行为最长行
保存该行长度
打印最长行
由上可知,程序分若干段,分别读入新行、测试读入的行、保存该行,其余部分则控制这一过程。
因该划分方式较合理,可按此编程。先编个独立函数 getline读取输入的下一行。尽量保持该函数在其他场合也可用。至少,getline函数必须在读到文本末尾时返回一个信号;甚至它能在读入文本行时返回该行长度,或在遇到文本结束符时返回0。由于0不是有效的行长度,因此可作为标志文件结束的返回值。每行至少包括一个字符;即使是只包含换行符的行,其长度为1。
当某个新读入的行比之前读入的最长行还长时,该行需被保存起来。即,需第二个函数,copy函数,把新行复制到一个安全位置。
最后,需要一个main主程序来控制getline和copy函数。编程:
#include <stdio.h>
#define MAXLINE 1000 /* Maximum input line length.*/
int getline(char line[], int maxline);
void copy (char to[], char from[]);
/* Print the longest input line.*/
int main()
{
int len; /* [Current line] Length.*/
int max; /* Maximum length [seen so far]. */
char line[MAXLINE]; /* Current input*/
char longest[MAXLINE]; /* Longest line saved here.*/
max = 0;
while ((len = getline(line, MAXLINE))>0)
if (len > max)
{
max = len;
copy (longest, line);
}
if (max > 0) /* There was a line.*/
printf("%s, longest");
return 0;
}
/*getline: Read a line into s, Return length.*/
int getline(char s[], int lim)
{
int c, i;
for ( i = 0; i < lim-1&(c = getchar()) != EOF &c!='\n'; ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i ;
}
/*copy: Copy 'from' into 'to'; Assume to is big enough.*/
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] =from[i]) != '\0')
{
++i;
}
}
在程序的开始声明了getline和copy函数,假定它们放在同一文件中。
main与getline函数之间通过一对参数及一个返回值交换数据。getline函数两个参数通过程序行
int getline(char s[], int lim)
声明:参数1—— s 声明为数组,参数2—— lim 声明为整型,声明中提供数组大小的目的是留出存储空间。在 getline 函数没指明数组 s 的长度是因为该数组大小是main函数设置的。同power函数,getline函数用一个return语句将值返回给其调用者。上述程序行也声明了 getline 函数的返回值类型为int。因函数默认返回值是int,所以int在此可省略。
有些函数返回有用的值,而有些函数(如copy)仅用于执行一些动作,并不返回值。copy函数返回值类型为void,它显式说明:该函数不返回任何值。
getline函数把字符'\0'(即空字符,其值0)插入到它创建的数组的末尾,以标记字符串的结束。这约定已被C语言采用:C语言中出现类似于
"hello\0"
的字符常量时,它将以字符数组形式存储,数组的各元素分别存储字符串的各个字符,并以'\0'标志字符串的结束。
h | e | l | l | o | \n | \0 |
printf函数中的规范格式——%s规定:对应的参数必须是以这种形式表示的字符串。copy函数实现正是依赖于输入参数由'\0'结束这一事实,它将'\0'拷贝到输出参数中。(即,空字符'\0'不是普通文本的一部分。)
值得一提,即使是上述这样小的程序,在传递参数时也会遇到一些麻烦的设计问题。如,当读入的行长度大于允许的最大值时,main函数该如何处理?getline函数的执行是安全的,无论是否达到换行符字符,当数组满时它将停止读字符。main函数可通过测试行的长度以及检查返回的最后一个字符来判定当前行是否太长,再根据具体的情况处理。为简化程序,在此不考虑该问题。
调用getline函数的程序无法预知输入行的长度,因此getline函数需检查是否溢出。另一方面,调用copy函数的程序知道(或能找出)字符串的长度,在此选择不对该函数增加错误检查。
练习1-16 修改打印最长文本行的程序的主程序main,使之可打印任意长度的输入行的长度,并尽可能多地打印文本。
练习1-17 编程,打印长度大于80个字符的所有输入行。
练习1-18 编程,删除每个输入行末尾的空格及制表符,并删除完全是空格的行。
练习1-19 编写函数reverse(s),将字符串 s 中的字符顺序颠倒过来。用该函数编写一个程序,每次颠倒一个输入行中的字符顺序。