ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

初心者用プログラミング手動検索コミュのテキストファイルを1画面ずつ表示

  • mixiチェック
  • このエントリーをはてなブックマークに追加
どうもです、私もさっそく、質問をしたいと思います。
勉強のやりかたとしては、何か役に立つ大きなプログ
ラムを理解すれば、Cに対しての理解が深まると思い
実行してみました。

・言語名はなにか
 C言語
・何をしたいのか
 テキストファイルを一画面づつ表示
・自分はどこまでしたのか
 本からサンプルを写して実行
 ある程度のソースの解析
・結果どうなっているのか
 実行はできました・・・ソースの詳細を知りたい

出典
作ってわかるCプロミング
日下部陽一

if ((cur = add_line(cur, buf)) == NULL)
add_line()の返り値って、何が返ってくるのですか?
つまりcurには、何が入るのですか?

if (ln > all - n + 1) /*ファイルの行数を超えた
    ln = all - n + 1; 場合は、最後の 23 行を表示する。*/

この部分で真の場合実行するコードの部分は納得いくの
ですが、条件式が納得いきません。
すべての行数からnを引くと最後の23行になるので、それで
良いと思うのですが、条件式の場合は、ファイルの行数を超えて
いませんよね。。。最後の23行の一番先頭を表していませんか?
ということは、ファイルの行数をこえていないようなのですが・・・

     LINE *p;

     p = &list;
     while (start--) /*開始行数分 ノードを進める。*/
       p = p->next;←この部分の処理?
     while (n--) { /*一画面分(23 行)表示する。*/
       fputs(p->buf, stdout);

p = &list;の部分は、先頭の部分を指すようにしてるのですね・・・
それで・・・
while (start--) /*開始行数分 ノードを進める。*/
  p = p->next;←この部分の処理?
上記の部分の動きというのは、どういう仕組みでしょうか?
p = p->next;でnextを、また、pに代入というのは、どういう意味でしょうか?

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

for文の使い方は知っているのですが、この場合ちょっと上級な使い方をしてるみたい
なので難しいですね。cur != &listの部分は、末尾(or先頭)になったら終了ですね。
cur = list.nextは、初期値ですけど、どこの部分を指しているのですか?
cur = del_line(cur)でdel_line()は、何が返ってくるのですか?curを引数にして
さらにcurに返り値を入れていますね、この動作はどうなのかわかりません。

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

上記のLINEとなっているのは、LINEの型の返り値が返ってくるわけですか?

みなさまよろしくお願いします。m(__)m

/*
 * 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; /*key_wait() で押されたキー(文字)。*/
     int all; /*ファイル全体の行数。*/
     LINE *cur; /*読み込んだ行を格納する、ノードへのポインタ。*/
     int ln; /*表示開始行。*/

     cur = &list; /* 読み込んだファイル内容を確保するリストの「先頭」+「末尾」*/
     all = 0;
     while (fgets(buf, LINE_SIZE, fp) != NULL) {
       if ((cur = add_line(cur, buf)) == NULL) { /*ファイルを 1 行ずつリストに追加。*/
          fprintf(stderr, "cant't alloc memory\n");
          delete_all_lines(); /*リストに追加した行の全てを削除(free())。*/
          return (R_QUIT_ALL);   
       }
       ++all;
     }

     ln = 1;
     show_page(ln, n); /*ln 行目から n(23) 行表示。*/
     if (all <= n) { /*全体の行数が、n(23) 以下なら、次のファイルへ。*/
       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: /*1 行進めるから、ln を ++ する。*/
                ++ln;
                if (ln > all - n + 1) /*ファイルの行数を超えた
                  ln = all - n + 1; 場合は、最後の 23 行を表示する。*/
                show_page(ln, n);
                break;
             case R_PAGE_NEXT: /*一画面分(23行)進めるから、ln に 23(n) を足す。*/
                ln += n;
                if (ln > all - n + 1) /*ファイルの行数を超えた
                  ln = all - n + 1; 場合は、最後の 23 行を表示する。*/
                show_page(ln, n);
                break;
             case R_PAGE_PREV: /*一画面分(23行)戻るから、ln に 23(n) を引く。*/
                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--) { /*一画面分(23 行)表示する。*/
       fputs(p->buf, stdout);
       if ((p = p->next) == &list) /*先頭行のノードに来たら break。*/
          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++) /*"--more--" の長さ分消す。*/
        putch('\b'); /*\b はバックスペース。*/
     for (i = 0; i < n; i++) /*"--more--" の長さ分空白を表示。*/
        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);
}

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

LINE list = {&list, &list, NULL}; /* prev / next が自分自身で、内容が 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 *);

コメント(1)

3連休は全く繋いでいなかった塾長です( ̄▽ ̄;)

>if ((cur = add_line(cur, buf)) == NULL)
>add_line()の返り値って、何が返ってくるのですか?
>つまりcurには、何が入るのですか?

LINE構造体風に書くと
{
  一つ前のアドレス
  listのアドレス
  bufの内容のアドレス
}
こんな感じかな


>if (ln > all - n + 1) /*ファイルの行数を超えた
>    ln = all - n + 1; 場合は、最後の 23 行を表示する。*/

このままだとコメントになってしまうので(笑
if (ln > all - n + 1) /*ファイルの行数を超えた */
    ln = all - n + 1; /*場合は、最後の 23 行を表示する。*/
こうだと考えて、これは最後の23行を表示するために先頭を求めているのだから
例えば、全24行だとすると最後の23行は2〜24行までの23行になる。
この先頭の2を越えた場合に2にするという条件であり、式


>while (start--) /*開始行数分 ノードを進める。*/
>  p = p->next;←この部分の処理?
>上記の部分の動きというのは、どういう仕組みでしょうか?
>p = p->next;でnextを、また、pに代入というのは、どういう意味でしょうか?

構造体line_tのnextはline_tで、1行目なら2行目のアドレス、
2行目なら3行目のアドレスが入っているので開始行数分ループ
させて、開始行の値まで進めている。


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

これは書き方を変えると
cur = list.next;
while(cur != &list){
  cur = del_line(cur);
}
こうなるので
list.nextにはファイル読み込み時に1行目が入っているので1行目から。
del_line()は渡された値を削除して、渡された値のnextを返しているので
それが&listと違う間繰り返している。


>LINE *add_line(LINE *, char *);
>LINE *del_line(LINE *);

>上記のLINEとなっているのは、LINEの型の返り値が返ってくるわけですか?

イメージとしてはあってます。
正確にはLINE構造体で確保したメモリ領域の先頭アドレスが返されます。


言葉だけで書いたら、分かるような分からんような書き方になってしまったな・・・

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

初心者用プログラミング手動検索 更新情報

初心者用プログラミング手動検索のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング