• ベストアンサー

strtok関数の使い方 その2

http://oshiete1.goo.ne.jp/kotaeru.php3?q=2376843 で、質問させて頂いた者です。 先日は大変にお世話になりました。 先日の質問の続きという感じなんですが… ------------------ 「ex」ファイルのデータ 41 100000 42 110000 43 120000 --------- これらのデータを kihokyu[1].tosi=41 kihokyu[1].kan=100000 kihokyu[2].tosi=42 kihokyu[2].kan=110000 という感じで格納したいのです。 ------------------------ お陰様で、kihokyu[].tosiの方は 格納する事が出来ました。 ただ、 kihokyu[].kanの方が 格納することが出来ません。 「1245015」という値が 格納されてしまいます。 この原因は strtokの第一引数にNULL を渡したときの動作を 理解していないのかも知れません。 ------------------------ バッファにいったん蓄えて >buff = "41 100000\n" 41を構造体「kihokyu[i].tosi」に格納 >kihokyu[i].tosi = atoi(strtok(buff , " ")); ここが上手く行かない 10000を構造体「kihokyu[i].kan」に格納したつもり >kihokyu[i].kan = atoi(strtok(NULL , " \n")); 私の理解では、説明文の方に >2回目以降の呼び出しでは s1 に NULL を指定します と、ありましたので この時点で、NULL変数には 「10000」が蓄えられていると 理解しています。 この認識は間違っているのでしょうか? ご教示して頂けたら幸いです。

  • niiza
  • お礼率43% (211/486)

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct nentbl_ { int tosi; int kan; } nentbl; int main(void){ char buff[16]; FILE *fp; int i=0; nentbl kihokyu[50]; fp = fopen("ex.fil","r"); while(fgets(buff,sizeof buff,fp) != NULL){ if ( i == 50 ) break; kihokyu[i].tosi = atoi(strtok(buff , " ")); kihokyu[i].kan = atoi(strtok(NULL , " \n")); printf("toshi:%d\n",kihokyu[i].tosi); printf("kan:%d\n",kihokyu[i].kan); i++; } fclose(fp); return 0; } ---------------------------------------------------------------- を試してみてどうなるか、教えていただけますか? あと、コンパイラは何をお使いでしょうか?

niiza
質問者

お礼

ご回答して頂いたプログラムを 試してみました。 正常に出力されました。 ただ分からないのは 私も同じようなプログラムだと思うのですが どこがおかしいのか 分からないのです。 それで今日、 私のプログラムを実行してみたところ 正常に出力されるのです。 ちょこまかといじっていたので その辺りが原因なのかとは思いますが ハッキリとしないところが気持ち悪いです。 >あと、コンパイラは何をお使いでしょうか? borlandのbcc32.exe というのを使用しています。

その他の回答 (2)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

char buff[16]; buff = "41 100000\n"; kihokyu[i].tosi = atoi(strtok(buff , " ")); 上記のようにstrtokにリテラルな文字列へのポインタを渡してはいけません。 上記の処理は kihokyu[i].tosi = atoi(strtok("41 100000\n" , " ")); と同じで、これを実行するとプログラムメモリを壊します。 この後は、メモリが壊れているので何が起きるか判りません。変な所に変な物が格納されたり、暴走したり、フリーズしたりするでしょう。 buff = "41 100000\n"; は「buffに文字列を格納せず、16バイトの作業用メモリを指していたbuffのアドレスを忘れ去り、新たにbuffが文字列定数"41 100000\n"の内部アドレスを指すようにする」って事です。 buffの中に文字列をセットしたいなら char buff[16]; strcpy(buff,"41 100000\n"); kihokyu[i].tosi = atoi(strtok(buff , " ")); と書かないとなりません。 「ポインタの変更」と「文字列のコピー」は見た目の実行結果は同じですが意味が全然違います。

niiza
質問者

補足

ご返事有り難うございました。 お陰様で正常に出力されました。 ただ、幾つか質問したいことがありましたので お手数かとは思いますが ご教示して頂けたら幸いです。 1. >「buffに文字列を格納せず、16バイトの作業用メモリを指していたbuffのアドレスを >忘れ去り、新たにbuffが文字列定数"41 100000\n"の内部アドレスを指すようにする」 >って事です。 ということは、 buff = "41 100000\n"; とした場合は、 buffに「41 100000\n」というアドレスが 格納されてしまうと理解して宜しいのでしょうか? 2.ファイルのデータから入力をする場合、 以下のようにしないといけないのでしょうか? ------------ 二つのバッファ変数を用意して、 char buff[16]; char buff2[16]; FILE *fp; ・ ・ ・ いったん仮のバッファに入れて、 while(fgets(buff2,sizeof buff2,fp) != NULL){ それから本当のバッファに入れる strcpy(buff , buff2); のような感じで 処理をするのでしょうか? 3.もう一つ分からないのは NO,3で回答して頂いた方の方法でも 正常に処理することが出来たのですが strcpyを使用した方が良いのでしょうか? 申し訳ありませんが よろしくお願いします。

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

その例だと, 期待通りの結果になると思うんですが, 違いますか? 「どのようなデータに対して」 「どのような結果を期待して」 「どのような (期待に反する) 結果が得られたのか」 を挙げてもらえませんか?

niiza
質問者

お礼

ご返事有り難うございました。 今日実行したところ 期待通りの結果が得られました。 どうしてだろう…

関連するQ&A

  • strtok関数の使い方

    http://oshiete1.goo.ne.jp/kotaeru.php3?q=2361151 で、質問させて頂いた者です。 先日は大変にお世話になりました。 先日の質問の続きという感じなんですが… ------------------ 「ex」ファイルのデータ 41 4352 42 2341 43 5411 --------- これらのデータを kihokyu[1].tosi=41 kihokyu[1].kan=4352 kihokyu[2].tosi=42 kihokyu[2].kan=2341 という感じで格納したいのです。 ------------------------ 回答者の方にご指導して頂いたように、 ・ ・ ・ while(fgets(buff,sizeof buff,fp) != NULL){ if ( i > 50 ){ break; } kihokyu[i].tosi = atoi(strtok(buff , " ")); kihokyu[i].kan = atoi(strtok(NULL , " \n")); printf("%d\n",kihokyu[i].tosi); i++; } というstrtok関数を使ってみました。 ところが 41 42 43 と、表示されたあと 強制終了になってしまいます。 >kihokyu[i].kan = atoi(strtok(NULL , " \n")); を削除すると スムーズに処理が終了します。 >printf("%s\n",NULL); と、「NULL」の値を調べたところ 「{NULL}」と表示されました。 たぶん、strtok関数の使い方がおかしいと思うのですが ご教授して頂けたら幸いです。

  • memcpyについて

    構造体に整数のデータを格納する方法を 教えて下さい。 「ex」ファイルのデータ 41 4352 42 2341 43 5411 --------- これらのデータを kihokyu[1].tosi=41 kihokyu[1].kan=4352 kihokyu[2].tosi=42 kihokyu[2].kan=2341 という感じで格納したいのです。 プログラム 構造体のテンプレートを宣言 typedef struct nentbl_ { int tosi; int kan; } nentbl; int main(void){ char buff[16]; FILE *fp; int age , kyoku , i, y; 構造体を宣言 nentbl kihokyu[50]; ファイルを開く fp = fopen("ex.fil","rb"); ・ ・ ・ while(fgets(buff,sizeof buff,fp) != NULL){     整数に変換 y = atoi(buff); ここでエラー memcpy(&kihokyu[i].tosi,y,4); パラメータ '__src' は const void * 型として定義されているので int は渡せない(関数 main ) たぶんmemcpy関数の使い方が間違えていると思うのですが… ご教授して頂けたら幸いです。

  • 構造体について

    構造体についての質問です。 main関数で構造体に 格納しています。 その構造体の値を 自作の関数(look)で 参照したいのですが どのようにすればいいのか ご教示して頂けたら幸いです。 typedef struct nentbl_ { int tosi; int kan; } nentbl; //--------------------------------------------------- int look(id){ nentbl kihokyu[50]; printf("%d %d\n",kihokyu[id].tosi , kihokyu[id].kan); } //---------------------------------------------------- int main(void){ nentbl kihokyu[50]; ・ ・ ・ kihokyu[1].tosi =11; kihokyu[1].kan = 20; kihokyu[2].tosi = 21; kihokyu[2].kan = 30; kihokyu[3].tosi = 31; kihokyu[3].kan = 40; y = look(1);

  • strtok

    strtokにて分解した文字を各変数に格納する場合 char *p; FILE *fp; char buf[1000]; if((fp = fopen("○","r"))==NULL){ return 0; } if(!fgets(buf,1000,fp)) return 0; strcpy(p, buf); number = strtok(p,","); class_type = strtok(NULL,","); name = strtok(NULL,","); subject = strtok(NULL,","); と一行の文字列を各変数に格納しています。 ファイルの一行は以下のような形式になっています。 1,A,山田,数学//番号,クラスタイプ,名前,得意教科 これで各値は変数に格納できています。 しかし このファイルはCSVファイルなのですが、空の欄があると 1,A,,数学というデータがbuf内に入っています。 この場合 number→1 class_type→A name→数学 と空欄の箇所が飛ばされてしまっています。 改善する方法がわからないのですが strtokを使わない方がいいのでしょうか?

  • C言語でファイルの内容を strtok関数 を使って数字と文字を分けて

    C言語でファイルの内容を strtok関数 を使って数字と文字を分けて配列に格納したいのですが、うまくできません。 どこが駄目なのかご指摘をお願いします! ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int i=0; int num[10]; char na[10]; fp=fopen(argv[1],"r"); while(fgets(str,sizeof str,fp)!=NULL); tp = strtok ( str, " " ); while(tp != NULL ) { num[i]=atoi(tp); tp = strtok( NULL," "); if ( tp != NULL ){ na[i]=*tp; } i++; } printf("%d\n%s",num[0],na[0]); printf("%d\n%s",num[1],na[1]); fclose(fp); return 0; }

  • malloc関数(strtok関数の自作版)につきまして分からないこと

    malloc関数(strtok関数の自作版)につきまして分からないことがあります。 以下のプログラムにmallo関数がフリーする最適な位置を明示しなさいといわれました。 文字が分離した時にfreeすると助言されたのですが いまいち理解できません・・・。 条件式の中で使用するともいわれていました。(おそらくif文・・・。) 色んな意見を参考にしたいので詳しい方助言のほうよろしくおねがいします。 なおプログラムはほかの箇所を変更したり、他の場所でもmalloc関数を使用することが認められています。 またfreeする場所はメイン関数ではなくあくまでもstrtok関数の中で宣言するようです。 よろしくお願いします。 #include <string.h> #include <stdio.h> #include <stdlib.h> main(){ char* s2 = ",/"; char* result; char* r1; char* r2; char* r3; char* r4; result = strtok("//123//,45/,678,9/","/,"); r1 = strtok(NULL, s2); r2 = strtok(NULL, s2); r3 = strtok(NULL, s2); r4 = strtok(NULL, s2); printf("%s\n",result); printf("%s\n",r1); printf("%s\n",r2); printf("%s\n",r3); printf("%s\n",r4); return; } char *strtok(char *s1, const char *s2) { int i,len; char *str1, *str2 , *str3; static char *tok ; static char* mstr; if(s1 != NULL) { str1 = s1; } else { str1 = tok; } str2 = str1 + strspn(str1, s2); /* strspnを利用 */ if (*str2 == '\0') { return (NULL); } len = 1; i = 0; while(*(str2 + i) != '\0'){ len++; i++; } mstr = (char*)malloc(sizeof(char)*len); if(mstr == (NULL)) { return 0; } i = 0; while(*(str2 + i) != '\0'){ *(mstr + i) = *(str2 + i ); i++; } *(mstr + i ) = '\0'; str3 = mstr + strcspn(mstr, s2); /* strcspnを利用 */ if (*str3 != '\0'){ *str3 = '\0'; str3 = str3 + 1; } tok = str3; return (mstr); }

  • c#でC言語のstrtokに相当する関数は何か

    文字列から指定した文字でデータを区切る関数strtokがC言語にはある これに相当するC#の関数は何か 例えばCでは以下のように書く。 char data1[]= " 123 , 456 Yamada " ; char *token ; strtok( data, " ," ) ; /* スペースとカンマを区切りに文字列を抽出 */ token = strtok( str, " ." ); printf(" token chat = %s\n", token ) ; while ( token != NULL ) { token = strtok( NULL," ." ); if ( token != NULL ) printf(" token chat = %s\n", token ) ; } これに相当するc#のSplit関数を使用すると 不要な空白を取り出しているようである 知っている方がおりましたら、教えて下さい。

  • 次のソースの使い方(strtok()関数)

     次のソースプログラムについてです。 (“□”は、タブを表します) ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ #include <stdio.h> #include <stdlib.h> /* EXIT_SUCCESS */ #include <string.h> /* strtok() */ int main(void) { □int i, n; □char str[10], *token1, *token2; □scanf("%d", &n); □for (i=0; i<n; i++) { □□scanf("%s", str); □□token1 = strtok(str, ","); □□token2 = strtok(NULL, ","); □□printf("hello = %s , world = %s\n" ,token1 ,token2); □} □return EXIT_SUCCESS; } ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆  これを実行すると、入力待ち画面になって、何を入力すれば何が得られるのか、てんで分からないのですが、どなたか、このプログラムの使い方と意味について、解説をお願いします。  ちなみに、“1”を入力した後、[Ctrl]+[c]で抜けると、結果は、 ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ hello = ヒヒz@俳・, world = (null)◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ となりました。

  • いつもお世話になっております。http://oshiete.goo.n

    いつもお世話になっております。http://okwave.jp/qa/q5836517.htmlで質問させているものです。 皆さんのアドバイスを頂き、2分探索法で郵便番号から住所を検索するプログラムが出来たのですが、 住所から郵便番号を2分探索法で出すプログラムも同じ方法でやろうとしましたが、比較対象が漢字の為、大きい・小さいの判断できずに上手くプログラムが出来ていません。 csvファイルは読みデータをひとつに繋げてあいうえお順にソートしました プログラムを一部載せておきます(かなり省略済みですが…) #define NAME ken_all_address.csv int main(int argc,char *argv[]) { struct tb line; FILE *fp; char buff[SIZE], string_buff[SIZE]; char *address,*ret; int flag,linesu,linesu1,sum,count,up,up1,low,low1,center,center1; int i,j; long pos[FSIZE]; clock_t start,end; start = clock(); //引数処理 if((fq=fopen(NAME1,"r")) == NULL){ printf("ファイル%sが開けません\n",NAME1); return -1; } if((fp=fopen(NAME,"r")) == NULL){ printf("ファイル%sが開けません\n",NAME); return -1; } flag = 0; address = argv[1]; count=0; sum=0; if(atoi(address) == 0){ for(i=0; ;i++){ pos[i] = ftell(fq); ret=fgets( buff, sizeof(buff), fp ); if(ret==NULL){ break; } } linesu = i; //printf("%d",linesu); low=0; up=linesu-1; while(low <= up){ center=(up+low)/2; fseek(fq,pos[center-1],SEEK_SET); fgets( buff, sizeof(buff), fp ); strtok(buff,",\""); strtok(NULL,",\""); strcpy(line.now_num,strtok(NULL,",\"")); strtok(NULL,",\""); strtok(NULL,",\""); strtok(NULL,",\""); strcpy(line.kanji1,strtok(NULL,",\"")); strcpy(line.kanji2,strtok(NULL,",\"")); strcpy(line.kanji3,strtok(NULL,",\"")); strcpy(string_buff,line.kanji1); strcat(string_buff,line.kanji2); strcat(string_buff,line.kanji3); printf("%s %s %s\n",line.kanji1,line.kanji2,line.kanji3); if(strcmp(string_buff,address)==0){ printf("〒%s \n",line.now_num); flag=1; } if(strstr(string_buff,address) ==NULL){ low=center+1; } else{ up=center-1; } } } fclose(fp); if(flag==0 && atoi(argv[1]) == 0){ printf("「%s」に該当する郵便番号はありませんでした\n",address); } if(flag==0 && atoi(argv[1]) != 0){ printf("「%s」に該当する住所はありませんでした\n",address); } end = clock(); printf("引数=%s\n",address); printf("%.30f秒かかりました\n",(double)(end-start)/CLOCKS_PER_SEC); printf("fgetsの実行回数=%d回\n",sum); printf("比較回数=%d回\n",count); printf("\n"); return 0; }

  • strtokでの空文字への置き換え

    大したことじゃないと言えばそうかもしれませんが、ちょっと氣になるんで質問させてください。 C言語でstrtokという函數ありますよね。 第1引數の文字列を、第2引數の文字列を構成する文字で區切る。 第2引數の文字を見つけたら、それを空文字('¥0')に置き換える。 字句の最初の文字へのポインタを返す。 このようなものだと理解しています。 次のプログラムを實行してみました。 #include <stdio.h> #include <string.h> int main(void) { char string[]="XYZ1231ABC"; int i; printf("%s\n", string); putchar('\n'); printf("%s\n", strtok(string, "1A")); printf("%s\n", strtok(NULL, "1A")); printf("%s\n", strtok(NULL, "1A")); printf("%s\n", strtok(NULL, "1A")); putchar('\n'); for(i=0; i<=10; i++) printf("string[%d]=%c\n", i, string[i]); return 0; } 結果 XYZ1231ABC XYZ 23 BC (null) string[0]=X string[1]=Y string[2]=Z string[3]= string[4]=2 string[5]=3 string[6]= string[7]=A string[8]=B string[9]=C string[10]= 私が思うには、string[7]は空文字に置き換わってしまうはずだと思うんですが、 結果は'A'のままです。 ここが '¥0'に置き換わるかどうかは しょり系によって異なるのでしょうか。