プログラミング初心者です。
よろしくお願いします。
C++を使っています。
早速なのですが、以下にプログラムを記載します。
◎1----------------------------------------
#include<stdio.h>
main()
{
char ss[256];
gets(ss);
puts(ss);
}
----------------------------------------
◎1を実行すると、「型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません」と表示されます。
参考書には、「戻り値のvoidがないと勝手に戻り値の関数をint型と解釈する。関数の宣言と定義が合わないとコンパイル時にエラーとなる」とあったのですが、
◎2-------------------------------------
#include<stdio.h>
int main()
{
char ss[256];
gets(ss);
puts(ss);
}
-------------------------------------
以上の◎2だと、なぜ実行出来るかよくわかりません。
本当に初心者的な質問ですいませんが、教えていただけると嬉しいです。
No.1
- 回答日時:
C++じゃなくって言語的にはCですよね?
ところで、◎1だと……「戻り値のvoidがないと勝手に戻り値の関数をint型と解釈する。関数の宣言と定義が合わないとコンパイル時にエラーとなる」の例としては適切じゃないんですが……。つまり、ここで言う「戻り値」が何なのか、そして「関数の宣言」と「定義」がどの部分指してるのか分かりづらい、って事ですよね(しかも、main関数で戻り値ってvoidにするのって推奨されてない、とか思うんですけど)。
つまり、
#include<stdio.h>
main()
{
char ss[256];
gets(ss); /*ここ*/
puts(ss); /*ここ*/
}
は別に「戻り値」として機能してるわけじゃないんです。これらは値を特に戻してない、のです。
注:これちょっとややこしいんですが、元々、工学的には「値を戻す」プログラムを「関数」と呼び、「値を戻さない」プログラムを手続き(プロシージャ)と呼ぶんです。例えばPascalなんかはそれなりに分けています。
一方、Cは「全てを関数」と呼ぶんですが、要するにvoid型の戻り値を持つ関数、ってのは工学的に言うと「関数」ではなくって「手続き」なんです。
また、main関数はそもそも「関数」として設計されるべきで、これをvoid型宣言して「手続き」として定義するべきではありません(コンパイラによっては「許してます」が、推奨されている書き方じゃない、と思います)。そしてmainの「戻り値」ってのは数学的に何かの意味がある数値ではなく、単にOSに「プログラムが正常実行出来たよ」「出来なかったよ」と教えるため「だけ」に存在します。
正確には次のように書くべき、でしょうね。
#include<stdio.h>
main()
{
char ss[256];
gets(ss);
puts(ss);
return 0;/*これが必要*/
}
この「return 0;」ってのがmain関数での「戻り値」になります。◎1のケースですと元々「return 0;」が省略されている、と考えられるんです。
と言う事は◎2がどうして実行されるのか、分かると思います。◎2が示しているコードは「本来は」次のようなものです。
#include<stdio.h>
int main()
{
char ss[256];
gets(ss);
puts(ss);
return 0;/*これが必要。型は「int」。*/
}
return 0;がある、とすれば型はintなんで、main関数のint宣言、と一致しますね。本当はこれが「正しい」書き方で、コンパイラによってはmain関数でint宣言した時点で、return 0;が「本当はある」んだ、って解釈してくれるのかもしれません。
いずれにせよ、mainでvoid宣言、なんてのはしちゃあダメだと思いますよ。
gets(ss);やputs(ss);という関数の戻り値がint型じゃないから、だめという感じですかね??
ちなみに、
-----------------------
#include<stdio.h>
main()
{
char ss[256];
gets(ss);
puts(ss);
return 0;
}
--------------------------
と書き直しても、やはり同じエラーが出ました。。
visual studio 2005を使っているのですが、ソースファイル名の拡張子をC++の「.cpp」から「.c」とし、Cとして使うように変更すれば、◎1は動きました。
main関数の戻り値や引数は複雑ですが、何となくですが理解できました。ありがとうございます。
No.2
- 回答日時:
参考書は C について説明しています
Cでは関数の戻り値の型を省略すると int と解釈されます
お使いのコンパイラが不明ですがソースファイルの拡張子を .cpp から .c にすれば C としてコンパイルされるかもしれません。
visual studio 2005を使っているのですが、ソースファイル名の拡張子をC++の「.cpp」から「.c」とし、Cとして使うように変更すれば、◎1は動きました。ありがとうございます。
C++は何か複雑ですね。。
No.4ベストアンサー
- 回答日時:
>gets(ss);やputs(ss);という関数の戻り値がint型じゃないから、だめという感じですかね??
この件は「関数の中で呼んでるgetsやputsは無関係」ですよ。
以下のそれぞれの書き方で、コンパイラがどういう反応をするか、確かめましょう。
まず、以下の1~4を「拡張子を.cpp」にして、C++としてコンパイルしてみましょう。
◎1
main()
{
}
◎2
int main()
{
}
◎3
main()
{
return 0;
}
◎4
int main()
{
return 0;
}
次に、上記の1~4を「拡張子を.c」にして、Cとしてコンパイルしてみましょう。
1、2の反応が「C++のとき」と「Cのとき」で違った筈です。
>◎1を実行すると、「型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません」と表示されます。
「mainの戻り値が何も書かれていないので、仮にint main()だと言う事にしますよ」と言っています。
>以上の◎2だと、なぜ実行出来るかよくわかりません。
C++では「intを返すmain関数の終りにreturn 0;って書いてなかったら、return 0;を勝手に付け足します」って言う「お約束」があるのです。
>visual studio 2005を使っているのですが、ソースファイル名の拡張子をC++の「.cpp」から「.c」とし、Cとして使うように変更すれば、◎1は動きました。ありがとうございます。
C++の場合、
main()
{
}
と書くと、コンパイルする時に「型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません」という警告が出て、勝手に
int main()
{
}
だということにされます。C++では、書き忘れを足してくれるのです。
そして「intを返すmain関数の終りにreturn 0;って書いてなかったら、return 0;を勝手に付け足します」と言うお約束があるので、勝手に
int main()
{
return 0;
}
だということにされます。C++では、書き忘れを足してくれるのです。
なので、Cとしてコンパイルしてしまうと、これらの書き忘れを足してくれなくなり、警告も出してくれなくなります。
つまり
>拡張子をC++の「.cpp」から「.c」とし、Cとして使うように変更すれば、◎1は動きました。
は間違いです。
Cとしてコンパイルすると、見た目には「警告も出ず、コンパイル出来てしまう」ので、ちゃんと動くと思いがちですが「ちゃんと動いてはいない」のです。
コンパイラは「書き忘れを足してくれない」し「警告も出さない」ので、main関数から「変な値」を返したままになっています。
main関数から返される値は「プログラムが正常終了したか、異常終了したかを、プログラムを起動した人に返す役目」があります。
例えば「バッチファイル」で、◎1をCとしてコンパイルしたプログラムを呼び出した場合、バッチファイルで「正常終了したのか異常終了したのか判らない」って事が起きます。
ネットで「バッチファイル ERRORLEVEL」で検索してみて下さい。検索したページを見れば「◎1をCとしてコンパイルしたプログラムは、マトモに動作してない」って事が判ります。
以下、とっても重要。
∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨
「コンパイラが警告を出さなくなったからと言って、そのプログラムがマトモに動くとは限らない」
∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
前回のリダイレクト指示の時と同様、わかりやすくご指導いただき大変参考になりました。
C++はエラーを見逃さず、促してくれるものだとわかりました。
最後に書かれている言葉は、本当に大事だと思います。
ありがとうございます。
試しにコマンドプロンプトから、C++の◎1をやってみたら、実行出来てしまうのは、何故かなと思いました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
<unistd.h>をVisualStudioでつ...
-
アプリケーションのDLLファイル...
-
C言語をコンパイルするとコンピ...
-
math.hに含まれる関数が使えない
-
実行ファイルが作成環境以外のP...
-
Visual Basic.NETの処理速度は6...
-
cygwinのgccで正常にコンパイル...
-
ビープ音が鳴りません・・・
-
<math.h>ヘッダを入力している...
-
#If True Then の # って何??
-
不明なプラグマ・・・?
-
define文のパラメータを実行時...
-
64ビットのlinuxで32ビットメモ...
-
ヘッダーファイル『windows.h』...
-
minGWでのopneMPコンパイルにつ...
-
gccでc++プログラムをコンパイ...
-
C言語をgccにコンパイルしよう...
-
Cygwinでのコンパイルができま...
-
C言語で作ったらWindowsでもMac...
-
[COBOL] ソースの復帰
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
<unistd.h>をVisualStudioでつ...
-
アプリケーションのDLLファイル...
-
C言語をコンパイルするとコンピ...
-
実行後にコンパイルに失敗しま...
-
math.hに含まれる関数が使えない
-
ビープ音が鳴りません・・・
-
c言語です コンパイルした時に...
-
<math.h>ヘッダを入力している...
-
C#で char型とstring型の比較で...
-
共有ライブラリの内容確認について
-
すべてのリビルド: 0 正常、 0 ...
-
[COBOL] ソースの復帰
-
64ビットのlinuxで32ビットメモ...
-
VS2010環境で2点ほど質問
-
gcc バージョン違いによるコン...
-
ヘッダーファイル『windows.h』...
-
C言語で作ったらWindowsでもMac...
-
自作DLLの中身を暗号化
-
MVSマシンで0C7でABENDしたので...
-
Verilog_HDLでのdefineとifdef
おすすめ情報