- 締切済み
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を使わない方がいいのでしょうか?
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- chie65536(@chie65535)
- ベストアンサー率44% (8765/19890)
http://okwave.jp/qa5122320.html があっという間に締め切られたので、こちらに回答。 >\の所を_に変更したらバグりませんでした。ありがとうござました。 別の漢字でバグるようになっただけで、何の解決になってません。 「表」の代わりに「農」とか「廟」とか書いたらバグります。
- chie65536(@chie65535)
- ベストアンサー率44% (8765/19890)
>1,A,,数学で試したら >class_typeにA,,数学が入ってて >nameとsubjectには何も入ってませんでした。 それは if(!fgets(buf,1000,fp)) return 0; のあとに if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; p = (char *)malloc(strlen(buf) + 1); ってやってないからじゃないでしょうか? pの初期化とメモリ確保は何処行っちゃったんですか? http://okwave.jp/qa5087561.html のANo.6で提示した例題は「どこかが1行でも欠けたら動かない」ので、変に端折ったり処理を削っちゃダメです。 因みに、この質問のANo.2を投稿する前に「一部の項目を省略した場合の全パターン」を読み込ませて、正しく動いたのを検証・確認してから投稿してます。 正しく動かなかったのは「質問者さんが勝手に改変。省略して、動く物を動かなくしちゃったから」です。 因みに、当方は 1,A,田中,社会 ,B,鈴木,音楽 3,,佐藤,国語 ,,山田,算数 5,A,,社会 ,B,,音楽 7,,,国語 ,,,算数 9,A,田中, ,B,鈴木, 11,,佐藤, ,,山田, 13,A,, ,B,, 15,,, ,,, と言う「すべての省略パターンが出現するcsvファイル」を読ませて、正しく動いているのを確認してから投稿しています。 質問者さんが勝手に改変し、動いている状態の物を動かない状態にされて「動きません」って言われても困ります。自分が行った改変は自分で責任取って下さい。そこまで面倒見切れません。
- asuncion
- ベストアンサー率33% (2127/6289)
pが配列ではなくポインタであるときに、 strcpyはマズいのではないでしょうか。
- chie65536(@chie65535)
- ベストアンサー率44% (8765/19890)
strtokは「,,,」のような「連続したセパレータ文字」を「1つの固まり」として処理するので「,」も「,,」も「,,,」も区別出来ません。 前回の回答では「空欄は無い筈」という前提でサンプルを作成して回答しました。 空欄が存在する可能性があるなら「自前で文字列の終端記号の'\0'を埋めながら「,」の次の位置まで進めていく」と言う処理が必要です。 例えば、 strcpy(p, buf); number = strtok(p,","); class_type = strtok(NULL,","); name = strtok(NULL,","); subject = strtok(NULL,","); を strcpy(p,buf); number = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/ } class_type = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/ } name = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/ } subject = p; のように修正します。 こうすると、空欄があった場合、各変数はNULLにはならず「長さ0の文字列」になります。 従って、前回の回答の if(!DataPtr->class_type || !DataPtr->name || !DataPtr->subject) {/*カンマで4項目に区切れない*/ printf("項目が足りません。"); return -1; } の部分は無意味になります。これらがNULLになる事はありませんから。 なお、上記の処理では 1,A,山田 や 1,A などのように「カンマが3つ無い」と言う場合にエラーになりませんから、カンマが足りない時にエラーで中断する場合は、判定方法を変える必要があります。 もし 1,,山田,数学 や 1,A,山田, は「カンマが3つあるからOK」にして 1,A,山田 は「カンマが3つないからNG」にするのなら strcpy(p,buf); number = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/ return -1; } class_type = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/ return -1; } name = p; if (p[strcspn(p,",")] == ',') { p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/ p += strlen(p) + 1; /*pを「,の次」に進める*/ } else { printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/ return -1; } subject = p; というように変更します。
補足
1,A,,数学で試したら class_typeにA,,数学が入ってて nameとsubjectには何も入ってませんでした。
- Tacosan
- ベストアンサー率23% (3656/15482)
たぶん strtok を使わない方が簡単.
補足
問題文はstrtokを使っている流れを軽く載せただけで strtokってこういうのは無理なの?という話です。 コメントでこういう風に修正しようと言われたので 質問文の方はあまり気にしていませんでした。本文はちゃんと 省略せずなっていると思いますがそこまで検証していただいているなら どこかミスがあるのでしょう。見直してみます