• 締切済み

fgets関数を使用したときの文字あふれについて

fgets関数を用いて文字列を入力し、その長さを測るプログラムを作っています。 #include <stdio.h> #include <string.h> #define MAX 256 int main ( int, char *[] ); int main ( argc, argv ) int argc; char *argv[]; { char buf[( MAX )]; while ( 1 ){ memset ( buf, 0, sizeof( buf )); fgets ( buf, MAX, stdin ); if( fgets == NULL ){ break; } printf("入力した文字列の長さは%dです\n" ,strlen( buf )); } return 0; } このプログラムでは、256までしか文字列の長さを測ることができません。 もしこのプログラムで256を超える文字列を入力してしまうと、文字のあふれが発生し、 「入力した文字列の長さは256です」 「入力した文字列の長さは(あふれた文字列の長さ)です」 とこのようになってしまいます。 このプログラムで256以上の文字を読み捨てて、 「入力した文字列の長さは(あふれた文字列の長さ)です」 を表示しないようにできるのでしょうか? また読み捨てた文字列の長さを知ることはできるのでしょうか? もしかしたらfgets関数を使用すると不可能なのではないか?と思っています。 分かる方が居ましたらどうか教えて下さい。 よろしくお願いします。

みんなの回答

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.5

fgetsの仕様は確認されていますか? fgetsは読み込んだ改行文字'\n'をバッファに格納します。 改行文字'\n'が格納されないのはバッファから溢れた場合とEOFに達した場合です。 また、 >printf("入力した文字列の長さは%dです\n" ,strlen( buf )); strlen()の戻り値の型はsize_tです。 sizeof(int) == sizeof(size_t) とは限りませんから"%d"では環境によって正しく出力されない事もありますし、たまたま正しく出力されてるように見えてるだけの事もあります。

回答No.4

fgetsは行末の改行をバッファに読み取ります。 このため, buf[strlen(buf) - 1] == '\n' が成立する場合は行末まで読み込んでおり,成立していない場合は読み残しがある状態になります。 「その行内で読んだ文字数」を保持する変数を一つ用意して,fgetsで読み込んだ文字数を追加していき, 行末まで読んだ場合にその変数の内容を出力して変数の内容を0にすることで,今回の問題に対処することができます。 ただし,最終行に改行を必要とするかはimplemation-definedであるため,それへの対処として, ループを抜けた時点で上記変数が0でなければ,文字数を出力する必要があります。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

対処としては既に回答があるのでいいとして…。 >int main ( int, char *[] ); main()のプロトタイプ宣言って必要でしたかね? >int main ( argc, argv ) >int argc; >char *argv[]; >{ かなり古い記述方法ですが、使用しているコンパイラと参照している資料はいつのものです? >if( fgets == NULL ){ >break; >} ここのif文の意図を説明できますか? おそらく勘違いしている可能性が高いので。 # fgetsのポインタがNULLだったらここまで到達出来ないので、何を判定すんのかなぁ…と。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

fgetsは ・可能なら改行文字まで読み込む ・文字数が多い場合は、途中で切れる ・どちらの場合も、文字列終端の'\0' は付加される という特徴があります。 「最後の文字を調べて、改行文字でなければ、途中で打ち切られたと判断して、(続きを読む等の)処置をする」というのが常套手段です。 そのようにするなら、自前で読み込むようにするか、fgetsを使わずにgetchar等を使って一文字ずつ確認するようにするか、でしょう。 ところで、本当に256でしたか?

  • honor
  • ベストアンサー率35% (25/71)
回答No.1

参考URLにあふれた文字をgetchar()で改行まで読み飛ばす方法が提案されています。

参考URL:
http://okwave.jp/qa/q549060.html

関連するQ&A

  • scanfの後のfgetsについて

    #include <stdio.h> int main(void) { char name[10]; int no; printf("ナンバーを入力してください: "); scanf("%d",&no); /* 35を入力 */ printf("文字列を入力してください: "); fgets(name,10,stdin); /*入力できない*/ return 0; } この例文だと、fgets関数が改行コードを読み取って、終了してしまい文字列入力が出来ないみたいなんですが、scanfの後にfgetsを使うような(scanfとfgetsの間にscanfの残した?改行コードを取り除く方法)処理はどのような方法があるのでしょうか? 試しにfgets文を2度書いたら思っていた動作をしてくれたのですが、はたしてfgets文を2度書くというような事をしていいものなのでしょうか?見た目もなんだか変な感じですし。。↓ #include <stdio.h> int main(void) { char name[10]; int no; printf("ナンバーを入力してください: "); scanf("%d",&no); /* 35を入力 */ printf("文字列を入力してください: "); fgets(name,10,stdin); fgets(name,10,stdin);  /*入力できる*/ return 0; }

  • どうしてもわかりません2

    #include <stdio.h> #include <string.h> #define MAX_LINE_SIZE 1024 #define NN 1000000 main(int argc, char* argv[]) { char fname[256]; char buf[MAX_LINE_SIZE]; int i; FILE *fp; for(i=1; i<argc; i++) { bzero(fname, 256); strcpy(fname, argv[i]); if( !(fp = fopen(fname, "r"))) { printf("File Open Error.\n"); exit(1); } while( fgets(buf, MAX_LINE_SIZE, fp ) ) { printf("%s", buf); } fclose(fp); } } このプログラムをコンパイルして(実行形式はa.out)コマンドラインから 以下のようなデータのテキストファイルna.txtを実行しました。./a.out na.txtするとこのソースだとbufに一行目がすべて文字列として入ってしまうと思います。そうではなく、1行目の数字ひとつずつを取り出す方法が知りたいです。たしか数字とか空白とかを判定する関数があったともうのですが、どうしてもわかりません。 ちなみにこの問いかけからこの問いがきています。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1577294 1 2 3 4 5 6 2 3 4 5

  • C言語のシェルプログラミングの課題が分かりません。

    C言語のシェルプログラミングを作れという課題で、以下のように作ったんですが、実行して何度かコマンドを入力した後、exitによって一発で終わらせることができません。どのように書き換えればいいか教えて下さい。 また、他にも書き換えた方がよいと思えるところがあったら是非教えて下さいm(_ _)m #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include MAX_ARGS 10 #include MAX_LEN 100 extern char **environ; void child(int argc, char *argv[MAX_ARGS]); int main(void){ int argc, n = 0; int status; char input[MAX_LEN], *argv[MAX_ARGS], *cp; const char *delim = "\t\n"; while (1){ ++n; printf("$ "); fflush(stdout); if(fgets(input, sizeof(input), stdin) == NULL){ break; } cp = input; for(argc = 0; argc < MAX_ARGS; argc++){ if((argv[argc] = strtok(cp, delim)) == NULL) break; cp = NULL; } if(strcmp(argv[0], "exit") == 0){ exit(0); } pid_t pid = fork(); if(pid == -1){ perror("fork"); exit(1); }else if(pid == 0){ child(argc, argv); }else{ wait(&status); } } return 0; } void child(int argc, char *argv[MAX_ARGS]{ execvp(argv[0], argv); }

  • メイン関数

    メイン関数には int main(void) と int main(int argc, char** argv) がありますが、後者のint argc, char** argv はどういう意味なのでしょうか?

  • main の引数には const 付けた方が

    C言語での質問です。 引数を取るような main 関数は int main( int argc, char *argv[]){~} とされていますが、argvの指す文字列を変更する、というのはいくら何でもまずいので、 int main( int argc, const char *argv[]){~} あるいは int main( int argc, const char const * const * argv){~} の方がいいのではないでしょうか? 何故、constを付けない形が出回っているのでしょうか?

  • strcmp,strcpy

    a.outの後で入力した文字列を比較するコードでの質問です。 #include<stdio.h> #include<string.h> int mystrcmp(???){ ??? } int main(int argc,char*argv[]){ printf(???); exit(0); } ???の所をどう書けばいいか分かりません、よろしくお願いします。

  • ファイルの内容の表示

    実行時のコマンドライン引数で指定したファイルの内容を、行番号付きで画面に表示するプログラムを作る という問題です。ヒントも与えられています。 行番号付きの表示、コマンドライン引数の利用。両者を組み合わせればできるはずだ >  main関数の引数にargcとargvを指定して、コマンドライン引数をファイル名として利用する。キーボード入力を促す文(プロンプト)や改行チェックは不要なので書かないこと >  コマンドライン引数が指定されない場合は、メッセージを表示してプログラムを終了 >  ファイルの内容を画面表示する処理は、ユーザー定義関数put_file_contentsに記述する。仮引数には文字型のポインタ変数をひとつ指定し、ファイル名を受け渡せるようにする。put_file_contents自体の型は整数型(int)で、正常終了なら返り値0を返すこと。 行番号付きのプログラム#include<stdio.h> > int put_file(char *filename); > > int main() > { > char line[50]; > char *ptr; > > printf("ファイル名を入力:"); > fgets(line,sizeof(line),stdin); > ptr = line + strlen(line) - 1; > if(*ptr == '\n') { > *ptr = '\0'; > } > > put_file(line); > > return 0; > } > > int put_file(char *filename) > { > FILE *fp; > char buf[100]; > int line_no; > > fp = fopen(filename,"r"); > if (fp == NULL){ > printf("%sを開けません\n",filename); > return 1; > } > line_no = 1; > while (fgets(buf,sizeof(buf),fp) != NULL){ > printf("%3d: ",line_no); > printf("%s",buf); > line_no++; > } > fclose(fp); > > return 0; > } で、コマンドライン引数のプログラムは#include<stdio.h> void write_key_inputs(char *filiname); int main(int argc, char *argv[1]) { write_key_inputs(argv[1]); return 0; } void write_key_inputs(char *filename) { FILE *fp; char buf[100] ; fp = fopen(filename,"w"); while(fgets(buf, sizeof(buf),stdin) != NULL) { fputs(buf, fp); } fclose(fp); return ; } です。これらを組み合わせて少しいじると出来るみたいなのですが、できていません。ちなみに私が考えたプログラムは #include<stdio.h> int put_file_contents(char *filename); int main(int argc,char *argv[]) { int i; if(argc == 1){ printf("コマンドライン引数がありません\n"); return 1; } for(i = 0;i<argc;i++) printf("argv[%d]は「%s」です\n",i,argv[i]); put_file(i); return 0; } int put_file(char *filename) { FILE *fp; char buf[100]; int line_no; fp = fopen(filename,"r"); line_no = 1; while (fgets(buf,sizeof(buf),fp) != NULL){ printf("%3d: ",line_no); printf("%s",buf); line_no++; } fclose(fp); return 0; } です。コマンドライン引数は表示されるのですが、行番号が表示されません。どうしたらいいでしょうか??

  • 関数の型

    C言語の勉強をしております。 以下のように、入力用の関数を作成し、入力された文字列を返して欲しいんですが、「1 番目の引数を 'char *[80]' から 'char *' に変換できません。」という警告メッセージが出てしまい、解決出来ません・・・。 原因と解決策を教えていただけないでしょうか? ちなみに環境はWindowsXP、コンパイラはVC6.0です。 #include <stdio.h> char *insertName(char *buf); int main(void) { char *buf[80]; buf = insertName(buf); printf(buf); return 1; } char *insertName(char *buf) { gets(buf); return buf; } mainの「buf」の定義を「char *buf」にすればエラーは出ないんですが、大きさを指定したいので・・・ どうかよろしくお願いいたします。

  • 文字列比較

    最長10文字の文字列を2件入力し、char型の配列にそれぞれ格納する。2つの文字列を比較し、文字列が同じだったら「equal」を表示し異なっていたら「Not equal」を表示するプログラムを作成せよという課題が出ました。 条件として、11文字以上の文字が入力されたら、先頭から10文字までを有効とし、11文字目以降を無視する。下記のプログラムで文字列1に11文字以上入力すると、うまく動きません。なぜ、うまくいかないかと、どうなおしたらよいかを教えてください。 #include<stdio.h> #include<string.h> #define max_length 10 void get_string (char *p_str, int size); int main() { char string1[max_length+2]; char string2[max_length+2]; printf("文字列1:"); get_string(string1,max_length+2); printf("文字列2:"); get_string(string2,max_length+2); if(!strncmp(string1,string2,max_length)) puts("equal"); else puts("Not equal"); } void get_string (char *p_str, int size) { fgets(p_str,size,stdin); }

  • プログラミング(関数reverseを作る)

    プログラミングの勉強会で文字列を反転させる関数(例:ABCDE→EDCBA)を作れという課題が出たのですが、以下のように書いたきり進みません。あと、何を書けばいいのでしょうか?教えてください。 #include <stdio.h> void reverse(char *); void reverse2(char *); void main(){ char buf[10]; printf("str :"); fgets(buf, 10, stdin); reverse(buf); printf("rev :%s", buf); return; } //文字列を反転させる関数 void reverse(char *s){ return; }

専門家に質問してみよう