C言語学習記録5 fgets使用時の入力ストリームのバッファ
fgets
char *fgets(char *s, int size, FILE *stream);
fgets は stream が示すファイルから改行('\n')または n-1 バイト目まで文字を読み込み、引数で渡された s に格納する。この n-1 バイトの中には改行自体も含まれる。その後文字列の末尾に終端記号 '\0' を付与する
入力に使用したテキストファイル
下記のようなテキストを使用する
abcdefghijklmnopqrstuvwxyz1234567890 aiueokakikukekosashisusesotachitsuteto
fgetsで2回入力してみる
下記のプログラムで入力する
fgetsの最大入力可能文字数は19文字とし、入力テキストの一行の文字数より少ない
#include<stdio.h> #include<stdlib.h> //exit() int main(void) { char file_name[] = "myfile.txt"; char buf[20]; int i; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) { perror(file_name); return 1; } printf("一回目\n"); if (fgets(buf, sizeof(buf), fp) == NULL) { printf("入力エラー\n"); exit(1); } for (i=0;i<sizeof(buf);i++) { printf(" buf[%d] -> %c : %d\n", i, buf[i], buf[i]); } if (fgets(buf, sizeof(buf), fp) == NULL) { printf("入力エラー\n"); exit(1); } printf("二回目\n"); for (i=0;i<sizeof(buf);i++) { printf(" buf[%d] -> %c : %d\n", i, buf[i], buf[i]); } if (fclose(fp) == EOF) { perror(file_name); return 1; } return 0; }
実行例
一回目 buf[0] -> a : 97 buf[1] -> b : 98 buf[2] -> c : 99 buf[3] -> d : 100 buf[4] -> e : 101 buf[5] -> f : 102 buf[6] -> g : 103 buf[7] -> h : 104 buf[8] -> i : 105 buf[9] -> j : 106 buf[10] -> k : 107 buf[11] -> l : 108 buf[12] -> m : 109 buf[13] -> n : 110 buf[14] -> o : 111 buf[15] -> p : 112 buf[16] -> q : 113 buf[17] -> r : 114 buf[18] -> s : 115 buf[19] -> : 0 二回目 buf[0] -> t : 116 buf[1] -> u : 117 buf[2] -> v : 118 buf[3] -> w : 119 buf[4] -> x : 120 buf[5] -> y : 121 buf[6] -> z : 122 buf[7] -> 1 : 49 buf[8] -> 2 : 50 buf[9] -> 3 : 51 buf[10] -> 4 : 52 buf[11] -> 5 : 53 buf[12] -> 6 : 54 buf[13] -> 7 : 55 buf[14] -> 8 : 56 buf[15] -> 9 : 57 buf[16] -> 0 : 48 buf[17] -> : 10 buf[18] -> : 0 buf[19] -> : 0
二回目の入力では一回目の入力で読みきれなかったストリームバッファに残っている分が出力する
回避策1: オーバーした分は読み飛ばす
改行文字が含まれていない場合はwhile(fgetc(fp) != '\n');で空読みする
#include<stdio.h> #include<stdlib.h> //exit() #include<string.h> // strchr(), strlen() int main(void) { char file_name[] = "myfile.txt"; char buf[20]; int i; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) { perror(file_name); return 1; } printf("一回目\n"); if (fgets(buf, sizeof(buf), fp) == NULL) { printf("入力エラー\n"); exit(1); } for (i=0;i<sizeof(buf);i++) { printf(" buf[%d] -> %c : %d\n", i, buf[i], buf[i]); } if (strchr(buf, '\n') != NULL) { buf[strlen(buf) - 1] = '\0'; } else { // 改行文字がない場合は、bufのサイズを超えた場合のため、 // 入力ストリームを空読みする while(fgetc(fp) != '\n'); } if (fgets(buf, sizeof(buf), fp) == NULL) { printf("入力エラー\n"); exit(1); } printf("二回目\n"); for (i=0;i<sizeof(buf);i++) { printf(" buf[%d] -> %c : %d\n", i, buf[i], buf[i]); } if (fclose(fp) == EOF) { perror(file_name); return 1; } return 0; }
実行例
一回目 buf[0] -> a : 97 buf[1] -> b : 98 buf[2] -> c : 99 buf[3] -> d : 100 buf[4] -> e : 101 buf[5] -> f : 102 buf[6] -> g : 103 buf[7] -> h : 104 buf[8] -> i : 105 buf[9] -> j : 106 buf[10] -> k : 107 buf[11] -> l : 108 buf[12] -> m : 109 buf[13] -> n : 110 buf[14] -> o : 111 buf[15] -> p : 112 buf[16] -> q : 113 buf[17] -> r : 114 buf[18] -> s : 115 buf[19] -> : 0 二回目 buf[0] -> a : 97 buf[1] -> i : 105 buf[2] -> u : 117 buf[3] -> e : 101 buf[4] -> o : 111 buf[5] -> k : 107 buf[6] -> a : 97 buf[7] -> k : 107 buf[8] -> i : 105 buf[9] -> k : 107 buf[10] -> u : 117 buf[11] -> k : 107 buf[12] -> e : 101 buf[13] -> k : 107 buf[14] -> o : 111 buf[15] -> s : 115 buf[16] -> a : 97 buf[17] -> s : 115 buf[18] -> h : 104 buf[19] -> : 0
二回目ではテキストの二行目が読み込まれた
回避策2: オーバーした場合はエラーにする
下記のようにエラーにする
if (strchr(buf, '\n') != NULL) { buf[strlen(buf) - 1] = '\0'; } else { printf("一行に入力可能な最大文字数(%d文字)をオーバーしました\n", sizeof(buf) -1 ); exit(1); }
実行例
一回目 buf[0] -> a : 97 buf[1] -> b : 98 buf[2] -> c : 99 buf[3] -> d : 100 buf[4] -> e : 101 buf[5] -> f : 102 buf[6] -> g : 103 buf[7] -> h : 104 buf[8] -> i : 105 buf[9] -> j : 106 buf[10] -> k : 107 buf[11] -> l : 108 buf[12] -> m : 109 buf[13] -> n : 110 buf[14] -> o : 111 buf[15] -> p : 112 buf[16] -> q : 113 buf[17] -> r : 114 buf[18] -> s : 115 buf[19] -> : 0 一行に入力可能な最大文字数(19文字)をオーバーしました