fgetc()関数の動作について

このQ&Aのポイント
  • Visual Studio 2008(C++)において、fgetc()関数を使用する際の戻り値の型について疑問があります。
  • char型のバッファでfgetc()関数の戻り値を受けることができる理由やShift-JISコードの文字コード番号についても知りたいです。
  • また、char型でEOF(End of File)を格納して識別する方法についても教えてください。
回答を見る
  • ベストアンサー

fgetc()関数の動作について

Visual Studio 2008(C++) において↓のようなコードを書いてビルドして、デバッグなしで実行すると、 コンソール上でちゃんとファイルの文字がコンソールに表示されます。 ところで、fgetc()関数のリファレンスを見ると、戻り値がint型を返すと書いてあるのに、 このコードだとchar型のバッファで受けています。char型でもfgetc() 関数の戻り値を受けられる理由がわかりません。 これはやはり、fgetc()がShift-JISコードの文字コード番号そのものを返しているのでしょうか。 (int型の配列で各要素にfgetc()の戻り値をみると、ファイル上の文字の文字コード番号が 入っています。) char型で受けると、文字そのものを受けられるのでしょうか? また、char型で受けた時に、char(1バイト)で、EOF(2バイト)をどうやって格納し、識別しているの でしょうか。 初歩的な質問で申し訳ありませんが、ご回答、よろしくお願いします。 #include <iostream> using namespace std; int main(){ FILE *fin = fopen("testa.txt", "r"); if(!fin){ "入力ファイルをオープンできません。"; return 1; } int i=0; char buf[20]; while((buf[i] = fgetc(fin))!=EOF){ i++; } buf[i]='\0'; cout << buf << endl; return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.2

>char型でもfgetc() 関数の戻り値を受けられる理由がわかりません。 char型は int型の一種です。長さが文字一文字分の整数型です。多くの場合8bit。 fgetc()の返すのは1文字もしくはEOFなので、格納できます。 >また、char型で受けた時に、char(1バイト)で、EOF(2バイト)をどうやって格納し、識別しているの でしょうか。 EOFは(かならずしも)2バイトではありません。値が -1 の int型定数です。多くの場合32bit。 char型が8ビットの場合、signed char は -128~+127の数値を扱えます。fgetc()がEOFの時は、-1 を返すので、signed char型変数に -1 が代入され、それと EOFつまり -1 を比較しているので一致します。 ファイルの途中に、0xFF というデータがあった場合、fgetc()は255というintデータを返しますが、signed char型変数にはそのまま255つまり0xFFが代入され、これはsigned char型では -1 と見なされるので、EOF と等しくなってしまいます。つまりそれ以降のデータが読めません。 「入力するファイルには将来にわたっても絶対に0xFFというデータは入っていない。入っていたら腹を切る」という場合には、fgetc() を signed char 型で受けてもかまいません。腹を切るのがいやな場合は、int型変数で受けます。 signed char とも unsigned char とも書かずに単に char と書いた場合にどちらになるかは処理系依存だったはずですので、単なる char型だと処理系によってはunsignedなので 0xFF は +255 になり、EOFと一致することは無くなります。なので、「特定のコンパイラだけで動けば良い。移植は許さない」という場合を除いて、上述のように腹を切る覚悟があってもchar型で受けてはいけません。

beterugius
質問者

お礼

詳しい長文を書いていただき、大変ためになりました。 どうも有難うございました。

その他の回答 (1)

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

C において char型は「小さい整数型」として扱われます. だから int の値を char型の変数に代入することも可能です. ただし, 「EOF を識別する」などという高級な機能はありません. たまたま EOF (の表す値) と一致したらアウトなので, fgetc (とその仲間たち) の返り値を char で受けるのはお勧めしません.

beterugius
質問者

お礼

どうも有難うございました。

関連するQ&A

  • 関数がうまく動作しない

    関数get_monthにchar *型の文字列を引数にして、先頭の三文字(大文字でも小文字でも可)が正しいかどうかを関数strnxcmpでチェックしていくものです。 ところが、関数get_month中のreturn iで帰ってくるのはメインプログラムを動作させたところいつも0になってしまっているようです。(本当は1~12が帰ってくるようにしたい。) for(i=1;i<=12;i++) { if(strnxcmp(tuki[i],s,3)==0) { return i;←ここのリターンで0が帰ってきてしまう。 } } } 何がおかしいためにこのようになってしまうのでしょうか? よろしくお願いします。 int strnxcmp(const char *s1,const char *s2,size_t n) { while(n && toupper(*s1) && toupper(*s2)) { if(toupper(*s1) != toupper(*s2)) { return ((unsigned char)*s1 - (unsigned char)*s2); } s1++; s2++; n--; } if(!n)return 0; if(*s1) return 1; return -1; } int get_month(char *s) { int m,i; char *tuki[]={"","January","Feburary","March","April","May","June","July","Augst", "September","October","November","December"}; for(i=1;i<=12;i++) { if(strnxcmp(tuki[i],s,3)==0) { return i; } } return -1; }

  • int型のchar型への代入について

    VC++6.0のfgetcのヘルプに以下のようなコードが有りました。 int型のchをcharのbuffer[i]に代入するということに違和感を感じたのですが、 1.このようにする必要性とは何なのでしょうか? 2.このような代入により具体的には何が行われているのでしょうか? 3.そもそも1文字とりだすfgetcの戻り値がcharでなくintなのはなぜ? 質問が漠然としていて申し訳ありませんが、お願いします。  FILE *stream; char buffer[81]; int ch; 省略   stream = fopen( "fgetc.c", "r" )) 省略 ch = fgetc( stream ); 省略 buffer[i] = ch;

  • CSVを用いた検索プログラム動かし方

    #pragma warning( disable: 4996 ) #include <stdio.h> #include <string.h> #include <fstream> using namespace std; typedef struct tagKOTOWAZA{ char japanese[50]; char english[50]; }KOTOWAZA; int main() { char buf[256]; KOTOWAZA c[200]; int i, count; /*ifstream strtok strcpy を使ってファイルを読み込む*/ //=====ここから===== ifstream fin("Book1.csv"); if(fin.is_open()){ //ファイル内容の表示とクローズ for(count=0;fin.getline(buf, sizeof(buf)), !fin.eof();count++){//読み込める間 //printf("%s",buf);デバッグ用 char *p; p = strtok(buf,","); if(p)strcpy(c[count].japanese,p); p = strtok(NULL,","); if(p)strcpy(c[count].english,p); } fin.close(); }else{ printf("ファイルのオープンに失敗しました。\n"); return 1; } //=====ここまで==== return 0; } ここからどうすればCSVファイルに書いた 漢字,English を検索できるのかがわかりません・・・ 言語はC++を使っていますvisualstudio2012を使っています。 どうすればいいのか全く分かりません。 よろしくお願いします。

  • C言語の関数の戻り値がおかしい?

    #include<stdio.h> #include<ctype.h> #include<stdlib.h> int get_word(char *buf,int buf_size,FILE *fp) { int len; int ch; while((ch = getc(fp)) != EOF && !isalnum(ch));/*→「英数字のとき」このループは飛ばす。*/ if(ch == EOF){/*もし英数字以外が入力されていたらメインプログラムにEOFを返す。*/ return EOF; } len = 0; do{ buf[len] = ch; len++; if(len >= buf_size){ fprintf(stderr,"word too long.\n"); exit(1); } }while((ch = getc(fp)) != EOF && isalnum(ch)); buf[len] = '\0'; return len; } int main(void) { char buf[256]; while(get_word(buf,256,stdin) != EOF){ printf("<<%s>>\n",buf); } return 0; } C言語ポインタ完全制覇という本のP67に載っていたプログラムをそのまま載せています。 get_word関数の中のif文で、EOFを返した時もループwhile(get_word(buf,256,stdin)により再入力するようなプログラムになっています。でも、「!=EOF」と記述されているのだから、EOFが返ったら終了だと思うのですが… なぜ再入力し続けるプログラム(無限ループ)になってしまっているのでしょうか? というか、私の環境で動作させたらおかしいだけじゃないでしょうか? よろしくお願いします。

  • 関数の型

    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」にすればエラーは出ないんですが、大きさを指定したいので・・・ どうかよろしくお願いいたします。

  • scanf()関数の使い方について

    はじめまして。 質問があります。 以下のコードを見てください。 ---------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> int main(void) { int i; char buf[256]; int y; int m; int d; printf("文字列を入力してください:"); scanf("%s",buf); i = sscanf(buf,"%d/%d/%d",&y,&m,&d); //OK #if 0 i = sscanf(buf,"%d %d %d",&y,&m,&d); //NG #endif printf("日付 %d-%d-%d 戻り値i=%d\n",y,m,d,i); return EXIT_SUCCESS; } ---------------------------------------------------------------- 標準入力から日付を表す文字列「例:"2007/04/17"」を入力してbufに 格納したものをsscanf関数の第1引数に指定して、y,m,dを表示 させてみると、「i = sscanf(buf,"%d/%d/%d",&y,&m,&d)」では、 うまくyとmとdに日付が格納される(つまり、yに2007が入り、mには 04が入り、dには17が入る。)のですが、 「i = sscanf(buf,"%d %d %d",&y,&m,&d);」でbufに格納すると、 yにはうまく格納されるのですが、他のmとdには、うまく格納してくれ ません。これは、なぜなのでしょうか? ご教授お願いします。

  • 関数から戻り値を得る方法について

    知り合いの方から関数の戻り値をえるときにreturn以外に例えば File(&i,&k);←関数呼び出し int File(int **j, double *k)←関数 {      ~      ~ } とやると(double *k)は関数からの出力として、呼び出しているFile(&i,&k)の(&k)に返されると聞きました。しかも、戻り値はint File()のintに依存しないと言われて試してみたのですが、どうもうまくいきません。 正しいやり方知っている方いましたら、教えて下さい。あと複数戻り値を返したいときはどうすればいいんでしょうか?

  • 引き数がポインタでない関数の戻り値はなぜint型なのか?

    最近、疑問に思っていることがあって質問したいんですが、一般的にc言語 で使われる関数っていうのは、引き数としてポインタをとる関数以外は全て 戻り値はint型なのですがこれはなぜでしょう。私自身の結論としては、も し関数の戻り値がchar型だとしたらchar型で表せる範囲の値は全てasciiコー ドとして使われているので、もしエラーがあって戻り値としてEOF(-1)を返す 際に1byteでは同じビット配列になる255が既に使われていてEOFとして-1を定 義できないために、-1と255が同じビット配列ではない1byte以上のデータ型 つまりint型(たぶん、int型がコンピュータが一番効率良く処理できるデータ型なのでたぶんint型を使ったと思いますが)を使ったのではないかと言う 結論に達したのですがこれは正しいのでしょうか。どなたか御教授お願い致 します。

  • C言語、fgetcを利用しファイルの内容を変数に

    C言語について質問です C言語のfgetcを利用しファイルの内容を変数にいれてそれを返す関数を作っているのですがうまくいきません <!--以下ソース--> char *file_get_contents(char *filename){ FILE *fp; int c; char *return_str; if((fp=fopen(filename,"r"))==NULL) return NULL; while((c=fgetc(fp))!=EOF ){ sprintf(return_str,"%c",c); } fclose(fp); return return_str; } 誰か理由と改善方法を教えてください!

  • fgetc関数について

    C言語で、fgetc関数を使って1文字読み込んだ文字をarray[i]=cのようにすると エラーが出るのですが、fgetcはint型を返すみたいのですが、それをうまく文字配列に入れるには、どうすればいいのですか?

専門家に質問してみよう