C言語関係掲示板

過去ログ

No.988 行末の空白を削除する(K&R 演習1-18)問題

[戻る] [ホームページ]
No.12923

行末の空白を削除する(K&R 演習1-18)問題
投稿者---HA(2004/02/24 14:47:41)


こんにちは。はじめて投稿します。
K&R 演習1-18で、行末のブランクやタブを削除し、かつ空白行はすべて削除するプログラムを作成せよ。
という問題があるのですが、一応動作はするのですがわからないところがあります。
プログラムは次のようになっています。

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

#define BUFFER 256

int getline(char*, int);

int main(void)
{
        int i;
        int newline;
        char buf[BUFFER];

        while((i = getline(buf, BUFFER)) > 0){
                newline = 0;

                if(i > 0 && buf[i-1] == '\n'){
                        newline = 1;
                        i -= 2;
                }
                else
                        i -= 1;

                while(i >= 0 && (buf[i] == ' ' || buf[i] == '\t'))
                        --i;

                if(i >= 0 && newline)
                        buf[++i] = '\n';

                buf[++i] = '\0';

                if(i > 0)
                        printf("%s", buf);
        }
        exit(0);
}

int getline(char s[], int lim)
{
        int c;
        int 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;
}

このプログラムでは、BUFFERの量が十分な場合のみに正しい動作をします。
しかし、BUFFERの量が小さかった場合(極端な話 5 など)は正しく動作しません。
もし、BUFFER が 5 のとき以下のような入力があっても正しく動作させるには
どのようにしたら良いのでしょうか?

aaaa____aaaa\n\0 (_はスペースのつもりです)

また、このプログラムで問題な点等がありましたら、ご指摘ください。
よろしくお願いします。

No.12928

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---Cマニア(超初心者)(2004/02/24 15:33:50)


これは入力した文字列間の空白を削除するプログラムですか???
ただ入力した文字列を表示させてる気がするんですけど・・・。
それからmain関数の
        exit(0);


は、
        return 0;


と書いたほうがいいと思います。それかmain関数をvoid型にする。

No.12931

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---HA(2004/02/24 15:51:47)


>これは入力した文字列間の空白を削除するプログラムですか???
>ただ入力した文字列を表示させてる気がするんですけど・・・。
このプログラムは文字列間の空白ではなく、行末の空白を削除する
プログラムです。入力の例が悪かったかもしれません。
aaaa____aaa_\n\0
と入力したときに
aaaa____aaa\n\0
と出力されてほしいのですがうまくいきません。

>それからmain関数の
main関数の終わりはexit(0); でも return 0; でもどちらでも良く、
趣味の問題だと思っていますが、間違いでしょうか?

>と書いたほうがいいと思います。それかmain関数をvoid型にする。
main関数はint型だと規格で決まっていたような気がします。


この投稿にコメントする

削除パスワード

No.12935

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---YuO(2004/02/24 16:09:22)


>>それからmain関数の
>main関数の終わりはexit(0); でも return 0; でもどちらでも良く、
>趣味の問題だと思っていますが、間違いでしょうか?

Cで書く限り,趣味の問題です。
see) 5.1.2.2.3 Program termination


>>と書いたほうがいいと思います。それかmain関数をvoid型にする。
>main関数はint型だと規格で決まっていたような気がします。

処理系が許すのであれば,mainの戻り値の型をvoid型にすることもできます。
see) 5.1.2.2.1 Program startup / Par.1 : "or in some other implementation-defined manner."
ただし,main関数の戻り値の型をわざわざvoid型にして,
処理系依存のプログラムにする必要があるとは,とても思えませんが。


No.12936

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---Cマニア(超初心者)(2004/02/24 16:20:38)


>それからmain関数の
main関数の終わりはexit(0); でも return 0; でもどちらでも良く、
趣味の問題だと思っていますが、間違いでしょうか?

>と書いたほうがいいと思います。それかmain関数をvoid型にする。
main関数はint型だと規格で決まっていたような気がします。

あ、そうですけど私の場合はexit(1)だと警告が出てすっきりしないんで・・・。
一応mainはvoid型とすることはできます。
YuOさんが言うように処理系依存になってしまいますけど・・。

No.12938

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---HA(2004/02/24 16:58:43)


>あ、そうですけど私の場合はexit(1)だと警告が出てすっきりしないんで・・・。

そうでしたか。コンパイラの違いでしょうか?私はCygwinのgccを使っていますが、
警告は出て来ません。

>一応mainはvoid型とすることはできます。
>YuOさんが言うように処理系依存になってしまいますけど・・。

void型にできること自体は知っていましたが、コンパイル時にWarningがでるので。処理系によって違うんですね。
勉強になります。

No.12932

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---YuO(2004/02/24 15:59:36)


>このプログラムでは、BUFFERの量が十分な場合のみに正しい動作をします。
>しかし、BUFFERの量が小さかった場合(極端な話 5 など)は正しく動作しません。
>もし、BUFFER が 5 のとき以下のような入力があっても正しく動作させるには
>どのようにしたら良いのでしょうか?

BUFFERが256だと行あたり256バイト以上あった場合,やはり失敗します。

対策ですが,行単位での処理を行う必要があるので,
以前に読み出したデータを保持しておく必要があります。

固定長のバッファではなく,可変長のバッファを使うことで,
メモリが許す限り大きな行を扱うことができます。
see) malloc/realloc/free


No.12933

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---NykR(2004/02/24 16:03:55)


>もし、BUFFER が 5 のとき以下のような入力があっても正しく動作させるには
>どのようにしたら良いのでしょうか?
>
>aaaa____aaaa\n\0 (_はスペースのつもりです)

空白が来たら、それが行末の空白なのか行の途中の空白なのかがわかるまでどこかにためておけばいいでしょう。
#空白だけ、又はタブだけ、とかなら単に数えるだけでも可。

で、空白でも改行でもない文字が来たらためておいた空白を出力、
改行が来たら、空白は出力せずに次の行の処理、と。
ただし、空白文字とタブ文字を区別しなければなりませんから、どうしてもそのための記憶領域は必要です。

No.12937

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---HA(2004/02/24 16:51:11)


YuOさん、NykRさん、返信ありがとうございます。
getline関数を変更すれば何とかできそうです。
お二人の対処法を両方とも試してみたいと思います。

また、getline関数は何も手を付けずにお二人の対処法を実現する方法はあるのでしょうか?

No.12939

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---かずま(2004/02/24 17:31:24)


> また、getline関数は何も手を付けずにお二人の対処法を実現する方法はあるのでしょうか?

ないことはないけど、.....。BUFFER = 1 はだめです。
int main(void)
{
    int i, j, k = 0, m = 0, n = 0;
    char buf[BUFFER], *space = NULL;

    while ((i = getline(buf, BUFFER)) > 0) {
        for (j = 0; j < i; j++) {
            if (buf[j] == ' ' || buf[j] == '\t') {
                if (k >= n) {
                    if (n == 0)
                        n = 256;
                    n *= 2;
                    space = realloc(space, n);
                    if (space == NULL) {
                        puts("out of memory");
                        return 1;
                    }
                }
                space[k++] = buf[j];
            }
            else if (buf[j] == '\n') {
                if (m > 0)
                    putchar('\n');
                m = k = 0;
            }
            else {
                printf("%.*s%c", k, space, buf[j]);
                k = 0;
                m++;
            }
        }
    }
    return 0;
}


No.12940

Re:行末の空白を削除する(K&R 演習1-18)問題
投稿者---HA(2004/02/24 18:07:07)


返信ありがとうございます。

>ないことはないけど、.....。

やはりgetline関数を変更するか、使わないで書いた方がよいのでしょうか?