演習5-7 K&R プログラミング言語C

演習5-7

読み込んだ各行文字列を保存するのに alloc の代わりに配列を引数として渡す。
lineptr には配列内の各行文字列の先頭になる配列要素のポインタを保存していく。

buf_lines : |h|e|l|l|o|\0|w|o|r|l|d|\0|f|r|o|m| ...
lineptr   :  ^            ^            ^

プログラムの実行速度は、ほとんど変化がわからなかった。

#include <stdio.h>
#include <string.h>
#include <time.h>

#define MAXLINES 5000 /* ソートすべき最大の行数 */
#define MAXLEN 1000 /* 任意の入力行の最大長 */

char *lineptr[MAXLINES]; /* テキスト行へのポインタ */
int my_getline(char*, int);
int readlines(char *lineptr[], int nlines, char *buf_lines);
void writelines(char *lineptr[], int nlines);
void qsort(char *lineptr[], int left, int right);

/* 入力行をソートする */
int main(void)
{
    int nlines; /* 読み込まれた入力行の数 */
    char buf_lines[MAXLINES * MAXLEN]; /* 読み込んだ文字の保存場所 */
    clock_t t1, t2;

    t1 = clock();
    if ((nlines = readlines(lineptr, MAXLINES, buf_lines)) >= 0) {
        qsort(lineptr, 0, nlines - 1);
        writelines(lineptr, nlines);
        t2 = clock();
        printf("%f\n", (double) (t2 - t1) / CLOCKS_PER_SEC);
        return 0;
    } else {
        printf("nlines => %d\n", nlines);
        printf("error: input too big to sort\n");
        return 1;
    }
}

/* readlines : 入力行を読み込む */
int readlines(char *lineptr[], int maxlines, char *buf_lines)
{
    int i, len, nlines;
    char line[MAXLEN];

    i = nlines = 0;
    while ((len = my_getline(line, MAXLEN)) > 0)
        if (nlines >= maxlines)
            return -1;
        else {
            line[len-1] = '\0'; /* 改行を消す */
            strcpy(&buf_lines[i], line);
            lineptr[nlines++] = &buf_lines[i];
            i += len;
        }
    return nlines;
}

/* writelines : 出力行を書き出す */
void writelines(char *lineptr[], int nlines)
{
    int i;

    for (i = 0; i < nlines; i++)
        printf("%s\n", lineptr[i]);
}

int my_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;
}

/* qsort : v[left] ... v[right] を昇順にソートする */
void qsort(char *v[], int left, int right)
{
    int i, last;
    void swap(char *v[], int i, int j);

    if (left >= right)  /* 配列の要素が2より*/
        return;         /* 少ないときは何もしない */
    swap(v, left, (left + right) / 2);
    last = left;
    for (i = left + 1; i <= right; i++)
        if (strcmp(v[i], v[left]) < 0)
            swap(v, ++last, i);
    swap(v, left, last);
    qsort(v, left, last - 1);
    qsort(v, last + 1, right);
}

/* swap : v[i] と v[j] を交換する */
void swap(char *v[], int i, int j)
{
    char *temp;
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}
プログラミング言語C 第2版 ANSI規格準拠
B.W. カーニハン D.M. リッチー
共立出版
売り上げランキング: 9726
コメント

こんにちは、演習問題の解答を探してここにたどりつきました

試してみたのですが、このプログラムはどのように実行したらよいのでしょうか?

一応コンパイルは通し、実行ファイルは生成されたのですが(ただし行MAXLINE5000は多すぎたのかスタックオーバーフローが発生)、入力方法がいまいちわかりません。とりあえず以下の方法で入力したのですが、mainのelseの方に入ってしまいます(実行はDOSプロンプト上)
(実験のためにMAXLINEは5)
1行目:MADOKA(入力後Enter)
2行目:SAYAKA(入力後Enter)
以下5行目まで入力
5行目入力後mainのelseに入ります

多分「入力終了」という判定をどこでもやっていないのが原因だと思うのですが、そのような判定はどこに入れたらよいのでしょうか?

よろしければご回答お願いします

コメント by OROCHI | 2012年9月30日 - 23:20

こんにちは、コメントありがとうございます。
「入力終了」の判定は my_getline 関数の EOF の部分で行ってます。

文字列データは標準入力から読み込むので、以下のようにファイルを読み込んで渡すか(a.out が実行ファイル)、端末上で EOF を入力する(Ctrl-D)するといいです。

$ cat hoge.txt | ./a.out

コメント by iNo | 2012年10月5日 - 11:03
Top