file_fgets_sscanf_buffer.c |
---|
#include<stdio.h> #include<stdlib.h> #define BUF_SIZE 1024 #define NATION_SIZE 20 #define REGION_SIZE 20 int main(void){ FILE *fp; char *ch_fgets; int ch_sscanf; char region[REGION_SIZE], nation[NATION_SIZE]; char buf[BUF_SIZE]; fp=fopen("for_file5.5.1buffer.txt", "r"); if(fp==NULL){ printf("Can't Open File\n"); exit(1); } while(1){ ch_fgets=fgets(buf, BUF_SIZE, fp); if(ch_fgets==NULL){ break; } ch_sscanf=sscanf(buf, "%s%s", nation, region); if(ch_sscanf!=2){ printf("Read Error\n"); break; } printf("%s\t%s\n", nation, region); } fclose(fp); return 0; } |
for_file5.5.1buffer.txt |
---|
Algeria Africa Argentina Latin-America Australia Oceanea Austria Europe Bangladesh Asia Belgium Europe Bolivia Latin-America Brazil Latin-America Bulgaria Europe Burkina-Faso Africa Cameroon Africa Canada North-Americal Chile Latin-America China Asia Colombia Latin-America Cote-d'Ivoire Africa Denmark Europe Ecuador Latin-America Egypt Africa Ethiopia Africa Finland Europe France Europe Germany Europe Ghana Africa Greece Europe Guatemala Latin-America Hungary Europe India Asia Indonesia Asia Iran Asia Ireland Europe Israel Asia Italy Europe Japan Asia Kazakstan Asia Kenya Africa Korea(South) Asia Kuwait Asia Madagascar Africa Malawi Africa Malaysia Asia Mali Africa Mexico Latin-America Morocco Africa Mozambique Africa Nepal Asia Netherland Europe New-Zealand Oceanea Niger Africa Nigeria Africa Norway Europe Pakistan Asia Peru Latin-America Philippines Asia Poland Europe Portugal Europe Rumania Europe Russia Europe Singapore Asia South-Africa Africa Saudi-Arabia Asia Spain Europe Sri-Lanka Asia Sweden Europe Switzerland Europe Tanzania Africa Thailand Asia Tunisia Africa Turly Asia Uganda Africa Ukraine Europe U.K. Europe U.S.A. North-America Venezuela Latin-America Vietnam Asia Yemen Asia Zambia Africa Zimbabwe Africa |
NATION_SIZE
を3に設定した場合の画面表示を以下に示します。
AlgeAfrica Africa ArgeLatin-America Latin-America AustOceanea Oceanea AustEurope Europe BangAsia Asia BelgEurope Europe BoliLatin-America Latin-America BrazLatin-America Latin-America BulgEurope Europe BurkAfrica Africa CameAfrica Africa CanaNorth-Americal North-Americal ChilLatin-America Latin-America ChinAsia Asia ColoLatin-America Latin-America CoteAfrica Africa DenmEurope Europe EcuaLatin-America Latin-America EgypAfrica Africa EthiAfrica Africa FinlEurope Europe FranEurope Europe GermEurope Europe GhanAfrica Africa GreeEurope Europe GuatLatin-America Latin-America HungEurope Europe IndiAsia Asia IndoAsia Asia IranAsia Asia IrelEurope Europe IsraAsia Asia ItalEurope Europe JapaAsia Asia KazaAsia Asia KenyAfrica Africa KoreAsia Asia KuwaAsia Asia MadaAfrica Africa MalaAfrica Africa MalaAsia Asia MaliAfrica Africa MexiLatin-America Latin-America MoroAfrica Africa MozaAfrica Africa NepaAsia Asia NethEurope Europe New-Oceanea Oceanea NigeAfrica Africa NigeAfrica Africa NorwEurope Europe PakiAsia Asia PeruLatin-America Latin-America PhilAsia Asia PolaEurope Europe PortEurope Europe RumaEurope Europe RussEurope Europe SingAsia Asia SoutAfrica Africa SaudAsia Asia SpaiEurope Europe Sri-Asia Asia SwedEurope Europe SwitEurope Europe TanzAfrica Africa ThaiAsia Asia TuniAfrica Africa TurlAsia Asia UganAfrica Africa UkraEurope Europe U.K.Europe Europe U.S.North-America North-America VeneLatin-America Latin-America VietAsia Asia YemeAsia Asia ZambAfrica Africa ZimbAfrica Africa |
for_file5.5.1buffer.txtの1列目,すなわち, nationに格納される国名の最大長は(a)なので, 終端文字を含めて(b)個の要素が確保されていれば 正常に動作するはずです.
逆にいえば,nationの要素数を(c)以下にしたら 何か不具合があってもおかしくありません.
国名用の要素数 | regionの先頭アドレス | nationの先頭アドレス | regionの先頭アドレスとnationの先頭アドレスとの差 |
---|---|---|---|
1 | |||
2 | |||
3 | |||
4 | |||
5 | |||
6 | |||
7 | |||
8 | |||
9 | |||
10 | |||
11 | |||
12 | |||
13 | |||
14 | |||
15 | |||
16 | |||
17 |
report8-1-3.c |
---|
#include<stdio.h> #include<stdlib.h> #define BUF_SIZE 1024 #define NATION_SIZE 1 #define REGION_SIZE 20 int main(void){ FILE *fp; char *ch_fgets; int ch_sscanf; char region[REGION_SIZE], nation[NATION_SIZE]; char buf[BUF_SIZE]; fp=fopen("for_file5.5.1buffer.txt", "r"); if(fp==NULL){ printf("Can't Open File\n"); exit(1); } while(1){ ch_fgets=fgets(buf, BUF_SIZE, fp); if(ch_fgets==NULL){ break; } ch_sscanf=sscanf(buf, "%s%s", nation, region); if(ch_sscanf!=2){ printf("Read Error\n"); break; } } printf("%d\t%p\t%p\t%d\n", NATION_SIZE, (void *)region, (void *)nation, region-nation); fclose(fp); return 0; } |
国名用の要素数 | regionの先頭アドレス | nationの先頭アドレス | regionの先頭アドレスとnationの先頭アドレスとの差 |
---|---|---|---|
1 | 0xbfffe090 | 0xbfffe08f | 1 |
2 | 0xbfffdd10 | 0xbfffdd0e | 2 |
3 | 0xbfffd990 | 0xbfffd980 | 16 |
4 | 0xbffff610 | 0xbffff60c | 4 |
5 | 0xbffff290 | 0xbffff280 | 16 |
6 | 0xbfffef10 | 0xbfffef00 | 16 |
7 | 0xbfffeb90 | 0xbfffeb80 | 16 |
8 | 0xbfffe810 | 0xbfffe808 | 8 |
9 | 0xbfffe490 | 0xbfffe480 | 16 |
10 | 0xbfffe110 | 0xbfffe100 | 16 |
11 | 0xbfffdd90 | 0xbfffdd80 | 16 |
12 | 0xbfffda10 | 0xbfffda00 | 16 |
13 | 0xbffff690 | 0xbffff680 | 16 |
14 | 0xbffff310 | 0xbffff300 | 16 |
15 | 0xbfffef90 | 0xbfffef80 | 16 |
16 | 0xbfffe710 | 0xbfffe700 | 16 |
17 | 0xbfffeb10 | 0xbfffeaf0 | 32 |
nationの要素数を2に設定し,AlgeriaとAfricaを読み込んだ場合の動作を説明します. sscanf関数によってあるアドレスから順に 文字(a),(b),(c),(d),(e),(f),(g),(h)が格納されていき, nationから(i)バイト後ろから 文字(j),(k),(l),(m),(n),(o),(p)が格納されていきます. よって, 文字(q),(r),(s),(t),(u),(v)が格納された場所に 文字(w),(x),(y),(z),(alpha),(beta)が上書きされたことになります. printf関数でnationを画面表示する際には, nation[(gamma)]に格納されている文字(delta)から文字(epsilon)の直前までの 文字列(zeta)が表示されることになります.
nationの要素数を2に設定し,AlgeriaとAfricaを読み込んだ場合の動作を説明します. sscanf関数によってあるアドレスから順に 文字'A', 'l', 'g', 'e', 'r', 'i', 'a', '\0'が格納されていき, nationから2バイト後ろから 文字'A', 'f', 'r', 'i', 'c', 'a', '\0'が格納されていきます. よって, 文字'g', 'e', 'r', 'i', 'a', '\0'が格納された場所に 文字'A', 'f', 'r', 'i', 'c', 'a'が上書きされたことになります. printf関数でnationを画面表示する際には, nation[0]に格納されている文字'A'から文字'\0'の直前までの 文字列AlAfricaが表示されることになります.
region-nation
が1,2,4,8なので、
そのときに正しく画面表示できなくなっています。
このような誤りを防ぐには,読み込まれるべき文字数を保持するために十分な大きさの要素数を設定すれば良いことになります.読み込む対象はfgets関数で読み込んだ文字列なので, nationもregionもその要素数をBUF_SIZEにすれば十分です。
ちなみに,region-nationにはある規則性が現れていますが,必ずこの規則にしたがうわけではないので,この規則を覚える必要はありません.むしろ,独立な変数(や配列)のアドレス配置に規則性があることを前提にプログラミングしてはいけません.