• ベストアンサー

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'に置き換わるかどうかは しょり系によって異なるのでしょうか。

noname#2823
noname#2823

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

  • ベストアンサー
  • muyoshid
  • ベストアンサー率72% (230/318)
回答No.1

こんにちわ。 strtok 関数の動作についてですが、kmu_0031 さんの確認された結果で 全く問題ないと思います。 strtok は文字列を区切り文字で分割して、分割されたトークンのアドレス を返すだけですので、連続した区切り文字を見つけた時に全てをNULL文字に 置き換えるかどうかについてはライブラリの実装に任されている筈です。 実装がライブラリに任されている場合、極力効率良く (処理が軽くなるように) 実装されている筈です。 (余計な事をして性能を劣化させないように) 今回の場合、string[7] にNULL文字をセットしても、しなくても3回目の 呼び出しで"BC" へのポインタを返していますので、strtok の処理としては 全く問題がないと言えます。

noname#2823
質問者

お礼

>strtok は文字列を区切り文字で分割して、分割されたトークンのアドレス >を返すだけですので、連続した区切り文字を見つけた時に全てをNULL文字に >置き換えるかどうかについてはライブラリの実装に任されている筈です。 おっしゃることわかります。私が質問したことはstrtokの本質とは關係なさそうですね。 ありがとうございました。

その他の回答 (1)

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.2

strtokは伝統的な(=Ritchie-C,Jhonson-C)C文字列ライブラリ(string)ではなく、White Smith-Cという方言色の強い処理系で実装されていた関数です。 White Smith-Cの独自関数はANSI-Cでほとんど駆逐されてしまったのですが、stringにstrtokやstrspnなどが残っています。 ってことで、strtokの挙動はPortable C Compiler(pcc)ライブラリから派生した他のANSI-Cライブラリ関数とは異質なことが多いようです。 (pccはポータビリティ確保のためトリッキーな内部処理を極力避けているため) で実装ですが、「インターフェース仕様がANSI-Cに適合していれば内部処理に関しては実装依存でかまわない」というのが実情です。 その他にmemoryなどのライブラリも実装依存です。 mallocやstdioなんかはOS依存部分を多く含むため「内部処理の挙動を想定してはいけない」というのが一般的な見解でしょう。

noname#2823
質問者

お礼

ご回答ありがとうございます。 どうも難しい話はよくわからないですが、 問題ないということですね。

関連するQ&A

  • 次のソースの使い方(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)◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆ となりました。

  • 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); }

  • 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関数の使い方がおかしいと思うのですが ご教授して頂けたら幸いです。

  • strtok

    strtokの問題というよりも、文字列とポインターの考え方がまだちゃんと分かってないせいだとは思うんですが、strtok()のところで、Access Violationとでます。すごく単純そうな問題だとは思いますが、教えてください。お願いします。 #include <iostream.h> #include <string.h> int main() { char *chk = "3453/5252"; char *tokenPtr; tokenPtr = strtok(chk, "/"); while (tokenPtr != NULL) { tokenPtr = strtok(NULL, "/"); } return 0; }

  • 長い文字列を配列に入れるには?

    VBから長い文字列を送って,c言語で受け取りたいのですが,うまく配列に入れることが出来ません.文字列サイズは最低でも4000バイト必要です. #include <stdio.h> #include <stdlib.h> #include <string.h> //VBから送られてくるデータ char getch[4000]="start1T\tpose 0 0 -5 0 -5 0 -5 0 -5 0 0 0 0 0\ ..省略.. 25\t\n"; void main(void){ char *token; char seps[]="\t\n"; FILE *pose; pose=fopen("pose.txt","a"); if((token=strtok(getch,"\t"))==NULL){ printf("Error File1\n"); exit(1); } printf("%s\n",token); while(strcmp(token,"\n")!=0){ token=strtok(NULL,"\t"); fputs(token,pose); fputs("\n",pose); printf("%s\n",token); } fclose(pose); }

  • strtokを使用したループ内でのstrtok

    お世話になっております。 現在C言語で下記のようなstrtokを使用したプログラムを作成しております。 (関係なさそうな箇所については省略しております。) 【ソース】 str="abc.def,ghi.jkl,mnopq.r,kkk.bbb" for( a=strtok(str,",\n") , a , a=strtok(NULL,",\n"){ b=strtok(a,"."); c=strtok(NULL,"."): } 【質問内容】 上記の内容を使用したソースでは、for文のa=strtok(NULL,",\n")にてaに値がはいりません。 (2回目のループに行かない) 上記のような処理を実施したい場合、皆様どのようなソースを作成しているかご教示いただけないでしょうか。 よろしくお願いいたします。

  • reallocとstrtokの併用について

    fscanfで文字列を読み込み、strtokでカンマ区切りにするという関数を作りたいのですが、 reallocすると先頭から徐々にデータが文字化けしていきます。 まず最初に4つ分のchar*を取ります。 もし、5つ目が見つかったらさらに4つ増やし、9つ目が見つかったらさらに。。。というようになっております。 n個目の判定はcntがn-1で真になり、reallocが成功したら個数を増やすようになってます。 5つ目が見つかった時点では出力に問題は無いのですが、6個目から侵食が始まっていきます。 原因がどうしても自分では分からなかったので、誰かお願い致します。 words.txtの内容(末尾改行なし) iii,jjj,kkkkkkkkk,l,m,n,ooooo,pppppppp,a,s,d,f,g main.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include"C:\borland\bcc55\Include\malloc.h" int readlinefile(FILE *fp,char **words){ int cnt=0,len; char *line=(char *)malloc(256); char *tmp; if(line==NULL) return 0; if(fscanf(fp,"%s",line)!=EOF){ if((tmp=(char *)realloc(line,sizeof(char)*(strlen(line)+1)))==NULL){//できるだけメモリを節約してみる return 0; }else{ line=tmp; } len=strlen(line); printf("line:%d:%d:%s\n",len,_msize(line),line); if(len>1){//ファイル終端の改行を排除 int i; char *tok=strtok(line,",");//カンマで区切ったアドレスを得る while(tok){ if(cnt==0)printf("tok:1st:%x\n",tok); if(cnt>3&&cnt%4==0){//サイズが足りなくなった時 char **tmp2; if((tmp2=(char **)realloc(words,sizeof(char *)*(4+4*(cnt%4))))==NULL){ printf("words realloc ERROR\n"); break; }else{ printf("realloc\n"); words=tmp2;//reallocを適用 } } words[cnt]=tok; if(cnt){ printf("line(func)"); for(i=0;i<len+1;i++){ printf("%c",words[0][i]); } printf("\n"); } tok=strtok(NULL,","); printf("words[%d]:%x:%s\n",cnt,words[cnt],words[cnt]); printf("\n"); printf("tok:%d回目:%x\n",cnt+1,tok); cnt++; } return cnt;//正常終了した }else{ free(line); } } return 0; } int main(){ FILE *fp=fopen("words.txt","r"); if(fp){ int cnt=1; while(cnt){ int i; char **words=(char **)malloc(sizeof(char *)*4); words[0]=NULL; cnt=readlinefile(fp,words); printf("mainに戻りました\n"); if(cnt) printf("words:%d\n",cnt); for(i=0;i<cnt;i++){ printf("words[%d]:%x:%s\n",i,words[i],words[i]); } free(words[0]); words[0]=NULL; printf("\n"); free(words); } }else{ printf("file open ERROR\n"); } return 0; } 実行結果 なぜかコピペできないので実行するか斧でダウンロードお願いします。 http://www1.axfc.net/u/3352789.txt 全てまとめたもの http://www1.axfc.net/u/3352796.zip

  • 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関数を使用すると 不要な空白を取り出しているようである 知っている方がおりましたら、教えて下さい。

  • 教えていただけませんか?C言語 文字列について

    学校で文字列のプログラムを組む課題が出ました 以下のような課題です 1つの文字列を読み込んで,ピリオドで改行し出力するプログラムを作成しろ ・読み込む文字列の長さ 最大で80文字 ・文字列の終わりは必ずピリオドで ・文字列の途中に現れるピリオドの次には必ずスペースが続く ・ピリオドに続くスペースは出力しない 例えば Hello. It is fine. Good-bye.  と打つと Hello. It is fine. Good-bye. と表示されるようなプログラムです そして自分で以下のプログラムを組みました ----------------------------------------------------------- #include <stdio.h> #include <string.h> int main(void){ int i; char A[100]; char *a; fgets(A,80,stdin); a = strtok(A, "."); printf("%s.\n",a); while(a != NULL){ a = strtok(NULL,"."); if (a != NULL){ printf("%s.\n",a); } } return 0; } --------------------------------------------------------------- ですがこれだとピリオドの後のスペースと文字列の後によくわからない改行が出力されてしまいます 自分で何とかするべきなのでしょうがどうにもうまく行きません どこをどうすればいいのか教えていただけないでしょうか?