• ベストアンサー

strtok()について

c言語にてstrtok()を使用しています。 以下の型をグローバル変数で宣言し、 (ヘッダ) typedef struct { char *pTmp; int len; } stAAA; (.cソース) stAAA stA; ある関数にてmalloc()によりstA.pTmpに動的に領域を割り当て、 "ABCDEFG:ABCDEFG:ABCDEFG:"という値を格納するとします。 その後他関数にてstA.pTmp内の":"をトークンとしstrtok()で 切り出す場合、stA.pTmpを切り出し後もアドレス移動させたく ないため strtok()使用関数にて以下のようにしたのですが・・・・ グローバル変数のアドレスが操作されてしまいます。 どうすればよいでしょうか?strtok()用にmalloc()する? int test(){ char *pTmp; char *pTok; pTmp = stA.pTmp; while ((pTok = strtok(pTmp, ":")) != NULL) { : : } }

  • sting
  • お礼率12% (35/274)

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

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

strtok()が元の文字列を変更するかどうかについては実装依存ですが、文字列は何らかの変更を受けると思ったほうがよいでしょう。 文字列を元のまま残しておく必要があるなら、退避しておく必要があります。

その他の回答 (1)

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.1

まず、strtok 関数の使い方について見直してみましょう。 strtok は、最初に文字列のポインタを与えて、2度目以降は NULLを与えます。 pTok = strtok (stA.pTmp, ":"); while (pTok != NULL) {   :  pTok = strtok (NULL, ":"); } stA.pTmpが操作されることはないはずです。

sting
質問者

お礼

while実行後にprintf文にてstA.pTmp内を参照すると ABCDEFGしか出力されなくなってしまいます。

関連するQ&A

  • strtokについて

    ただ今、C言語の勉強中のヨッピーともうします。 今回質問させていただきたいのは、strtokについてです。 時間を格納している文字列 char time[] = "2007:10:18:22:30:55";//年月日時間 から不要な「:」を抜き出す作業を行っています。 ただ、抜き出して表示するのではなく、別の変数に「:」を抜かした 文字列を代入させたいのです。 char kakunou[16];     //用意した変数に kakunouに"20071018223055" //「:」が入っていない日付を入れたい 自分で調べましたら、strtokやstrtokenという関数が使用したらいいのではないことが分かりました。 どうしたら、不要な文字を抜かして新しい変数に代入できるでしょうか? また、他にいい方法がありましたら、strtokを使用しなくても大丈夫です。 よろしくお願いいたします。

  • 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について

    strtokを使うにあって注意すべき点がしりたいのですが、 test1やtest2は書き換わるので、変わっては困る場合は あらかじめコピーしておくのは理解しましたが、 strtokをネストして使う場合、(1)で必ずNULLになります。 strtokはネストでは使えないのでしょうか? また、他に注意点があるのでしたら教えてください。 あと、C++では、strtokより便利なものはありますか? char test1[] = "111,222,333"; char test2[] = "333,222,111"; char *p, *q; int flag; p = strtok(test1, ","); while ( p != NULL ) { flag = 0; q = strtok(test2, ","); while ( q != NULL ) { if (0 == strcmp(p, q)) { flag = 1; break; } q = strtok( NULL, ","); } if (flag == 0) { return 1; } p = strtok( NULL, ","); // <------- (1)ここで必ずNULL }

  • 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を使わない方がいいのでしょうか?

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

  • strtokのしくみについて

    よろしくお願い致します。 strtokは以下のように使いますよね。 (と言っても今回初めて使うのですが) 1回目はstrを渡しているので自然ですが、2回目以降はNULLですよね。なのにどうしてstrを続けて分解するということが出来るのでしょうか? うまく説明できませんが、要はstrtokはどういうコードで実現されているのでしょうか? int main(void) { char str[] = "ABCD ef.1234.G"; char *tp; /* スペース.を区切りに文字列を抽出 */ tp = strtok( str, " ." ); puts( tp ); while ( tp != NULL ) { tp = strtok( NULL," ." ); if ( tp != NULL ) puts( tp ); } return 0; }

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • 基本的な領域確保の仕方について

    下記のような構造体が宣言されている場合、 A.c.e ←を配列扱いにし、 A.c.e[0].g.h ←を配列扱いにし、 A.c.e[0].g.h[0].iにデータを設定するには、 どのように領域を確保すれば良いのでしょうか? eee型はポインタ宣言のみされていて配列宣言されて いません。(Max10配列) typedef struct { int len; char *i; } hhh; typedef struct { int number; hhh *h; } ggg; typedef struct { fff f; ggg g; } eee; typedef struct { int number; eee *e; } ccc; typedef union { aaa a; bbb b; ccc c; ddd d; } A;

  • Visual Stdioで、C言語のプログラミングを勉強してるのですが

    Visual Stdioで、C言語のプログラミングを勉強してるのですが、 不明点があるため質問させて頂きます。 【前提条件】 ---------------------------------------------------- < TestHeader.h > typedef struct A { int (*a)(struct B* x, char* y, struct C** z); } A; ---------------------------------------------------- < TestSource.c > static int func(struct B* x, char* y, struct C** z) { return 0; } struct A D = { .a = func, }; ---------------------------------------------------- 上記の条件で、< main.c >を作成し、 main関数からfunc関数へ遷移するようにしたいです。 書籍などで調べたのですが、main関数の作成方法が分かりません。 ご教授のほど、よろしくお願いします。

専門家に質問してみよう