🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

539閲覧

変数についての謎の動作

oppeke

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

1グッド

0クリップ

投稿2019/12/18 15:02

編集2019/12/19 10:29

お世話になっています。
特に問題が出て困っているという訳ではないのですが、謎な現象が発生したので、何故このような動作になるのか、知りたい次第です。

以下のようなプログラムがあります。

C

1void main() 2{ 3 int i = 0; 4 5 if (i == 0) // ←---① 6 { 7 int test = 123; // ←---② 8 char str[] = "sss", i; // ←---③ 9 } 10}

上記のプログラムをデバッグで実行し、①の行にブレークポイントをつけて止めます。
iの中身は、その時はもちろん0です。
しかし、ステップオーバーを行い②の行に行くと、変数iがなぜかchar型に変わり(ウォッチの種類がcharになっています)、値が[-52'フ']に変更されます。

③の部分の記述が明らかにおかしいので、そこが悪さをしているのだとは分かるのですが(実際、,i の部分を消すとiの値は0となります)
②の行で止めているときはまだ③の行は実行されていないはずです。
なのに、if文に入ると何故iの値が変更されてしまうのでしょうか。

また、変数 = xxx,xxx;のような書き方は、どのような動作となるのでしょうか。
int a = 1,2
とすると、識別子が必要ですとエラーが出てビルドできません。
③の行がそもそも何故エラーとならないのかも分かりません。

また、①をfor文にしても同じ結果となりました。

実行環境はvisual studio 2017です。

初歩的な勘違いをしているかもしれませんが、よろしくお願いします。

rubato6809👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

(3)の行は、char型配列のstrと、char型のiを宣言してしまっています。

C

1char str[] = "sss"; 2char i;

これと同じ結果になるのかと思います。

そのため、ifの中に入った途端に、外のint iは使えなくなり、char iが有効になっているんだと思います。

投稿2019/12/18 15:40

segavvy

総合スコア1038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oppeke

2019/12/19 10:39

回答ありがとうございました! カンマ区切りにすると変数の宣言になってしまうんですね。
guest

0

ベストアンサー

ブロック内で、icharで宣言しているというのは他の人の回答の通りです。

宣言文は実行される文じゃないので、

②の行で止めているときはまだ③の行は実行されていないはずです。

の認識が間違っていると思われます。

また、変数 = xxx,xxx;のような書き方は、どのような動作となるのでしょうか。

型 宣言1, 宣言2;
は、
型 宣言1;
型 宣言2;
と同じです。

宣言文じゃなくて、

C

1int i; 2i=x,y;

のような場合は、,は「コンマ演算子」です。演算子の中で一番優先度が低いので、(i=x),yということになります。
この演算子を知らなかったのなら、学習してください。

参考:
CとC++の演算子 - Wikipedia
コンマ演算子 - Wikipedia

投稿2019/12/18 16:30

otn

総合スコア85890

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oppeke

2019/12/19 10:26

回答ありがとうございました! >>②の行で止めているときはまだ③の行は実行されていないはずです。 の部分が大きな間違いでした。変数を宣言していることになっていたため、char i の方を見ていたんですね。 また、コンマ演算子についてもありがとうございました。参考サイト見てみます。
guest

0

https://programming.pc-note.net/c/scope.html

一言で言うと、char...の行で変数を宣言することは、その文を含む「ブロックに入ったとき」(その文に差し掛かったときではない)に、そのブロック内でのみ通用する、(外側にあるiとは別の)char型変数iの領域を確保してください、という意味だからです。デバッガは、内側のブロックに入った時点で、char型のiに注目するよう切り替わったのです。

投稿2019/12/18 16:48

majiponi

総合スコア1722

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oppeke

2019/12/19 10:33

回答ありがとうございました! >> ブロックに入ったとき…char型変数iの領域を確保してください、という意味 そうなんですね。その行を通ったときに確保されるものだと思っていました。 大変参考になりました!
guest

0

良い質問です。はっきり言いましょう。
int i; と char i; は、同名「i」だけど、別の変数だから。もちろん割り当てられるメモリも違う。
証拠をお見せしましょう。i のメモリアドレスと値を表示させます。

C

1#include <stdio.h> 2void main() 3{ 4 int i = 0; 5 6 if (i == 0) { // ←---① 7 int test = 123; // ←---② 8 char str[] = "sss", i; // ←---③ 9 i = 'A'; 10 printf("%p: %d inner i\n", &i, i); 11 } 12 printf("%p: %d outer i\n", &i, i); 13}

私の手元の実行結果です。

C

1$ ./a.out 20x7ffcae6277c7: 65 inner i 30x7ffcae6277c8: 0 outer i

ほらね、アドレスが違う。コードブロックの内側で 'A' を代入したのに、外側が0のままなのは、別の変数だから。

内側の char str[] = "sss", i; は変数定義です。文法的に言うと実行文ではありません。これも注意が必要。で、この変数定義は2行に書くことができて、こう書くのと同じです。

C

1 char str[] = "sss"; 2 char i;

ここはコードブロックの中で、変数を定義すると新たな変数が作られる、そうご理解ください。重要なキーワードは変数のスコープです。majiponiさんの回答にリンクがあるので、ご覧あれ。

値が[-52'フ']に変更されます

質問者のコードは内側の i を定義しただけで値をセットしていません。不定値です。値が無いのではありませんよ、値が不定なだけ。だってメモリには何かの値があるのだから。普通、割り当てられたメモリに残っていた値が表示されるのだけど、この場合はデバッガがセットした値だそうです、コメントをお読みください。私的には不思議な表示ですが、文字化けのようなものかな。残っていた値は -52 = 0xCC である、これは半角カタカナの「フ」かもね、と表示したんだな。0xCC が int3(デバッグ割り込み)ということは、プログラムのバグで、ここを「実行」しちゃったらただちにデバッガに捉えられるという仕掛けなんですね。

投稿2019/12/18 23:39

編集2019/12/19 01:37
rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/12/19 01:16

Visual C++のデバッグモードだと、未初期化のローカル変数はひたすら0xCCで埋められ、文字列だと「フフフフ」のようになっています。 x86で0xCCはint3(デバッグ割り込み)なので、その加減での値と思われます。
rubato6809

2019/12/19 01:22

ほう! デバッガがセットしたんですか。完全に読みきった感じw
oppeke

2019/12/19 10:29

詳しく説明していただきありがとうございました! 変数のアドレスを表示して確認する方法は思いつきませんでした。 大変参考になりました。 >>maisumakunさん 補足いただきありがとうございます。 確かに正確には半角のフでした。 念の為修正しておきます。
guest

0

char str[] = "sss", i; ←この時点でiはchar型の変数です。

t2.c:8:29: warning: declaration shadows a local variable [-Wshadow] char str[] = "sss", i; // ←---③ ^ t2.c:3:9: note: previous declaration is here int i = 0; ^

投稿2019/12/18 15:39

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oppeke

2019/12/19 10:45

回答ありがとうございました! >>#ちなみにclangでは、以下のエラーが出ます。 確かにvs2017でも警告となっていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問