• 締切済み

getsをscanfで書き直すにはどうしたらよいですか?

現在。行数を数えるプログラムを例をみながらエディダに入力してコンパイルしてみたのですが、gets関数ではエラーが出てそれ以上すすまないです。 他の掲示板なんかをみると、getは危険だからscanfを使うといいですよと書いてあったのですが、書き換えかたがよく分からないのです。 *以下が問題にしているソースです。 /* ************************************* */ /* */ /* 行を数えるプログラム */ /* */ /* ************************************* */ #include <stdio.h> #include <stdlib.h> void main(void) { FILE *fp; char fname[256]; int c; int count; printf("ファイル名:"); if (gets(fnama) == NULL) { /* この部分 */ printf("入力エラーが発生しました。\n"); exit (-1); } if ((fp = fopen(fname,"r")) == NULL) { printf("ファイル '%s'をオープンできませんでした。\n",fname); exit (-1); } while ((c fgetc(fp)) != EOF) { if (c == '\n') { count++; } } printf(">>> ファイル %s は %d 行です。\n",fname,count); fclose(fp); }

みんなの回答

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.8

処理系が不明な状況で、「決め付け」の回答をいくらしても不毛なだけですが... 何となく、glibcがgetsをリンクしたときに出す警告の話のような気がします。 その警告を消すためにscanfを使うというのなら、一応効果があります。 なお、scanfで入力文字数を制限するのであれば、 char *mygets(char *s) {  if (scanf("%256[^\n]%*[^\n]", s) < 1)  {   return NULL;  }  return scanf("%*c") == EOF ? NULL : s; } とでもしておけば、入力文字数を256文字に制限できます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.7

う~ん, 「getsは危険だからscanfを使うといいですよ」って意味が分からんなぁ. まあ確かに gets よりは scanf の方が安全にできるけど, 普通の流れは「gets は危険だから fgets」だと思う. ああ, fgets は仕様上「最後に改行が残ることがある」のでその処理は必要. 以下 #5 に対する補足というか突っ込みというかなんというか: まず, 「ファイルが 0x1a で終わっている」とは限らない. 0x1a はいわれる通り CP/M の名残だが, これは CP/M がブロック単位でしか長さを記録できなかったためであり, MS-DOS では既にこの仕様は廃止されている. また, 「プログラムが正常に終了した場合」に「返すべき」値は C の規格で決まっているし, (#define された) 記号定数として与えられている. プログラム上で「OS のご機嫌取り」をする必要はない.

  • chie65535
  • ベストアンサー率43% (8523/19372)
回答No.6

「getsが危険な理由」は「改行が来るまで延々と読み込もうとする」からです。 入力をリダイレクトし、ファイルを標準入力に結び付けた場合、そのファイルが2メガバイトあって、改行コードが一切入って無いとしたら、getsは、指定したバッファに2メガバイト読み込もうとします。 それが「危険な理由」です。 どなたかの回答で scanf("%[^\n]%*c", s) < 1 ? NULL : s; と書いているのがありますが、これも「scanfを使ってgetsを忠実に再現した」ので「getsとまったく同じ危険性を孕んでいる」のです。 これでは「危険性を回避する」と言う目的を達していません。 「危険性を回避する」には「上限(バッファサイズ)を与え、改行が来ない場合にも上限を超えないように打ち切る」と言う処理が必要です。 そういう意味では「scanfもgetsと同様に危険」なので「getsをscanfに置き換えても危険なのは危険」です。 安全性を求めるなら「getcharだけ使って1行入力を自作する」しかありません。

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.5

>gets関数ではエラーが出てそれ以上すすまないです。  いや、それ以上進みますが・・(もち、スペルミス修正後 fnama → fname )。  (BorlandC++5.5.1)  「エラー」の出た場所は、while ((c fgetc(fp)) != EOF) { では・・?。  まっ、ここを直し、コンパイルできたとしても、  テキストファイルは、ファイル終端が 「改行」0x1A ではなく、直 0x1A のこともあります( 0x1A は CP/M の名残?)。  if( c == '\n' ){ は「改行」を数えているので、この場合、最終行をカウントしません。  正確に行数を数えるのなら fgets がよろしいのでは・・。  http://www.bohyoh.com/CandCPP/C/Library/index.html  「・・改行文字を読み取ったとき、またはファイルの終わりを検出したときに、文字の読取りは終了・・」    ここの「または・・」が「改行なしの最終行」を指すのだと思います。 >他の掲示板なんかをみると、getは危険だからscanfを使うといいですよと書いてあったのですが、書き換えかたがよく分からないのです。  gets の、「入力する文字数を制限できない」という点は、今回は関係ないかと・・。 +++++++++++++++++++++++++++++++++++++ >void main(void)  質問者様お使いの処理系が、この定義を「エラー」としないのは、「処理系定義の方法」だからで、いたって正常な使い方だと思います。 ☆「自分」で「自分」のプログラムからの「戻り値」を使おうとしない限り、void main() のままのスタイルで良いと思います。  なお、「戻り値」は、OS、少なくとも MS-Windows にとっては、全く無用で屁の突っ張りにもなりません。  万が一、「戻り値」がOSにとって重要であるならば、(プログラム的には正常終了 = return )状態によって、どんな整数を「戻す」べきか、調べてプログラムしないといけません。  言い換えると、OSのご機嫌取りをしなくてはなりません。 ☆「言語」側(「自分」のプログラム)で、「OS」のご機嫌取りをする必要は全くない、と考えます。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.4

>getは危険だから 今回のような練習問題のレベルであれば、getsを使っても特に問題ないです。 他のだれにも迷惑がかかりませんので。 >void main(void) main関数の型は言語規格でintであると決まっています。 >count++; インクリメントするからには、ゼロで初期化しておかねばなりません。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.3

>このままgets関数を使っていてもいいですか? まずは何故危険であるかを理解しましょう。 scanf() を使用しても「自動的に」安全性が手に入るわけではありません。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

スペルミスのような気もしますが... > getsをscanfで書き直すにはどうしたらよいですか? これに答えるのであれば、 char *mygets(char *s) {  return scanf("%[^\n]%*c", s) < 1 ? NULL : s; } でよいかと思います。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

>gets関数ではエラーが出てそれ以上すすまないです。 スペルを間違えている。とかそんなオチではないですよね?

dohri
質問者

補足

すいません、そんなオチでした・・・ でも、最後まで、gets関数は危険ですというメッセージは 消えませんでした。 このままgets関数を使っていてもいいですか?

関連するQ&A

  • C言語のプログラミングで困っています

    C言語を勉強しています。まだまだ初心者で分からないことだらけなのですが、今回はファイル入出力の部分が分からず苦戦しています。 『100個の実数が入った2つのテキストファイルから数値を読み込み、  絶対値を求めるなどの計算をする』プログラムを作成しているのですが、 コンパイルし実行すると強制終了してしまいます。 プログラムは、 void main(void) { FILE *fp; double c[50000];   double d[50000];   double e[50000]; int n = 0;   int m = 0;   int i = 0;   char fname[80];   char fname2[80]; printf("ファイル名 : ");    gets(fname); if((fp = fopen(fname, "r")) == NULL){ printf("ファイルがオープンできません\n"); exit(1); } printf("\n"); while (fscanf(fp,"%lf",&c[i])!=EOF){ printf("%3d : %3lf",++n,c[i]); printf("\n"); i++; } printf("\n"); i=0; n=0; printf("ファイル名 : ");    gets(fname2); if((fp = fopen(fname2, "r")) == NULL){ printf("ファイルがオープンできません\n"); exit(1); } printf("\n"); while (fscanf(fp,"%lf",&d[i])!=EOF){ printf("%3d : %3lf",++n,d[i]); printf("\n"); i++; } …(以下計算) のようになっています。 整数のデータで計算を行うと、正常に動くのですが…。 コンパイルしてもエラーが出ないので、どこが悪いのかわからず困っています。 どなたか教えていただけないでしょうか。お願いしますm(_ _)m

  • ファイルから一文字ずつ読み込む

    ファイルを読み込むfgetc()関数のところでプログラムが停止します。 以下が実行したプログラムです。 #include<stdio.h> void get_name(char name[],int a){ printf("ファイル名を入力してください。\n"); scanf("%s",name); } void open(FILE *fp2,char name[]){ if((fp2=fopen(name,"r"))==NULL){ printf("ファイルオープンエラー"); } } int count(FILE *fp3){ int ch=0; int count=0; if(fp3==NULL){ printf("error"); } while((ch=fgetc(fp3))!=EOF){ if(ch=='\n'){ count++; } } printf("TEST"); fclose(fp3); return(count); } int main (void){ FILE *fp; char fname[30]; get_name(fname,30); open(fp,fname); printf("%d",count(fp)); return(0);} ファイル名を入力してください。ファイル名を入力、プログラム停止です。 '\n'を数えれるようにしてください。御指摘お願いします。

  • プログラムの異常終了

    TEST2とコマンドプロンプトに表示された後、異常終了します。 以下が実行したプログラムです。 #include<stdio.h> void get_name(char **f_name2){ printf("ファイル名を入力"); scanf("%s",*f_name2); } int count_num(FILE *fp){ int ch =0; int count=0; while((ch=fgetc(fp))!=EOF){ if(ch>0&&ch<9){ count++; } } return(count); } int main (void){ char *fname; FILE *fp; get_name(&fname); if((fp=fopen(fname,"r"))==NULL){ printf("ファイルオープンエラー"); }else{ printf("%d\n",count_num(fp)); } fclose(fp); printf("TEST2\n"); return(0); } textc13-7.exeは動作を停止しました。と表示があります。正常に終了したいので、 御指摘お願いします。

  • ファイル

    AからZまでの文字が何回出力されるか数えるプログラムなのですが、うまく出力されません。 どこを変えればよろしいでしょうか。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int count[26]; int main(void) { char str[100] = "xyzYZZ\n"; FILE *fp; char *p; int i; char ch; if((fp = fopen("myfile","w")) == NULL){ printf("ファイルを開くことが出来ません"); exit(1); } p = str; while(*p){ if(fputc (*p,fp) == EOF){ printf("ファイル書き込みエラー"); exit(1); } p++; } fclose(fp); if((fp = fopen ("myfile","r")) == NULL){ printf("ファイルを開くことが出来ません"); exit(1); } while((ch == fgetc(fp)) != EOF){ ch = toupper(ch); if( ch >= 'A' && ch <='Z' ) count[ch - 'A']++ ; } for( i=0 ; i<26 ; i++) printf("%c は %d 回出現\n",i + 'A', count[i]); fclose(fp); return 0; }

  • 'strcpy': 識別子が見つかりません

    またもやわからないことが・・・ Visual C++ 2005で以下は(一部なんですが)をコンパイルすると、 #include<stdio.h> #include<stdlib.h> FILE *fp; struct meibo{ char name[12]; double tokutenA[6]; double tokutenB[6]; }; void main(int argc,char *argv[]) { char fname[20]; printf("ファイル名\n"); scanf("%s",fname); strcpy(fname,argv[1]); void input(FILE *fp,struct meibo* a,int* end); struct meibo a[5]; FILE *fp; int ban,end; if((fp=fopen("d:\\test\\fname","w"))==NULL){ printf("開けません\n"); exit(1); } visual studio 2005\projects\meibo\meibo1.cpp(18) : error C3861: 'strcpy': 識別子が見つかりませんでした となります、どう言うことでしょうか。 よろしくお願いします。

  • 'strcpy': 識別子が見つかりません

    初心者でまたもやわからないことが・・・ Visual C++ 2005で以下は(一部なんですが)をコンパイルすると、 #include<stdio.h> #include<stdlib.h> FILE *fp; struct meibo{ char name[12]; double tokutenA[6]; double tokutenB[6]; }; void main(int argc,char *argv[]) { char fname[20]; printf("ファイル名\n"); scanf("%s",fname); strcpy(fname,argv[1]); void input(FILE *fp,struct meibo* a,int* end); struct meibo a[5]; FILE *fp; int ban,end; if((fp=fopen("d:\\test\\fname","w"))==NULL){ printf("開けません\n"); exit(1); } visual studio 2005\projects\meibo\meibo1.cpp(18) : error C3861: 'strcpy': 識別子が見つかりませんでした となります、どう言うことでしょうか。 よろしくお願いします。

  • ファイルの出力

    コマンドラインで指定したファイルの内容を一行ずつ表示するプログラムです。一行表示するごとに次の行も表示するか尋ねます。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int main(int argc, char *argv[]) {  FILE *fp;  char str[80];  char ch;  if (argc != 2){   printf("コマンドライン引数が違います\n");   exit(1);  }  if ((fp = fopen(argv[1],"r")) == NULL){   printf("ファイルが開けません");   exit(1);  }  while(!feof(fp)){   fgets(str, 79, fp);   if (!feof(fp)) printf("%s",str);   printf("追加しますか?(y/n)");   gets(str);   if ( toupper(*str) == 'N') break;   printf("\n");  }     if (fclose(fp) == EOF){   printf("ファイルを閉じれません\n");   exit(1);  }  return 0; } while文の   gets(str);  if ( toupper(*str) == 'N') break; この部分を  ch = getchar();  if ( toupper(ch) == 'N') break; でやると上手く実行できないのですが、なぜでずか?

  • C言語、ファイル操作、fgets()について

    次のプログラムは入力された行を読み込み、コマンドラインで指定されたファイルに書き込みます。 空白行が入力されたら、入力の終了とみなしてファイルを閉じます。続いてファイルを入力用に開き、 fgets()を使ってファイルの内容を表示するものです。 (ソースコードが長くてすみません) #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp; char str[80]; /* コマンドライン引数を検査する */ if(argc!=2) { printf("ファイル名を指定してください\n"); exit(1); } /* 出力用にファイルを開く */ if((fp = fopen(argv[1], "w"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } printf("終了するには空白行を入力してください\n"); do { printf(": "); gets(str); strcat(str, "\n"); /* 改行を追加する */ if(*str != '\n') fputs(str, fp); } while(*str != '\n'); fclose(fp); /* 入力用にファイルを開く */ if((fp = fopen(argv[1], "r"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } /* ファイルを読み込み直す */ do { fgets(str, 79, fp); if(!feof(fp)) printf(str); } while(!feof(fp)); fclose(fp); return 0; } 【質問】fgets()内のint型の数値「79」がどうして79なのかが分かりません。     80でも良いような気がするのですが・・・

  • C言語について

    以下のプログラムについてです。 test.txtというファイルを読み込み、その中の異なる単語の数を求めるプログラムです。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> #include<stddef.h> #define NMAX 80 #define LMAX 5000 void count(FILE*, int); void all_words(FILE *); FILE *fp, *fp2; char *fn="alice.txt"; char *fn2="total word.txt"; char *ignore="\n !?()*-;:.,_\"[]"; int main(void){ int p=0, x, count, l, t=0,k=0; char name[LMAX][NMAX], word1[NMAX], word2[NMAX]; char *tp, *tp2; if((fp=fopen(fn,"r"))==NULL){ printf("Can't open '%s'.\n",fn); exit(1); } if((fp2=fopen(fn2,"w"))==NULL){ printf("Can't open '%s'.\n",fn2); exit(1); } for(count=0;count<LMAX;count++){ if(fgets(name[count],NMAX,fp)==NULL)break; p++; } for(count=0;count<p;count++){ for(x=0;x<NMAX;x++){ word1[x]=tolower(name[count][x]); } tp=word1; while((tp2=strtok(tp,ignore))!=NULL){ if(*tp2=='\''){ if(*(tp2+1)=='`') t=1; tp2++; } strcpy(word2,tp2); k=l=strlen(word2)-1; if(word2[k]==('\'' & l)) word2[l]='\0'; if(word2[0] =='\'' &&t==0){ if(word2[1]!='\0'){ fputs(word2+1,fp2); fputc('\n',fp2); } } else{ if(word2[0]!='\0'){ fputs(word2,fp2); fputc('\n',fp2); } } tp=NULL; } } fclose(fp); fclose(fp2); all_words(fp2); return 0; } void all_words(FILE* fp2){ char word3[NMAX]; int n=0; if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); exit(1); } for(;;){ if(fgets(word3, NMAX,fp2)==NULL) break; n++; } fclose(fp2); count(fp2,n); } void count(FILE* fp2, int n){ int count, x, y=0; char *m=(char *)malloc(n*NMAX); char *xp,*yp; if(m==NULL){ return ; } if((fp2=fopen(fn2,"r"))==NULL){ printf("Can't open '%s'.\n", fn2); exit(1); } for(count=0,xp=m; count<n;count++,xp+=NMAX){ fgets(xp,NMAX,fp2); } qsort(m,n,NMAX,(int (*)(const void*, const void*))strcmp); count=1; for(x=0,xp=m,yp=m+NMAX;x<n-1;xp+=NMAX,yp+=NMAX,x++){ if(strcmp(xp,yp)==0){ y++; count++; } else{ count=1; } } printf("KIDN OF WORD:%d\n",n-y); if(m){ free(m); m=NULL; printf("%p\n",m); } fclose(fp2); } このプログラムを実行するとメモリリークになってしまいます どうしたら良いでしょうか?

  • ファイルの入出力で困っています(C言語)

    はじめまして、nathan3と申します。 昔、さらっとC言語を学んでいたので、仕事場でも活用できればと思い、勉強しなおしています。 以下のプログラムですが、コンパイルはするものの、実行がなされません。 sprintfをつかってファイルを作り、fprintfで読み込み、countで繰り返し別名のファイルを読み込み・作成し…といったプログラムを書いているつもりです。 調べながら書いた稚拙なプログラムですが、ここがちがう!というところをお教えいただけると大変助かります。 #include <stdio.h> int main(void){ FILE *fp,*fo; char *fname1; char *fname2; char s[100],t[100]; int ret,count; for(count = 0 ; count < 3 ; count++) { sprintf(fname1, "sankasha%d.txt", count); fp = fopen(fname1, "r"); if (fp == NULL){ printf("%s can't open a file\n", fname1); return -1; } sprintf(fname2, "matome%d.txt", count); fo = fopen(fname2,"w"); if (fo == NULL){ printf("%s can't open a file\n", fname2); return -1; } printf("--fscanf---"); while( (ret = fscanf(fp,"%[^,],%s", s, t)) != EOF ){ fprintf(fo,"%s ", t); } } fclose(fo); fclose(fp); return 0; } 何度見直しても間違いが見つからず困窮しております。 どうぞ、みなさまのお力をお貸しください! よろしくお願いいたします。

専門家に質問してみよう