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

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

 詳しくはこちら


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

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


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

No.22484

テキストの中央揃え
投稿者---CENTER(2005/08/06 19:11:54)


ある本で、文章を中央に揃えるプログラムがありました。
そのプログラムでわからない部分があるのでご指導ください。

原理・・・
80文字分の場所に10文字の文字列を真ん中に持ってくるたまえには、
80-10=70の空白のうち半分の35文字分の空白を文字列の前に付け足
せがよい。

質問は←でソースに書いてあります。

ご指導よろしくお願いします。

/*
 *ce1.c
 */
#include <stdio.h>
#include <string.h>

#define MAX_SIZE (80 + 1 + 1) /* +改行 +'\0' */ ← この部分の意味がわかりません
#define WIDTH     80          /*そろえる最大幅*/

void center(char [], int);
void carte(FILE *);
void cant(char *);

main(int argc, char **argv)
{
    FILE *fp;
    --argc;
    ++argv;
    if (argc == 0)
        carte(stdin);
    else {
        while (argc--) {
        if ((fp = fopen(*argv,"r")) == NULL)
            cant(*argv); /*no return */
        carte(fp);
        fclose(fp);
        argv++;
        }
    }
    return (0);
}

void carte(FILE *fp)
{
    char buf[MAX_SIZE];

    while (fgets(buf, MAX_SIZE, fp) != NULL) {
        center(buf, WIDTH);
        fputs(buf,stdout);
    }
}

/*
 * center() - 前にいくつか空白をいれることによって中央にそろえる
 *    buf - 格納領域 (in/out) 
 *    w - 最大幅   
 */        

void center(char buf[], int w)
{
    int off;
    int n;
    int i;

    n = strlen(buf) - 1; /*-1 for '\n'*/ ←-1は\nを取り除く意味ですか?
    if (w < n) ← この部分は何をやっているのですか?
        return;
    off = (w - n + 1) / 2; /*前に入れるべき空白の数*/ ← +1は、何を取り除く?

    /*まず後ろにずらしてから*/  ← この部分の処理をわかりやすく説明してほしい
    for (i = n + 1; i >= 0; i--) ← 難しいです。
        buf[i + off] = buf[i];

    /*前に空白を入れる*/
    while (off--)
        buf[off] = ' ';
}

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

あそれでこの本に載っていたことで別のことを聞きます。
#define iskanji(c) (0x81 <= ((c) & 0xff) && ((c) & 0xff) <= 0x9f ||
                    0xe0 <= ((c) & 0xff) && ((c) & 0xff) <= 0xfc)


EUCコード
#define iskanji(c) (0xa1 <= ((c) & 0xff) && ((c) &0xff) <= 0xfe)

と上記のように書いてあり iskanji(c)のようにプログラム中で使用していた
のですが、このような使い方は、あるのですか?
それと、なぜ、上記のようになったか知りたいのですがわかる方いませんか?
上記のことは、話題の中心でなくていいです。中心はプログラムについてで
よいです。

ご指導お願いします。



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:テキストの中央揃え 22485 まきじ 2005/08/06 20:26:40
<子記事> Re:テキストの中央揃え 22490 かずま 2005/08/07 01:22:21


No.22485

Re:テキストの中央揃え
投稿者---まきじ(2005/08/06 20:26:40)


>#define MAX_SIZE (80 + 1 + 1) /* +改行 +'\0' */ ← この部分の意味がわかりません

改行 と \0 合わせて最大 82 文字。

>n = strlen(buf) - 1; /*-1 for '\n'*/ ←-1は\nを取り除く意味ですか?

そうです。
他を見ると、n + 1 としてるので意味がないと思います。

>if (w < n) return; ← この部分は何をやっているのですか?

1 行の長さが 80 文字以下か否か?

>off = (w - n + 1) / 2; ← +1は、何を取り除く?

\n の分を + 1。

>この部分の処理をわかりやすく説明してほしい
>for (i = n + 1; i >= 0; i--) buf[i + off] = buf[i]; ← 難しいで
す。

行の i 番目の文字を、後ろに off 文字ずらす。
off は、行の先頭に入れる空白の数。


>#define iskanji(c) (0x81 <= ((c) & 0xff) && ((c) & 0xff) <= 0x9f ||
0xe0 <= ((c) & 0xff) && ((c) & 0xff) <= 0xfc)

Shift-JIS コードの漢字は、上位ビットが、0x81 から 0x9f あるいは
0xE0 から 0xFC の範囲と決まっています。
上位ビットだけで、漢字か 1 バイト文字かを区別できる為、
この様なプログラムになってます。
# c と 0xff との & をとる意図については、よく解りません。

>#define iskanji(c) (0xa1 <= ((c) & 0xff) && ((c) &0xff) <= 0xfe)

EUC コードも同様に、漢字のコード範囲(0xA1 から 0xFE)が決まっています。


この投稿にコメントする

削除パスワード

No.22486

もう少しお願いします。
投稿者---CENTER(2005/08/06 23:32:40)


まきじ 様

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

>>この部分の処理をわかりやすく説明してほしい
>>for (i = n + 1; i >= 0; i--) buf[i + off] = buf[i]; ← 難しいで
>す。
>
>行の i 番目の文字を、後ろに off 文字ずらす。
>off は、行の先頭に入れる空白の数。

i = n + 1でiの値は、幅ができますよね・・・
ズレちゃうような気がするのですが・・・

buf[i + off] = buf[i]; は、普通に考えれば
offすらした所に、buf[i]を貼り付けるのですが
i = n + 1があるので難しくなってます。
もう少し、解説いただけないでしょうか?
すいませんm(__)m

>>#define iskanji(c) (0xa1 <= ((c) & 0xff) && ((c) &0xff) <= 0xfe)

上記のような宣言の仕方で関数というのは、つかえるのでしょうか?
はじめてみました。

ご指導ください。



この投稿にコメントする

削除パスワード

No.22487

Re:もう少しお願いします。
投稿者---まきじ(2005/08/06 23:51:46)


>i = n + 1でiの値は、幅ができますよね・・・
>ズレちゃうような気がするのですが・・・

n = strlen(buf) - 1 で n は 改行の分を -1 してます。
よって、buf[n] は、配列の添え字は 0 からなので、\0 の
一文字前を参照することになります。
文字列の終端は、\0 なので、 \0 もずらす為に n + 1 となります。

>上記のような宣言の仕方で関数というのは、つかえるのでしょうか?

関数ではないです。マクロと呼びます。


この投稿にコメントする

削除パスワード

No.22494

もう一度お願いします。
投稿者---CENTER(2005/08/07 03:19:22)


ご指導お願いします。

まきじ 様

本当にすいません。

なんだかもう少しまとめてみましょう・・・
整理しますね・・・
    
>n = strlen(buf) - 1; /*-1 for '\n'*/ ← -1は\nを取り除く意味ですか?

上記でまず、文字列の長さを求めてますね・・・
nには、文字列の長さが入っています・・・

>n = strlen(buf) - 1 で n は 改行の分を -1 してます。

これは改行を除外と・・・

>よって、buf[n] は、配列の添え字は 0 からなので、\0 の
>一文字前を参照することになります。

もしかしてこれって後ろから参照していますか?
 0 1 2 3 4 5 6 7 8   9←添え字 
[][][][][][][][][][\0]

>文字列の終端は、\0 なので、 \0 もずらす為に n + 1 となります。

for文では、i = n + 1と初期化されてますから仮に9とすると
後ろを指していますよね・・・
\0を指しているので、n + 1とすると範囲外を指しませんか?

>for (i = n + 1; i >= 0; i--) 
>   buf[i + off] = buf[i]; ← 難しいです。
>行の i 番目の文字を、後ろに off 文字ずらす。
>off は、行の先頭に入れる空白の数。

それで後ろからコピーするとか・・・

すいません私何か混乱してますかね?

ご指摘お願いします



この投稿にコメントする

削除パスワード

No.22497

Re:もう一度お願いします。
投稿者---まきじ(2005/08/07 12:32:21)


>n = strlen(buf) - 1;
>上記でまず、文字列の長さを求めてますね・・・
>nには、文字列の長さが入っています・・・

仮に buf が"abcdefg\n\0" だとしたら strlen() は (n =)8 です。

buf[n] は \0 です。
buf[n - 1] は、\n です。

>もしかしてこれって後ろから参照していますか?

そうです。

>\0を指しているので、n + 1とすると範囲外を指しませんか?

-1 してるの \n を指してます。
よって、+1 をすれば、\0 を指します。


この投稿にコメントする

削除パスワード

No.22500

ありがとうございました
投稿者---CENTER(2005/08/07 14:09:04)


まきじ 様

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

何かあちこちで+1したり-1したりしていて混乱して
しまいました。

>仮に buf が"abcdefg\n\0" だとしたら strlen() は (n =)8 です。
>
>buf[n] は \0 です。
>buf[n - 1] は、\n です。

それに後ろからとうのがわかりにくかったです。

ようやくわかりましたよ・・・

ありがとうございました





この投稿にコメントする

削除パスワード

No.22490

Re:テキストの中央揃え
投稿者---かずま(2005/08/07 01:22:21)


> ある本で、文章を中央に揃えるプログラムがありました。
> そのプログラムでわからない部分があるのでご指導ください。
その本は、「作ってわかるCプログラミング」ですね。
はっきり言って、この本は入門書としては失格です。
アマゾンのカスターレビューで、☆一つの人の書いているとおりです。

関数形式マクロの説明なしに、#define iskanji(c) ...  なんて平気で書いて
います。

main(int argc, char *argv[]) の形で argc と argv の説明をしておきなが
ら、その後のプログラム例では、いつのまにか main(int argc, char **argv)
に変っています。

関数の定義で、その関数が返す型を書かず、勝手に int や void として
コードを書いています。

ポインタの説明や for文の説明にもおかしな記述があります。


>   n = strlen(buf) - 1; /*-1 for '\n'*/ ←-1は\nを取り除く意味ですか?

その後のページにある改良プログラムでは、

    n = strlen(buf) + 1;

となっていますが、それは間違い。

実は、もっとひどいことがあるのですが、あまり他人の本の悪口をいうのも
気持ちのいいものではないので、これぐらいでやめておきます。



この投稿にコメントする

削除パスワード

No.22493

関数形式マクロについて
投稿者---CENTER(2005/08/07 02:36:43)


かずま 様

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

そうですね、初心者には、きついですね・・・
レビュー見ましたが評判悪いみたいですね・・・

関数形式マクロの説明なしに、#define iskanji(c) ... なんて平気で書いて
います。

そうなんです、関数形式マクロというんですね。
私も初めてみてビックリしました。
こういう形式があるのですね。
ご解説いただければありがたいのですが・・・

/*まず後ろにずらしてから*/  ← この部分の処理をわかりやすく説明してほしい
for (i = n + 1; i >= 0; i--) ← 難しいです。
buf[i + off] = buf[i];

この処理についても知恵を貸していただけると嬉しいのですが・・・
混乱してます・・・



この投稿にコメントする

削除パスワード

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