C语言圣经K&R笔记 1.9字符数组

1.9 字符数组

C中最常见的数组类型是字符数组。为说明字符数组的用法以及函数如何操作数组,写个程序来读入一些文本行并打印出最长的一行。大纲如下:

        while (有另一行时)
                if (它比之前的最长行要长)
                        保存它
                        保存它的长度
        打印最长的行

这大纲清楚地表明程序要自然地分成哪几部分。一部分用于获取新行,一部分用于比较,一部分用于保存,剩下的部分控制整个过程。

因此我们写个单独的getline函数用来获取新行,并使之可用于其他场景。至少,getline要返回文件结束的信号;更有用的设计是返回行的长度,当文件结束时返回0。0是个可接受的文件结束返回值,因为它不是合法的行长度。每行至少有一个字符,即使时空行也有一个字符,换行符。

找到比之前最长行还要长的行时,我们要把它存下来。第二个函数copy用来保存最长的行。

最后,用main程序来控制getline和copy。结果如下:

注意:getline已经是C标准库函数了(POSIX.1-2008.),如果要在新环境下编译运行代码,要给getline改个名字。

#include <stdio.h>
#define MAX_LINE 1000 /* 最长的输入行长度 */

int getline(char line[], int maxline);
int copy(char to[], char from[]);

/* 打印最长行 */
main()
{
    int len;    /* 当前行的长度 */
    int max;    /* 最长行的长度 */
    char line[MAX_LINE];       /* 当前输入行 */
    char longest[MAX_LINE];    /* 最长输入行存这里 */

    max = 0;
    while ((len = getline(line, MAX_LINE)) > 0)
        if (len > max) {
            max = len;
            copy(longest, line);
        }
    if (max > 0)    /* 如果有输入行的话 */
        printf("%s", longest);
    return 0;
}

/* 把一行读入s,返回长度 */
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;
}

/* 把from拷贝到to,假设长度足够 */
int 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 max)这一行声明,指明其中第一个参数s是个数组,而第二个参数lim是个整数。在声明中提供数组的长度是因为不计较存储。在getline中数组s的长度不是必需的,因为它在main中设置。getline用return将一个值返回给调用者,如power函数一样。该行也声明了getline返回一个int,由于int是默认的返回类型,因此可以省略。

copy函数只是用来做事,并不返回值。copy的返回类型是void,明确指出不会返回值。

函数getline将字符'\0'(空字符, 值为0)放在它创建的数组末尾,来标识字符串的结束。这个约定同样被C语言采用:当一个字符串常量如 "hello\n" 出现在C程序中时,它被作为一个字符数组来存储,其中包含了字符串内的字符,并在结尾用'\0'标识结束。

printf中的%s格式化标志,也期望对应的参数是如上格式的字符串。copy同样依赖”它的输入参数以'\0'结束“的这个事实,它将这个字符串拷贝到输出参数。(上述所有的前提都在于:'\0'不是正常文本的一部分)

值得一提的是,如此小的程序也存在棘手的问题。比如main遇到超过长度限制的行时该怎么做?getline能够安全工作,因它在数组满的时候停止收集,即使这时没遇到换行。main可以通过检查返回的长度以及最后一个字符,来应对这种情况。出于简洁考虑,我们上面代码没有处理这个问题。

getline的使用者没办法事先知道输入行有多长,所以getline要检查溢出。另一方面,copy的使用者已经知道(或者可以得出)字符串有多大,所以我们选择不增加错误校验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值