C言語関係掲示板

過去ログ

No.1125 文字数制限の無い標準入力

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

文字数制限の無い標準入力
投稿者---new(2004/06/15 15:06:46)


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

int main(void){
    char buf[256];
    char *len;
    
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf) -1] = '\0';
    fflush(stdin);
    
    len = (char *)malloc(strlen(buf) + 1);
    
    strcpy(len,buf);
    
    return 0;
}


上記のソースで最初にbuf[256]と制限をせず、入力文字分のメモリを確保したいと考えていますが、どうしてもできません。
どなたか、教えてください。お願いします。


No.2034

Re:文字数制限の無い標準入力
投稿者---あかま(2004/06/15 15:38:58)


>上記のソースで最初にbuf[256]と制限をせず、入力文字分のメモリを確保したいと考えていますが、どうしてもできません。
>どなたか、教えてください。お願いします。
reallocを使ってみてください。
http://www9.plala.or.jp/sgwr-t/lib/realloc.html

プログラムに一応つっこみを入れておくと
fgetsは文字列の最後に'\0'を付加しておくので↓はいりません。
buf[strlen(buf) -1] = '\0';

fflush()は出力ストリームを引数にとるので入力ストリームを入れると動作は未定義です。




No.2036

Re:文字数制限の無い標準入力
投稿者---円零(2004/06/15 16:58:29)


>プログラムに一応つっこみを入れておくと
>fgetsは文字列の最後に'\0'を付加しておくので↓はいりません。
>buf[strlen(buf) -1] = '\0';
それって、最後の改行を消してるのだと思います。


>fflush()は出力ストリームを引数にとるので入力ストリームを入れると動作は未定義です。
入力ストリームを入れた場合バッファのクリアのみを行なうのでは?



No.2044

Re:文字数制限の無い標準入力
投稿者---あかま(2004/06/15 22:19:53)


>>プログラムに一応つっこみを入れておくと
>>fgetsは文字列の最後に'\0'を付加しておくので↓はいりません。
>>buf[strlen(buf) -1] = '\0';
>それって、最後の改行を消してるのだと思います。
ボケてましたね。改行取りでした。

>>fflush()は出力ストリームを引数にとるので入力ストリームを入れると動作は未定義です。
>入力ストリームを入れた場合バッファのクリアのみを行なうのでは?
MSDNなどの大抵の環境ではきっちり動作するようです。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vclib/html/_crt_fflush.asp

ですが、規格は未定義。このHPでも書かれています。
http://www9.plala.or.jp/sgwr-t/lib/fflush.html

ついでなのでもうちょい調べて見ました。C言語辞典には、
>入力や、更新モードでの直前の操作が出力でない場合のストリームの動作は未定義である。たとえば、処理系によっては、ungetc関数の操作を取り消すこともある。
と書かれています。
MSDNでもこの辺には引っかかるようです。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vclib/html/_crt_ungetc.2c_.ungetwc.asp



No.2053

Re:文字数制限の無い標準入力
投稿者---円零(2004/06/16 10:19:39)


なるほど、環境依存だったのですか。
勉強になります。ありがとうございました。
因みに私の環境はVC++6.0で、付属のMSDNライブラリを見てました。

ただ、ungetc()については、fflush(stdin)後にも取り消さずにおく必要性が良くわからないです。
…ちょっとオフトピックですかね。


No.2037

ちょっとわかりません
投稿者---new(2004/06/15 17:05:02)


>reallocを使ってみてください。
>http://www9.plala.or.jp/sgwr-t/lib/realloc.html

お返事ありがとうございます。
reallocを調べてみましたが、今回のにどうやって応用できるかわかりませんでした。再度確保するということは、一度確保していなければならないんですよね?そのときの確保するサイズをどの様に動的にするのかが理解できませんでした。

>プログラムに一応つっこみを入れておくと
>fgetsは文字列の最後に'\0'を付加しておくので↓はいりません。
>buf[strlen(buf) -1] = '\0';

確かこれは、fgetsはリターンも入力から取ってくると聞きましたのでこのようにしていました。リターンは取らないのでしょうか?

>fflush()は出力ストリームを引数にとるので入力ストリームを入れると動作は未定義です。
>
fflush()は以前、どこかのHPで見たのをそのまま使ってました。まだまだ、勉強不足で恥ずかしい限りです。






No.2040

Re:ちょっとわかりません
投稿者---ニタチ(2004/06/15 19:09:11)


>reallocを調べてみましたが、今回のにどうやって応用できるかわかりませんでした。再度確保するということは、一度確保していなければならないんですよね?そのときの確保するサイズをどの様に動的にするのかが理解できませんでした。

 malloc()で確保します。動的に確保するには、ループ文内でfgets()し、
 改行が取り込まれていなかったらrealloc()する。
 といった感じでどうでしょうか??


>確かこれは、fgetsはリターンも入力から取ってくると聞きましたのでこのようにしていました。リターンは取らないのでしょうか?

 取ります。しかしbuf[strlen(buf) -1]が'\n'とは限りません。
if( buf[strlen(buf) -1] == '\n' ){
    buf[strlen(buf) -1] = '\0';
}
とするといいと思います。

>fflush()は以前、どこかのHPで見たのをそのまま使ってました。まだまだ、勉強不足で恥ずかしい限りです。
>

 私は↓のような方法でバッファをクリアしています。(違ってたらごめんなさい)
if( buf[strlen(buf) -1] != '\n' ){
    while( getchar() != '\n' )
            ;
}
#でもこれもあまり良くなかったような気も・・・。



No.2043

Re:ちょっとわかりません
投稿者---RAPT(2004/06/15 22:18:36)


stdinのバッファクリアには、rewind()を使います。



No.2045

Re:ちょっとわかりません
投稿者---YuO(2004/06/15 22:39:33)


>stdinのバッファクリアには、rewind()を使います。

rewind(fp)はfseek(fp, 0, SEEK_SET)にほぼ等しいわけですが,
stdinに対してfseekを行った場合の動作って定められていましたっけ?
呼び出しが失敗してもいいような気がするのですが。


No.2069

Re:ちょっとわかりません
投稿者---RAPT(2004/06/17 01:09:56)


> > stdinのバッファクリアには、rewind()を使います。
> rewind(fp)はfseek(fp, 0, SEEK_SET)にほぼ等しいわけですが,
> stdinに対してfseekを行った場合の動作って定められていましたっけ?
> 呼び出しが失敗してもいいような気がするのですが。
標準ではどうなっているかは存じませんが、少なくとも、VC++6のMSDNでは、
キーボード バッファをクリアするには、デフォルトでキーボードに結合して
いる標準入力ストリーム (stdin) に対して rewind 関数を使います。
とrewind()の解説欄に記載されていました。



No.2052

すいません遅くなりました。ご返信ありがとうございます。
投稿者---new(2004/06/16 09:49:01)


> malloc()で確保します。動的に確保するには、ループ文内でfgets()し、
> 改行が取り込まれていなかったらrealloc()する。
> といった感じでどうでしょうか??

私の勉強不足でちょっとピンときません。
fgets()するということは,以下のfgetsの書式で
char *fgets(char *str,int n,FILE *fp)

と定められているように、nの値(文字列数)が必要になり変数宣言で
buf[256]といったように文字数を宣言しなければならないような気がしてなりません。私の勘違いでしょうか?

> 取ります。しかしbuf[strlen(buf) -1]が'\n'とは限りません。
>
if( buf[strlen(buf) -1] == '\n' ){
    buf[strlen(buf) -1] = '\0';
}
とするといいと思います。

なるほど、そうだったんですか!てっきり最後に'\n'があると思っていました。勉強になります。

>
> 私は↓のような方法でバッファをクリアしています。(違ってたらごめんなさい)
>
if( buf[strlen(buf) -1] != '\n' ){
    while( getchar() != '\n' )
            ;
}
#でもこれもあまり良くなかったような気も・・・。


>stdinのバッファクリアには、rewind()を使います。

>rewind(fp)はfseek(fp, 0, SEEK_SET)にほぼ等しいわけですが,
>stdinに対してfseekを行った場合の動作って定められていましたっけ?
>呼び出しが失敗してもいいような気がするのですが。

バッファクリアにも何かいろいろあるんですね。まだ、rewindやfseekなどは使ったことがなく、理解力が欠けているのでこれをきに学習していきたいと思います。


No.2057

Re:すいません遅くなりました。ご返信ありがとうございます。
投稿者---ニタチ(2004/06/16 12:32:07)


>私の勉強不足でちょっとピンときません。
>fgets()するということは,以下のfgetsの書式で
>
char *fgets(char *str,int n,FILE *fp)

>と定められているように、nの値(文字列数)が必要になり変数宣言で
>buf[256]といったように文字数を宣言しなければならないような気がしてなりません。私の勘違いでしょうか?

 えっと、こんな感じでしょうか?
 自分で言っておきながら自信ありません。
    char *buff;
    
    buff = malloc( BUFF_SIZE ); 
    if( buff == NULL ){
        exit(1);
    }
    
    *buff='\0';

    while( fgets(buff + strlen(buff), BUFF_SIZE, stdin) )
    {
        if( strchr( buff, '\n' ) != NULL ){
            break;
        }

        buff = realloc( buff, strlen(buff) + BUFF_SIZE  );
        if( buff == NULL ){
            exit(1);
        }
    }


>> 取ります。しかしbuf[strlen(buf) -1]が'\n'とは限りません。
>なるほど、そうだったんですか!てっきり最後に'\n'があると思っていました。勉強になります。

 fgets( buf, 5, stdin );として、4文字以上入力された場合、'\n'はbufに取り込まれませんよね?
 例えば、abcdefgと入力したすると、buf[]には'a','b','c','d','\0'が入ります。
 buf[strlen(buf) -1] = '\0';とした場合、'd'が消されてしまいます。


No.2059

Re:すいません遅くなりました。ご返信ありがとうございます。
投稿者---円零(2004/06/16 13:20:30)


getcharの方が世話がなくて良いんじゃないかと思ったり。

#include <stdio.h>
#include <malloc.h>

int main(void){
    char *buffer;
    int size = 0;
    buffer = calloc(1, 1);
    do{
        buffer = (char*)realloc(buffer, ++size);
        if(buffer == NULL)exit(1);
        buffer[size - 1] = getchar();
    }while(buffer[size - 1] != '\n');
    printf("%s", buffer);
    return 0;
}



No.2061

free()忘れました。
投稿者---円零(2004/06/16 14:02:18)


標題の通りです。うっかりしてました。
printfの次にfree(buffer);入れといてください。
まあこのプログラムの場合は、次ですぐ終了ではありますが。


No.2064

ありがとうございます。
投稿者---new(2004/06/16 14:37:04)


ニタチ様、円零様ありがとうございました。
おふた方のご協力により、思うようにできました。

malloc,realloc,callocだけでなくfgetsにもいろいろ学ぶことができ、大変勉強になりました。感謝です。

しかし、どうしても理解できないところが一箇所あります。
ニタチ様からご教授いただいた次の文なんですが、
>while( fgets(buff + strlen(buff), BUFF_SIZE, stdin) )
この文の"buff + strlen(buff)"のやっていることが理解できません。
buffはこの時ポインターで、strlen()は文字列数を返すと理解していますが、その二つをプラスするとは一体どういうことなんでしょうか?


No.2065

Re:ありがとうございます。
投稿者---NykR(2004/06/16 14:59:06)


>>while( fgets(buff + strlen(buff), BUFF_SIZE, stdin) )
>この文の"buff + strlen(buff)"のやっていることが理解できません。
>buffはこの時ポインターで、strlen()は文字列数を返すと理解していますが、その二つをプラスするとは一体どういうことなんでしょうか?

buffは、配列の要素を指すポインタで、それに整数を足すと、その個数分後ろの要素を指すポインタが得られます(そこに要素がある場合)。
つまり、&buff[strlen(buff)] と同じです。

> strlen()は文字列数を返すと

strlen()は文字列長を返します。

それから
    char *buff;
    
    buff = malloc( BUFF_SIZE ); 
    if( buff == NULL ){
        exit(1);
    }
は単純に
char *buff = NULL;
でいいでしょう。reallocの第一引数が空ポインタの場合、mallocと同じなので。
あと、malloc.hは標準にはないので stdlib.hを使いましょう。


No.2066

重ね重ねありがとうございます。
投稿者---new(2004/06/16 15:22:38)


>buffは、配列の要素を指すポインタで、それに整数を足すと、その個数分後ろの要素を指すポインタが得られます(そこに要素がある場合)。
>つまり、&buff[strlen(buff)] と同じです。

なるほど、そういうことですか納得です。

>strlen()は文字列長を返します。

数ではなく長さなんですね!わかりました。

これで、すべて納得できました。これもみなさまがたのおかげです。
ありがとうございました。




No.2067

Re:ありがとうございます。
投稿者---ニタチ(2004/06/16 15:47:53)


>それから
    char *buff;
    
    buff = malloc( BUFF_SIZE ); 
    if( buff == NULL ){
        exit(1);
    }
は単純に
>char *buff = NULL;
>でいいでしょう。reallocの第一引数が空ポインタの場合、mallocと同じなので。

 そうでしたか、勉強になりました。ありがとうございます。