• ベストアンサー

atoiについての疑問

いつもお世話になっております。 またしても、教えていただきたい事がありまして質問させていただきます。 年月を『YYYY/MM/DD』形式で入力するプログラムで、『YYYY/MM/DD』形式以外の形式や暦として不正な値を入力すると、再度入力を促すプログラムを作成しています。 そこで、「strtok関数」を使い"/"で区切った文字列を「atoi関数」で数値にしようと思いました。(この方法で良いかは分からないのですが、他の方法が思い浮かばなかったので…) そこで、以下のようなプログラムを作ってみたのですが、結果を表示すると、なぜか最後の数字が1文字消えてしまいます。 ↓このようなソースを作りました。 【作ったソース】 #include<stdio.h> #include<stdlib.h> #include<string.h> void manth_view(void) { char nengetu[30],*syear; int year,manth; printf("年月を入力して下さい。>>"); fgets(nengetu,sizeof(nengetu),stdin); syear = strtok(nengetu,"/"); year = atoi(syear); printf("入力された年 %d\n",year); manth=atoi(strtok(NULL,"/")); printf("入力された月 %d\n",manth); } 【結果】入力した年月→2007/12  入力された年 200  入力された月 1 上記の結果のように、どのように入力しても、最後の1文字が消えてしまいます。 何故なのか昨日からずっと考えているのですが、分かりません。 どうか教えてください。

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

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

strtokもそうですが、atoiもあまり使用が推奨される関数ではないような… void month_view(void) { char nengetu[30]; char *p, *stp; int year, month; printf("年月を入力して下さい。>>"); fgets(nengetu, sizeof(nengetu), stdin); p = nengetu; year = (int)strtol(p, &stp, 10); printf("入力された年 %d\n", year); if (*stp!='/') { fprintf(stderr, "区切り記号が変です(%c)\n", *stp); return; } p = ++stp; month = (int)strtol(stp, &stp, 10); printf("入力された月 %d\n",month); } #1の方のstrstrを使ったやり方はstrtolだけでできますよ。

empuru
質問者

お礼

empuru様 丁寧なご回答をありがとうございます!! #1の方もおっしゃっていたのですが、strtokだけではなくatoiもあまり使わない方が良いのですね。 またしても勉強不足ですが【strtol】知りませんでした・・・。 調べてみると、エラー(数字以外)のチェックもできるのですね。 これは大変便利ですね。 早速ソースを書き直してみます。 とても勉強になりました! どうもありがとうございました。

その他の回答 (2)

  • FAY
  • ベストアンサー率49% (95/193)
回答No.2

WinXP上で動いているVC6.0のコンソールアプリケーションでは 示されたソースで正常に動作します。 他の原因があるのかも。

empuru
質問者

お礼

FAY様 説明足らずで申し訳ありません。 この部分だけを取り出すと動くのですが、関数としてmain関数などと共に動かすと、うまくいかないのです…。

  • yukimican
  • ベストアンサー率70% (112/159)
回答No.1

まず、strtokとatoiのどちらに問題があるのか切り分けましょう。 strtokの直後で、printfで戻り値を表示して確認してみてください。 この時点で文字列が切れていたら、strtokが悪いことになります。 おそらくstrtokの方に問題があるのだと思いますが、 strtokはたまに挙動が怪しいときがあるので、なるべく使わない方が良いです。 こういうときに良く使う方法は (a)sscanfを使う(正否は関数の戻り値で判定) (b)strstr()とポインタを使って、自前で文字列を分解する  (0) 文字列の先頭をポインタpStrにセット  (1) pStrの中から、strstr() で文字('/')を検索、結果をポインタpSepにセット    → pSepがNULLだったらここで終了  (2) pSepが指している文字('/')を'\0'に置き換える  (3) pStrを atoi() で文字列→数値変換  (4) pSepの次のアドレスをpStrにセット    → pStrがNULLだったらここで終了  (5) (1)からもう1回

empuru
質問者

お礼

yukimican様 丁寧なご回答をありがとうございます。 教えていただいた通り、strtokの戻り値をprintfしてみたところ、文字列全体が表示できたことから、atoi関数の動きが悪いようです。以前はstrtokを使ったため、変な風になってしまったことがあるのですが、やはりstrtokは使わない方が良いのですね。 勉強不足でお恥ずかしいですが、【strstr()】を知りませんでした。 文字列から対象文字を検索できるのですね! ぜひ使ってみたいと思います! 本当にありがとうございました。