char型の変数の扱いで悩んでいます。
具体的には以下の二つのプログラムの差異についてです。
----------------------
char c;
scanf("%c", &c);
printf("%c\n", c);
-----------------------
char c;
scanf("%s", &c);
printf("%s\n", &c);
-----------------------
上のプログラムは正しいと思うのですが、下のプログラムが正しいのかどうか、わかる方に教えていただきたいと思い質問させていただきました。
どちらのプログラムも問題なく動作します。
僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。
scanf("%s", &c) は入力された文字のうち、終端文字の手前までの文字を引数のポインタが示すオブジェクトへ順に格納していく関数だと理解しているので、入力された文字が一文字だった場合、&cの示すオブジェクトに文字が代入されると考えたからです。
逆に printf("%s", &c) は、&cの示すオブジェクトから”ヌル文字”の手前までの文字列を順に表示する関数だと理解しているので、問題なく動作しているのは&cで示されるオブジェクトの後ろの領域が偶然'\0'だったからではないかと考えたからです。
何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。
僕の考え方がどの程度正しくて、正確にはどうなのかを教えて欲しいです。
ちなみに、
-----------------------
char c;
char str[100];
scanf("%s", str);
scanf("%c", &c);
------------------------
と書くと c には改行文字が代入されてしまいます。
scanf("%s", str);
において"aasssdd "と最後に空白を入れると
c には空白文字が代入されます。
しかし、
--------------------------
char str1[100];
char str2[100];
scanf("%s", str1);
scanf("%s", str2);
--------------------------
においては、
scanf("%s", str1);
で "asdfg "と最後に空白を入れても次のstr2が空白で始まることはありません。
この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。
おそらく、
scanf("%s", str);
の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。
分かる方がいましたら回答をよろしくお願いします。
No.1ベストアンサー
- 回答日時:
> char c;
> scanf("%s", &c);
char c では1文字分の領域しか確保されていないので、
1文字以上の文字列を無理矢理格納すると
他のデータが存在しているかもしれない領域を書き換えてしまいます。(メモリ破壊)
なお、'\0'はscanfが(本来書き込んではいけない領域に対してですが)書き込んでいます。
> と書くと c には改行文字が代入されてしまいます。
最初のscanfが改行文字を読み込んでいないからです。
以下のページに書かれている内容と本質的には同じ。
http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-
> 最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。
そう考えて問題ないと思います。
No.4
- 回答日時:
いろいろと回答が出ていますが、一応。
----------------------
char c;
scanf("%c", &c);
printf("%c\n", c);
-----------------------
これはscanfの「指定した文字だけを読み込む」という
仕様から正しいプログラムです。
文字は文字列でないため、'\0'はありません。
但し、Enterなどで入力された改行文字が入力ストリームに残ります。
-----------------------
char c;
scanf("%s", &c);
printf("%s\n", &c);
-----------------------
これは文字列を読み込む時、領域の無い部分へ
書き込みを行うため誤ったプログラムです。
やってはいけません。
>何かの本で、未使用の領域は0である確率が高いという記述を
>みたことがあり、'\0'は0と同じだということなので
>問題なく動作する率が高いのではないかと思っています。
そもそも、確率なんていってる時点でダメダメですね。
スタティック変数などは定義された時初期化が保障されていますが、
ローカル変数などは初期化保障されていません。
-----------------------
char c;
char str[100];
scanf("%s", str);
scanf("%c", &c);
------------------------
>と書くと c には改行文字が代入されてしまいます。
上で書いたように、指定されず読み込まれなかったものは、
Enterなどで入力された改行文字が標準入力に残ります。
>"aasssdd "と最後に空白を入れると
>c には空白文字が代入されます。
>"asdfg "と最後に空白を入れても
>次のstr2が空白で始まることはありません。
これは上で少し述べましたが、矛盾した入力文字は読まれないまま
入力ストリーム上に残り入力中で後続し(改行文字を含む)
空白類は、指令に照合しない限り読み込まれないまま残る。
というscanfの指定子集合の仕様のためです。
scanfは多くの場合、バッファオーバーフローを起こすと言われますが、入力文字数の制限などは可能です。
詳細な回答ありがとうございます。
入力ストリームという概念とscanf関数の知識が足りなかったのだと分かりました。これからの学習に役立てていこうと思います。
No.3
- 回答日時:
誤----------------------------
char c;
scanf("%s", &c);
printf("%s\n", &c);
誤----------------------------
例に上げられている後のプログラムは間違いです。たまたま正しく動いているように見えるだけです。
%sはNull終了の文字列を扱うので、通常は以下のように書きます。
正----------------------------
char str[100];
scanf("%s", str); // strは配列の先頭を示すアドレス
printf("%s\n", str);
正----------------------------
なお、scanfは、本当に「ちょっとお試しで入力」という「お勉強用」関数と考えたほうがいいですね。バッファオーバーフロー攻撃ってのもありますし。
質問者さんは、不可解な動作で悩まれていますが、その問題の原因が判ったとしても、使いにくいのは変わらないと思います。私は深く追求していません。scanf関数は通常は使いませんので。
その手の入力が必要な場合は、fgetsなどの1行単位で文字列入力を受け取ったあとに、sscanfで入力された文字列から、個々のデータを切り出すやり方を使っています。このほうがエラー検出も容易だし、使いやすいからです。
それから、蛇足ですが・・・.
C言語で、それなりに、まともに使える入力ルーチンを作ると、カーソル処理とか漢字対応や編集処理なども含めて、いろんな知識が必要で、コードも500行以上になる可能性があります。
最近はフォーム画面を使うので、画面処理もある意味で楽なんですが、エスケープコードを使ってCUI画面で入力処理するプログラムを作ると、結構勉強になります。ただし、あまり参考になる書籍が無い気がします。linuxのGNUライブラリにある1行入力ルーチン(たぶんあると思う)が見本になると思います。
No.2
- 回答日時:
>僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。
どちらも間違っています。
1文字入力して、Enterキーで確定したとしても、最低でもchar型の配列が必要です。charで2つは必要。
「文字列」ですから、'\0'も書き込みます。
ちなみに、このままでは何百文字だろうと入力可能です。
無論、その後の動作は保証できませんが。
> 何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。
そんな保証はないかと思いますが…
Cの規格書読んだわけではないので断言しかねますけど。
> この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。
> おそらく、
> scanf("%s", str);
> の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。
標準ライブラリの仕様書を確認する必要があるかと思いますが…
"%s"がホワイトスペース(半角空白、水平タブ、改行)を読み飛ばす仕様になっているからではないかと。
# scanf()使わないのでなんとも…
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
許せない心理テスト
私は「あなたの目の前にケーキがあります。ろうそくは何本刺さっていますか」と言われ「12本」と答えたら…
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
文字列から空白を取り除きたいのですが
C言語・C++・C#
-
関数から配列を返すには?
C言語・C++・C#
-
改行を読み飛ばす
C言語・C++・C#
-
-
4
nullと"、\\0とEOFの違いについて。
C言語・C++・C#
-
5
Enterキーを押されたら次の処理に移るという事をしたい。
C言語・C++・C#
-
6
UpdateData( FALSE); による文字列データの表示更新(VC++6.0)
C言語・C++・C#
-
7
CStringの文字列検索&抜き出しについて
C言語・C++・C#
-
8
C言語のポインターに関する警告
C言語・C++・C#
-
9
0xffffとは?
C言語・C++・C#
-
10
静的でないメンバ関数の呼び出しが正しくありません
C言語・C++・C#
-
11
配列を使わずに、変数名を動的にループで回したい
C言語・C++・C#
-
12
C言語についてです 5人のテストの点数を入力すると 合計点、平均点、最高点、最低点を 出力するプログ
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringのFindで文字列検索を行...
-
fgetsで拾われる改行文字を削除...
-
charと%c , %s の関係について
-
文字列の途中に「0」がある場...
-
itoaわかりません
-
C言語のステップ数をカウントす...
-
反転した数値を表示させるやり方
-
ブランクのチェック
-
str[j++]の意味
-
CStringについて
-
c言語について array[i]-‘0’ こ...
-
C言語で右シングルクオートがう...
-
2÷3などの余りについて
-
「指定されたキャストは有効で...
-
Enterキーを押されたら次の処理...
-
「Aに対するBの割合」と「Aに対...
-
ある商品のロス率を5%見込み、...
-
C言語でセルオートマトンを作成...
-
Aの値からBの値を除するとは??
-
マイナスからプラスへ転じた時...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
sscanfとscanfの違いがよくわか...
-
CStringのFindで文字列検索を行...
-
fgets関数を使用したときの文字...
-
charと%c , %s の関係について
-
Cで「大文字、小文字の判定」は...
-
itoaわかりません
-
C言語のステップ数をカウントす...
-
文の意味
-
C言語で16進数文字列から16進数...
-
単語数のカウントについて
-
反転した数値を表示させるやり方
-
C言語 空白の行(改行のみ)が...
-
strstrを利用しない文字列検索...
-
fgetsで拾われる改行文字を削除...
-
C言語の課題です
-
[Java]文字列分割
-
教えていただけませんか?C言語...
-
ある文字列で2回目3回目に出現...
-
文字列の途中に「0」がある場...
-
初歩的なプログラムなんですが...
おすすめ情報