K&Rを読もう(9) 1.9 文字配列

C言語で凶悪なのが、文字配列。というか、文字列自体あんまり得意じゃない。今回は、配列で行の取得。スクリプト言語に慣れてると固定長配列は凄くキツイ。

テキストファイルについての考察。


行はは文字の連続と改行で表されて、
ファイルは行の連続と、EOFで構成されている。


と、再帰的なんだけど納得がいかない。

K&Rの1.9をちょっとわかりやすくしてみた。一番長い行を表示する。

#include <stdio.h>
#include <stdlib.h>

#define MAX_LENGTH 1024

int  getline(char s[], int limit);
void copy(char to[], char from[]);

int main(void)
{
    int  len;
    int  max = 0;
    char line[MAX_LENGTH];
    char longest[MAX_LENGTH];

        
    while ((len = getline(line, MAX_LENGTH)) > 0) {
        if (len > max) {
            max = len;
            copy(longest, line);
        }
    }
    if (max > 0)
        printf("%s", longest);

    exit(EXIT_SUCCESS);
}

int getline(char s[], int limit)
{
    int i, c;
    for (i = 0; i < limit - 1; ++i) {
        c = getchar();
        if (c == EOF)
            break;

        s[i] = c;

        if (c == '\n') {
            ++i; // pushしたのに足されてない。
            break;
        }
    }

    s[i] = '\0';
    return i;
}

void copy(char to[], char from[])
{
    int i;
    for (i = 0;(to[i] = from[i]) != '\0'; i++)
        ;
}

getlineをもっとシンプルに出来ないのかなぁ・・・と悩んだが、あまり良い案が思い当たらず。

あっ

ちょっと眺めてたら気づいた。

EOFの位置だ。改行の前にEOFがある場合があるので、うまく再帰で表せない。

行はは文字の連続と改行で表されて、
ファイルは行の連続と、EOFで構成されている。

という僕の考察では、全然足りない。どこにEOFが発生してもおかしくない。

つまり、EOFを最初に見る必要があるので、改行の処理が面倒になる。

EOFを先に見るなんて当たり前の事だと思ってたけど、かなり面倒な処理が必要なんだと気づいた。文字列の難しさの一端がわかった気がする。

ファイルの最後には改行を入れようと思った。

修正

おぉ、コレダ

int getline(char s[], int limit)
{
    int c;
    int i = 0;
    for (;;) {
        c = getchar();
        if (c == EOF)
            break;

        if (i < limit - 1)
            s[i++] = c; // push
        else
            break;

        if (c == '\n')
            break;
    }

    s[i] = '\0';
    return i;
}

インクリメントの位置を直してスッキリした。


ファイルは文字の連続とEOFで表される。
行は文字長に制限がある。
行は文字の連続と改行で表される。


と、解釈を変えた。

これなら改行にCRLFが来ても柔軟に対応出来る。

修正2

もうちょっと修正。

int getline(char s[], int limit)
{
    int c;
    int i = 0;
    while ((c = getchar()) != EOF) {
        if (i < limit - 1) /* push */
            s[i++] = c;
        else
            break;

        if (c == '\n')
            break;
    }
    s[i] = '\0';
    return i;
}

今までと変わらないじゃん!!