【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.23068

テキストファイルを1画面ずつ表示 page1.c
投稿者---CENTER(2005/09/14 16:43:42)


次のプログラムでわからない部分があるのでもしよろしければ
ご指導ください。

whileループのうしろにある
    if (i > 0)
       key_wait();
の部分は、ファイル末尾の何行か分(23で割り切れなかった分)の処理です。ファイルの
末尾では23行に満たなくても一旦停止し、それから次のファイルの処理にかからないと
、ファイルの末尾と次のファイルの先頭の1ページがつながってしまう。それを避ける
ための処理です。iが0の場合を除外しているのは、iが0の場合は直前に一旦停止をして
いるはずなので、その後1行も表示しないうちにまた続けて停止しないための作戦です。

上記のように載っていたのですが、どういう意味かつかめません何か具体的に説明して
いただけないでしょうか?もう具体的だと言われればそれまでですが^_^;

/*
 * page1.c - テキストファイルを1画面ずつ表示
 */

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

#define LINE_SIZE (80 + 1 + 1) /* 80 + 改行の分 + '\0'の分 */
#define LINE_PAGE 23           /* 1画面に表示する行数 */

static void paging (FILE *, int);
static void key_wait(void);
static void usage(void);
static void cant(char *);

main(int argc, char **argv)
{
    FILE *fp;
    --argc;
    ++argv;
    if (argc == 0)
       usage();
    else {
       while (argc--) {
               if ((fp = fopen(*argv, "r")) == NULL)
           cant(*argv);
           paging(fp, LINES_PAGE);
           (void)fclose(fp);
           argv++;
       }
        }
    return (0);
}

/*
 * paging() - 1画面ごとに表示して止まり次のキーを待つ
 */
static void paging(FILE *fp, int n)
{
    char buf[LINE_SIZE];
    int i;

    i = 0;
    while (fgets(buf, LINE_SIZE, fp) != NULL) {
        fputs(buf, stdout);
        if (i++ >= n - 1) {
            key_wait();
        i = 0;
        }
    }
    if (i > 0)
       key_wait();
}

/*
 * key_wait() - return キーが押されるまで待つ
 */
static void key_wait(void)
{
    char comline[LINE_SIZE];

    fprintf(stderr, "--Hit Return Key--");
    (void)fgets(comline, LINE_SIZE, stdin);
}

static void usage(void)
{
    fprintf(stderr, "Usage: page1 file [...]\n");
    exit(1);
}

static void cant(char *name)
{
    fprintf(stderr, "cant't open %s\n", name);
    exit(1);
}

次のプログラムもわからない部分があるのでご指導ください。
わからないのは、paging()関数の中身です。
細かい動きを教えていただけないでしょうか・・・
とりあえず→で示しておきます。



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> テキストファイルを1画面ずつ表示 page2.c 23070 CENTER 2005/09/14 16:47:56
<子記事> Re:テキストファイルを1画面ずつ表示 page1.c 23091 KING・王 2005/09/14 20:55:39
<子記事> Re:テキストファイルを1画面ずつ表示 page1.c 23100 まきじ 2005/09/15 00:46:58


No.23070

テキストファイルを1画面ずつ表示 page2.c
投稿者---CENTER(2005/09/14 16:47:56)


次のプログラムもわからない部分があるのでご指導ください。
わからないのは、paging()関数の中身です。
細かい動きを教えていただけないでしょうか・・・
とりあえず→で示しておきます。

/*
 * page2.c - テキストファイルを1画面ずつ表示
 */

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

#define LINE_SIZE   (80 + 1 + 1) /* 80 + 改行の分 + '\0'の分 */
#define LINE_PAGE   23           /* 1画面に表示する行数 */
#define R_QUIT_ALL  0       /* すべて終了 */
#define R_PAGE_NEXT 1       /* 次のpageへ */
#define R_FILE_NEXT 2       /* 次のfileへ */

static void paging (FILE *, int);
static void key_wait(void);
static void usage(void);
static void cant(char *);

main(int argc, char **argv)
{
    FILE *fp;
    int r;

    --argc;
    ++argv;
    if (argc == 0)
       usage();
    else {
       while (argc--) {
               if ((fp = fopen(*argv, "r")) == NULL)
           cant(*argv);
           r = paging(fp, LINES_PAGE);
           (void)fclose(fp);
           if (r == R_QUIT_ALL)
                  break;
           argv++;
       }
        }
    return (0);
}

/*
 * paging() - 1画面ごとに表示して止まり次のキーを待つ
 */
static void paging(FILE *fp, int n)
{
    char buf[LINE_SIZE];
    int r;
    int i;

    i = 0;
    while (fgets(buf, LINE_SIZE, fp) != NULL) {
        fputs(buf, stdout);
        if (i++ >= n - 1) { ← この部分はどういう意味でしょうか?
            if ((r = key_wait()) != R_PAGE_NEXT) ← ifのreturnも含めた意味?
           return (r);
        i = 0;
        }
    }
    if (i > 0) { ← この部分のifの意味?
       if ((r = key_wait()) != R_PAGE_NEXT) ← この部分の意味?
          return (r);
    }
    return (R_FILE_NEXT); ← とりあえずpaging()全体的の動き?
}

#if HAVE_GETCH
/*
 * key_wait() - キーが押されるのを待つ(getch版)
 */
static void key_wait(void)
{
    int c;

    fprintf(stderr, "--more--", stderr);
    while((c = getch()) != 'q' && c != ' ' && c != 'n')
        ;
    if (c == 'q')
        return (R_QUIT_ALL);
    else if (c == 'n')
        return (R_FILE_NEXT);
    else
        return (R_PAGE_NEXT);
}
#else
/*
 * key_wait() - キーが押されるのを待つ(fgets版)
 */
static void key_wait(void)
{
    char comline[LINE_SIZE];

    fprintf(stderr, "--Hit Return Key--", stderr);
    (void)fgets(comline, LINE_SIZE, stdin);
    if (comline[0] == 'q')
        return (R_QUIT_ALL);
    else if (comline[0] == 'n')
        return (R_FILE_NEXT);
    else
        return (R_PAGE_NEXT);
}
#endif

static void usage(void)
{
    fprintf(stderr, "Usage: page2 file [...]\n");
    exit(1);
}

static void cant(char *name)
{
    fprintf(stderr, "cant't open %s\n", name);
    exit(1);
}



この投稿にコメントする

削除パスワード

No.23072

テキストファイルを1画面ずつ表示 page3.c
投稿者---CENTER(2005/09/14 16:52:12)


このプログラムについては、かなり大きなプログラムなのでわからない
部分があります。わからない部分が、←で示しています。

/*
 * page3.c - テキストファイルを1画面ずつ表示
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "line.h"

#define LINE_SIZE   (80 + 1 + 1) /* 80 + 改行の分 + '\0'の分 */
#define LINE_PAGE   23           /* 1画面の行数 */
#define R_QUIT_ALL  0       /* すべて終了 */
#define R_LINE_NEXT 1       /* 次のlineへ */
#define R_FILE_PREV 2       /* 前のlineへ */
#define R_PAGE_NEXT 3            /* 次のpageへ */
#define R_PAGE_PREV 4       /* 前のpageへ */
#define R_FILE_NEXT 5       /* 次のfileへ */
#define R_FILE_PREV 6       /* 前のfileへ */

extern LINE list;

static void paging (FILE *fp, int n);
static void show_page(int, int);
static void key_wait(void);
#if HAVE_GETCH
static void prompt(char *str);
static void noprompt(char *str);
#endif
static void usage(void);
static void cant(char *);

main(int argc, char **argv)
{
    FILE *fp;
    int r;

    --argc;
    ++argv;
    if (argc == 0)
       usage();
    else {
       while (argc--) {
               if ((fp = fopen(*argv, "r")) == NULL)
           cant(*argv);
           r = paging(fp, LINES_PAGE);
           (void)fclose(fp);
           if (r == R_QUIT_ALL)
                  break;
           argv++;
       }
        }
    return (0);
}

/*
 * paging() - 1画面ごとに表示して止まり次のキーを待つ
 */
static void paging(FILE *fp, int n)
{
    char buf[LINE_SIZE];
    int c; ← この変数はなんのためにありますか
    int all; ← この変数はなんのためにありますか
    LINE *cur; ← この変数はなんのためにありますか
    int ln; ← この変数はなんのためにありますか

        cur = &list; ← これは、どういう操作ですか 
    all = 0;
    while (fgets(buf, LINE_SIZE, fp) != NULL) {
        if ((cur = add_line(cur, buf)) == NULL) { ← この操作は何ですか?
            fprintf(stderr, "cant't alloc memory\n");
        delete_all_lines(); ← この関数はかなりの部分で使われていますが
                return (R_QUIT_ALL);   何ですか?
        }
        ++all; ← この処理は?
    }

    ln = 1; ← この処理は?
    show_page(ln, n); ← この処理は?
    if (all <= n) { ← この処理は?
       delete_all_lines();
       return (R_FILE_NEXT);
    }
    else {
       while ((c = key_wait()) != R_QUIT_ALL) {
                  switch (c) {
              case R_FILE_NEXT:
              delete_all_lines();
              return (R_FILE_NEXT);
              case R_LINE_NEXT: ← このケースの全体の処理
                  ++ln;
              if (ln > all - n + 1)
                  ln = all - n + 1;
              show_page(ln, n);
              break;
              case R_PAGE_NEXT: ← このケースの全体の処理
              ln += n;
              if (ln > all - n + 1)
                  ln = all - n + 1;
              show_page(ln, n);
              break;
              case R_PAGE_PREV: ← このケースの全体の処理
              ln -= n;
              if (ln <= 0)
                  ln = 1;
              show_page(ln, n);
              break;
              }
       }
    }
    delete_all_lines();
    return (R_QUIT_ALL);                        
}

/*
 * show_page() - 1画面分の表示
 */
static void show_page(int start, int n)
{
    LINE *p;

    p = &list; ← この操作は?
    while (start--) ← この処理は?
        p = p->next; ← この操作は?
    while (n--) { ← この操作は?
        fputs(p->buf, stdout); ← この操作は?
        if ((p = p->next) == &list) ← この操作は?
        break;
    }
}   

#if HAVE_GETCH
/*
 * key_wait() - キーが押されるまで待つ(getch() 版)
 */
static void key_wait(void)
{
    prompt("--more--"); ← この関数の処理は?
    for (;;) {  /* 無条件に(常に)ループ */
        switch (getch()) {
        case 'q';
            noprompt("--more--"); ← この関数の処理は?
            return (R_QUIT_ALL);
        case 'n';
            noprompt("--more--");
            return (R_FILE_NEXT);
            case ' ';
            noprompt("--more--");
            return (R_PAGE_NEXT);
        case '\b'; /* Back Space */
        case 'b';
            noprompt("--more--");
            return (R_PAGE_PREV);
            case '\r';
            noprompt("--more--");
            return (R_LINE_NEXT);
        }
        }         
}
#else
/*
 * key_wait() - return キーが押されるまで待つ
 */
static int key_wait(void)
{
    char comline[LINE_SIZE];

    fprintf(stderr, "--Hit Return Key--", stderr);
    (void)fgets(comline, LINE_SIZE, stdin);
    if (comline[0] == 'q')
        return (R_QUIT_ALL);
    else if (comline[0] == 'n')
        return (R_FILE_NEXT);
    else if (comline[0] == 'b')
        return (R_PAGE_PREV);
    else
        return (R_PAGE_NEXT);
}
#endif

#if HAVE_GETCH
static void prompt(char *str)
{
    cprintf("%s", str); ← この関数の処理は?
}
#endif

#if HAVE_GETCH
static void noprompt(char *str)
{
    int n;
    int i;

    n = strlen(str);
    for (i = 0; i < n; i++) ← この処理は?
         putch('\b');
    for (i = 0; i < n; i++) ← この処理は?
         putch(' ');
    for (i = 0; i < n; i++) ← この処理は?
         putch('\b');
}
#endif

static void usage(void)
{
    fprintf(stderr, "Usage: page3 file [...]\n");
    exit(1);
}

static void cant(char *name)
{
    fprintf(stderr, "cant't open %s\n", name);
    exit(1);
}



この投稿にコメントする

削除パスワード

No.23073

テキストファイルを1画面ずつ表示 page3.c その2
投稿者---CENTER(2005/09/14 16:53:39)


/*
 * list.c - リスト構造操作用の関数群
 */
#include <stdio.h>
#include <stdlib.h>
#include "line.h"

LINE list = {&list, &list, NULL}; ← この部分の意味は?

#if MSC
#include <string.h>
#else
char *strdup(char *);
#endif

/* リスト構造に1行分のデータを追加 */
LINE *add_line(LINE *c, char *buf)
{
    LINE *np; ← この変数は?

    if ((np = (LINE *)malloc(sizeof(LINE))) == NULL) ← この処理は?
        return (NULL);
    if ((np->buf = strdup(buf)) == NULL) { ← この処理は?
        free(np);
        return (NULL);
    }
    np->prev = c; ← ここから
    np->next = c->next;
    c->next->prev = np;
    c->next = np;
    return (np); ← ここまでの操作の意味は?
}

/* 各行用に確保したメモリーをすべて解放 */
void delete_all_lines(void)
{
    LINE *cur;

    for (cur = list.next; cur != &list; cur = del_line(cur)) ← ここの処理は?
        ;
}

/* リスト構造から1行分のデータを削除 */
LINE *del_line(LINE *c) ← この操作の細かい説明
{
    LINE *p;

    p = c->next;
    c->next->prev = c->prev;
    c->prev->next = c->next;
    free(c->buf);
    free(c);
    return (p);
}

/*
 * line.h - リスト構造用の定義
 */
typedef struct line_t {
    struct line_t *prev; /* 前のノードへのポインター */
    struct line_t *next; /* 後のノードへのポインター */
    char *buf;           /* その行のデータ */    
} LINE;

void delete_all_lines(void);
LINE *add_line(LINE *, char *);
LINE *del_line(LINE *);



この投稿にコメントする

削除パスワード

No.23076

Re:テキストファイルを1画面ずつ表示 page3.c その2
投稿者---shu(2005/09/14 17:08:28)


量が多過ぎる。


この投稿にコメントする

削除パスワード

No.23093

Re:テキストファイルを1画面ずつ表示 page2.c
投稿者---KING・王(2005/09/14 22:07:38)


簡単にしか見ていませんが、page1.cのkey_wait()での入力待ちの部分に関して、
qの場合、処理を終了し、nなら次のファイルに処理にかかる、
それ以外なら次のページを表示するという風に改造したものです。

というか、まずpage1.cを理解しましょう。
それが理解できれば、その理解をもとにpage2.cを見ると、
自力で理解できるかもしれません。
page1.cが理解できていな状態では、page2.cの理解は不可能です。
でもって、おそらくそれ以降も、順番に機能追加・改造をしたものだと思いますので、
一歩ずつ確実に理解していきましょう。

あと・・・実際にデバッガなどでステップ実行でもしながら、動作を確認してみると、
その動きを理解する助けになるかもしれません。


この投稿にコメントする

削除パスワード

No.23091

Re:テキストファイルを1画面ずつ表示 page1.c
投稿者---KING・王(2005/09/14 20:55:39)



基本的に、記述されている通りなのですが・・・

    // iの値を0で初期化
    i = 0;

    // (1) ファイルから1行データを読み込む
    while (fgets(buf, LINE_SIZE, fp) != NULL) {

        // (2) 読み込んだデータを標準出力に出力
        fputs(buf, stdout);

        // (3) iの値をインクリメントする
    // iの値が一定値以上ならkey_wait()で、キー入力を待つ。
        // その後iの値を0に戻す。
        if (i++ >= n - 1) {
            key_wait();
        // (4) iの値を0に戻す
        i = 0;
        }
    }

   // (5) iが0で無い場合key_wait()で入力をまつ。    
   if (i > 0)
       key_wait();



(3)のところで、提示されたプログラムの場合n=23となり、iは0からカウントされているので、
(3)のif文のところで23回に1回key_wait()が呼ばれます。
ということで、23行表示ごとに、key_wait()が呼ばれるということです。
で、ファイルの行が23行の倍数の仮に46行だった場合、
46行目を読み込んだときに、(3)のif文の中が実行されて、
(4)のところで、iの値が0に戻されます。
そして、(1)のところにループし、末尾行まで読み込み済みなため、
whileループを抜け、次に(5)のif文の処理にかかり、
i=0なのでkey_wait()は実行されません。

しかし、23行の倍数でない仮に47行だった場合、
46行目を読み込んだときに、(3)のif文の中が時刻されて、
(4)のところで、iの値が0に戻されます。
そして、(1)のところにループし、47行目を読み込みます。
それから、(3)if文のとろを通り、iがインクリメントされてi=1となります。
また、(1)のところにループし、今度は末尾行まで読み込み済みなため、
whileループを抜け、次の(5)のif文の処理にかかります。
このとき、i=1なので、key_wait()が実行されます。

#すいません。(3)のところのインクリメントの順番が比較の前か後か記憶があやふやです。
#間違っているようならフォローをよろしくお願いします


この投稿にコメントする

削除パスワード

No.23100

Re:テキストファイルを1画面ずつ表示 page1.c
投稿者---まきじ(2005/09/15 00:46:58)


>if (i++ >= n - 1) { ← この部分はどういう意味でしょうか?

ファイルから一画面の行数を読み込んだか否か

>if ((r = key_wait()) != R_PAGE_NEXT) ← ifのreturnも含めた意味?
>return (r);

key_wait() で q か n が押されたら、return(r)。

>if (i > 0) { ← この部分のifの意味?

23068 で説明されている
「iが0の場合は直前に一旦停止をしているはずなので、
その後1行も表示しないうちにまた続けて停止しないため」
の事です。

つまり、ファイルの行数が、23 の倍数の行数とは限らないので
最後だけ、10 行という事も考えられるので、その時にキー入力を促す為。

>if ((r = key_wait()) != R_PAGE_NEXT) ← この部分の意味?
>return (r);

key_wait() で q か n が押されたら、return(r)。

>int c; ← この変数はなんのためにありますか

key_wait() で押されたキー(文字)。

>int all; ← この変数はなんのためにありますか

ファイル全体の行数。

>LINE *cur; ← この変数はなんのためにありますか

読み込んだ行を格納する、ノードへのポインタ。

>int ln; ← この変数はなんのためにありますか

表示開始行。

>if ((cur = add_line(cur, buf)) == NULL) { ← この操作は何ですか?

ファイルを 1 行ずつリストに追加。

>delete_all_lines(); ← この関数はかなりの部分で使われていますが

リストに追加した行の全てを削除(free())。

>show_page(ln, n); ← この処理は?

ln 行目から n(23) 行表示。

>if (all <= n) { ← この処理は?

全体の行数が、n(23) 以下なら、次のファイルへ。

>case R_LINE_NEXT: ← このケースの全体の処理

1 行進めるから、ln を ++ する。

>case R_PAGE_NEXT: ← このケースの全体の処理

一画面分(23行)進めるから、ln に 23(n) を足す。

>case R_PAGE_PREV: ← このケースの全体の処理

一画面分(23行)戻るから、ln に 23(n) を引く。

>if (ln > all - n + 1) ln = all - n + 1;

ファイルの行数を超えた場合は、最後の 23 行を表示する。

> if (ln <= 0) ln = 1;

ファイルの先頭行より前に戻ろうとした場合、1 行目を表示する。

>while (start--) ← この処理は?
>p = p->next; ← この操作は?

開始行数分 ノードを進める。

>while (n--) { ← この操作は?
>fputs(p->buf, stdout); ← この操作は?
一画面分(23 行)表示する。

>if ((p = p->next) == &list) ← この操作は?
>break;

先頭行のノードに来たら break。

>for (i = 0; i < n; i++) ← この処理は?
>putch('\b');

"--more--" の長さ分消す。
\b はバックスペース。

>for (i = 0; i < n; i++) ← この処理は?
>putch(' ');

"--more--" の長さ分空白を表示。

# これ一回きりです。
# このレスに対しての質問は、私は回答しない可能性がありますのであしからず。

# 説明が間違ってる所もあるかもしれませんが・・・


この投稿にコメントする

削除パスワード

No.23101

まきじ様、shu様、KING/王様 ありがとうございました。
投稿者---CENTER(2005/09/15 11:46:03)


まきじ様、shu様、KING/王様 ありがとうございました。

お忙しい中、お答えいただきありがとうございます。

># これ一回きりです。
># このレスに対しての質問は、私は回答しない可能性がありますのであしからず。
>
># 説明が間違ってる所もあるかもしれませんが・・・

了解です。

長々とすいませんでしたm(__)m





この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧