scanfの使い方を教えてください – プログラミング – Home

scanfの使い方を教えてください
 
通知
すべてクリア

scanfの使い方を教えてください


HAL
 HAL
(@HAL)
ゲスト
結合: 24年前
投稿: 67
Topic starter  

お世話になります、下記のようにコンソール画面からキー入力をscanf()で受け
ファイルに書き出したいのですが、int型のデータが期待した動作となりません
(1234と入力しても1234と書き出しできません)
プロジェクトのプロパティーから文字セットはマルチバイト文字を選択しています

また、scanf(%d%*c, &shurui);
ここでの抑制文字 *の意味なのですが、int型以外の文字を受け付けないように
するためという解釈で使っているのですが、この認識は正しいのでしょうか
自信がありません、間違っていたらご指摘願います。

以上よろしくお願いいたします。

VS2005 VC++ Express

#include <stdio.h>

void touroku(int shurui);

int main(void)

{
int shurui;
char kakunin;

printf(\n <<< 商品マスタ更新 >>>\n\n);
printf( 新規登録=1、追加登録=2 );
scanf(%d%*c, &shurui);
do {
touroku(shurui);
printf( 続けますか?(y/n) : );
scanf(%c%*c, &kakunin);
shurui = 2;
} while(kakunin == 'y' || kakunin == 'Y');

return 0;
}

void touroku(int shurui)
{
int temp, temp1;
typedef struct {
int code;
char hinmei[21];
int tanka;
} SHOHIN_M;

char kakunin;
FILE* fp;
SHOHIN_M srec;

printf(\n 1 商品コード(半角数字4桁) : );
scanf(%d%*c, &srec.code); // ここの文字がおかしくなる
temp = &srec.code;

printf( 2 商 品 名(全角10文字) : );
scanf(%s%*c, srec.hinmei);

printf( 3 単 価(半角数字8桁) : );
scanf(%d%*c, &srec.tanka); // ここの文字がおかしくなる
temp1 = &srec.tanka;

printf( 登録しますか?(y/n) : );
scanf(%c%*c, &kakunin);

if(kakunin == 'y' || kakunin == 'Y') {
if(shurui == 1) {
fp = fopen(shohin_m.txt, w);
} else {
fp = fopen(shohin_m.txt, a);
}
fwrite(&srec, sizeof(SHOHIN_M), 1, fp);
fclose(fp);
}
}


引用解決済
トピックタグ
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

実用に耐える強度で(操作性とかセキュリティホールとか) scanf を使うのは
上級者でも細心の注意が必要だったりするので、ここはあえて断言しておこう

scanf は使うな!
fgets + sscanf/strtol/strtod にしとけ!

char userinput[MAXINPUT];
fgets(userinput, MAXINPUT, stdin);
sscanf(userinput, %d, &shurui);

scanf は改行までを読み込む関数ではないので、期待通りに使うのは難しいのさ
fgets で改行までを読み込み sscanf や strtol で分解するのがいいぞ

それでもあえて scanf を使いたいのであれば解説しないわけでもないが・・・


返信引用
HAL
 HAL
(@HAL)
ゲスト
結合: 24年前
投稿: 67
Topic starter  

tetrapodさんお世話になります
>>scanf は使うな!
私も調べているうちにscanf関数って奥が深いなと感じたしだいです
デバッガーでキーボードから入力した値を追いかけると変数への代入は正しく行えていま
したが書き込みの部分でおかしくなっているもようです

下記ように書式付で書き込んでやると正しく書き込むことができたのですが
fprintf(fp, %d%s%d, srec.code, srec.hinmei, srec.tanka);

fp = fopen(shohin_m.txt, wb);
fwrite(&srec, sizeof(SHOHIN_M), 1, fp);
上記のようにバイナリ形式にシリアライズして書き込むにはどのようにしたらいいのでし
ょうか?


返信引用
wclrp ( 'o')
 wclrp ( 'o')
(@wclrp ( 'o'))
ゲスト
結合: 18年前
投稿: 287
 

>fwrite(&srec, sizeof(SHOHIN_M), 1, fp);
>上記のようにバイナリ形式にシリアライズして書き込むにはどのようにしたらいいのでし
>ょうか?

たぶん書き込みはできていると思う。
何か問題?

テキストエディタでは読めないよ。
たとえばhinmeiに5バイト分の文字が入っていても
この方法では21バイト分書き込みをするからね。

freadで読み込めば読み込めるよ。

俺的には構造体にパディングがあるかないかで動作変わるから気になるけど。


返信引用
wclrp ( 'o')
 wclrp ( 'o')
(@wclrp ( 'o'))
ゲスト
結合: 18年前
投稿: 287
 

>fprintf(fp, %d%s%d, srec.code, srec.hinmei, srec.tanka);

srec.hinmeiが数字で始まる名前だったり数字で終わるとしたら困らないないのぅ?
こういうのよくないよ。
まあ、例として書いているんだろうけど

当然scanfでの読み込みはどこまでがcodeでどこまでがhinmeiかわからない
ってか人間が見ても区別つかないし。

余談
俺的に考えて、テキスト形式にシリアライズするなら

商品名には,が含まれないというルールで
fprintf(fp, %d,%s,%d\n, srec.code, srec.hinmei, srec.tanka);

商品名に,が含まれる場合は
fprintf(fp, %d\t%s\t%d\n, srec.code, srec.hinmei, srec.tanka);

かな。


返信引用
Haru
 Haru
(@Haru)
ゲスト
結合: 24年前
投稿: 41
 

>> temp = &srec.code;
tempはint型だけどcodeのポインタいれるの??

>>fwrite(&srec, sizeof(SHOHIN_M), 1, fp);
構造体のパディングを無しというか1バイトにしておかないと、
読み込みの時に困るかも知れない。

>>scanfについて
scanfを使うなといわれるのは、書式に%dなど数値を取得した場合に
オーバーフロー(数値の表現範囲を超え桁あふれする場合)が防げないからです。
#多くの人はバッファオーバーラン(書き込みしてはいけない領域を上書きする場合)が
#防げないと思っている人が多いですが、そんなことはありませんので。

>>fgets(userinput, MAXINPUT, stdin);
>>sscanf(userinput, %d, &shurui);
sscanfとscanfに書式指定の仕様に差異は無かったはずなので、
これは無意味と思います。
上に書いたようなオーバーフローは防げないし、
セキュリティホールを克服したことにはなら無いかと。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

scanf(%d, &a); に対して a と入力しちゃうと無限ループしちゃいがちに対して
fgets+sscanf だと無限ループしませんな
# 既に書いたとおり scanf は改行までを読む関数ではない

integer overflow については御意 strto* を使うべきですな
buffer overflow については scanf のフォーマット文字の工夫で防げるけど
つい忘れがち=細心の注意が必要なので、やっぱり scanf は非推奨


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

scanfって関数はそれこそ入力する側は絶対に間違えないとか
入力チェックはいいからちょっとしたロジックテストがしたいだけ
とかそういう時に間に合わせに使うようなものと言うイメージが
あるので入力周りをきちんと作りたい時は使いませんねぇ。

その辺はすでにtetrapodさんが書かれている通り。
真面目に入力周りも作るのであれば、tetrapodさんが書かれている
ような方法を使ったほうが良いと思いますね。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました