• ベストアンサー

戻り値について

プログラミング初心者です。 よろしくお願いします。 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だと、なぜ実行出来るかよくわかりません。 本当に初心者的な質問ですいませんが、教えていただけると嬉しいです。

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8519/19367)
回答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としてコンパイルしたプログラムは、マトモに動作してない」って事が判ります。 以下、とっても重要。 ∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨ 「コンパイラが警告を出さなくなったからと言って、そのプログラムがマトモに動くとは限らない」 ∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧

muffler
質問者

お礼

前回のリダイレクト指示の時と同様、わかりやすくご指導いただき大変参考になりました。 C++はエラーを見逃さず、促してくれるものだとわかりました。 最後に書かれている言葉は、本当に大事だと思います。 ありがとうございます。 試しにコマンドプロンプトから、C++の◎1をやってみたら、実行出来てしまうのは、何故かなと思いました。

その他の回答 (3)

noname#208124
noname#208124
回答No.3

int mainに限りreturnせずに最後まで実行された場合return 0;とする、というのが最新のC/C++規格では規定されています

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

参考書は C について説明しています Cでは関数の戻り値の型を省略すると int と解釈されます お使いのコンパイラが不明ですがソースファイルの拡張子を .cpp から .c にすれば C としてコンパイルされるかもしれません。

muffler
質問者

お礼

visual studio 2005を使っているのですが、ソースファイル名の拡張子をC++の「.cpp」から「.c」とし、Cとして使うように変更すれば、◎1は動きました。ありがとうございます。 C++は何か複雑ですね。。

回答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宣言、なんてのはしちゃあダメだと思いますよ。

muffler
質問者

お礼

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関数の戻り値や引数は複雑ですが、何となくですが理解できました。ありがとうございます。

関連するQ&A

  • int型とchar型について

    C言語初心者です。 よろしくお願いします。 ◎1----------------------- #include<stdio.h> int main(void) { int ss[4]="789"; printf("%c\n",ss[0]); return 0; } --------------------------- ◎2----------------------- #include<stdio.h> int main(void) { int *p; p="789"; printf("%c\n",*p); return 0; } --------------------------- ◎1、◎2の2つのプログラムについて疑問があります。 ◎1の「int ss[4]="789";」と◎2の「int *p;」のintの部分は今まで、何の疑問も抱かず、「char」として入力していました。 そこでchar型は1バイトの整数、int型は4バイトの整数ということで容量が違うだけで、intとしても大丈夫だろうと思ったのですが、 ◎1では、「'initializing' : 'char [4]' から 'int [4]' に変換することはできません。」とエラーが出て、◎2では「'char [4]' から 'int *' に変換することはできません。」とエラーが出ます。 intは文字列は扱えないということなのでしょうか? 以上intだと実行できない理由がわかりません。 初歩的なことですいませんが、教えていただけると嬉しいです。

  • 配列について

    初歩的な質問ですいませんが、質問よろしくお願いします。 ◎1----------------------------- #include<stdio.h> int main(void) { char ss[10]="AB"; printf("ss=%s\n",ss); return 0; } ------------------------------------ ◎2-------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss[0]='A'; ss[1]='B'; ss[2]=0; printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎3------------------------------- #include<stdio.h> #include<string.h> int main(void) { char ss[10]; strcpy(ss,"AB"); printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎4------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss="AB"; printf("ss=%s\n",ss); return 0; } ---------------------------------- 以上4つのプログラムで、◎2と◎3は正常に動くと理解できたのですが、何故、◎1は正常に動き、◎4は「'const char [3]' から 'char [10]' に変換できません。」といったようなエラーが出てしまうか分かりません。 教えていただければ嬉しいです。

  • 文字列ポインタとgets関数の関係について。

    以下のプログラムはコンパイルは出来ますが、 実行するとクラッシュしてしまいます。 gets関数は char *gets( char *str ); と定義されているので文字列の先頭アドレスを返すはずですが 何故このプログラムはエラーが出るのでしょうか・・。 #include <stdio.h> int main ( void ){  char *p, *s;  p = gets(s);  printf("%s", p);  return 0; }

  • scanf関数の戻り値について

    --------------------------------------- #include<stdio.h> int main(void) { int dt; while(scanf("%d",&dt)==1){ if(dt==0){ printf("0は入力しないでください\n"); puts(""); } else if(dt<0){ dt=-dt; printf("入力値の絶対値は「%d」です\n",dt); puts(""); } else{ printf("入力値の絶対値は「%d」です\n",dt); puts(""); } } return 0; } --------------------------------------- 以上のプログラムについて疑問があります。 scanf関数の戻り値が1の間、繰り返すというもので、入力の時に整数入力ですが、あえて実数である1.1を入れたとします。 scanfの戻り値は1で、dtには整数部の1だけ設定されていたので、これでもうまくいくのかと思ったのですが、次の入力はscanfの戻り値が0になっていて出来ませんでした。 何故0になっているのかわかりません。 入力バッファに何か残ってしまっているということなのでしょうか? 以上教えていただけると嬉しいです。

  • 複数の戻り値

    関数にポインタを渡して、結果を格納してもらう方法で 複数の戻り値を得ようとしたのですがうまく行きません どうしたら複数戻せますか? ---ソース--- #include <stdio.h> #include <stdlib.h> void check(int a,char *b,char *c); void main(void){ int a; char *b,*c; int i; char *va[5]={"2","3"}; for(i=0;i<5;i++){ //ここ何とかなったらwhileにしとこ if(va[i]!=NULL){ a=atoi(va[i]); check(a,b,c); printf("%s%s\n",b,c); } } } void check(int a,char *b,char *c){ switch(a){ case 0: b="0:×\n"; c="0:○\n"; break; case 1: b="1:×\n"; c="1:○\n"; break; case 2: b="2:×\n"; c="2:○\n"; break; case 3: b="3:×\n"; c="3:○\n"; break; case 4: b="4:×\n"; c="4:○\n"; break; } }

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

  • 配列やポインタに文字列を設定することについて

    ◎1------------------------- #include<stdio.h> int main(void) { char ss[80]; scanf("%s",ss); printf("%s\n",ss); return 0; } ---------------------------- ◎2--------------------------- #include<stdio.h> int main(void) { char *ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- ◎3---------------------- #include<stdio.h> int main(void) { char *ss; ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- 以上3つプログラムで疑問をいだいたのですが、 まず◎1で、これは例えば、 cahr ss[80]="abc"; のように配列ssに文字列"abc"そのものを入れているのか、 char *ss="xyz"; のようにまず"xyz"という文字列をメモリ上のどこかに設定し、その先頭番地をssに代入しているのか、どちらの考えでいいのかわかりません。 次に、◎2、3ではどちらも正常に実行できたのですが、特に◎3で「ss="abcde";」と記述していますが、ssにはアドレスを代入するという認識かあるのですが、文字列定数を代入しても問題ないのか?という疑問があります。 教えていただけたら嬉しいです。

  • このソースは間違っていますか?

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ #include<stdio.h> #include<stdlib.h> #define MAXLINE 256 int main(void); int main(void) { char buffer[MAXLINE]; int x; int y; char a; char b; printf("一人目の名前を英数字で入力してください。\n"); gets(buffer); a = at

  • 関数の戻り値がこうなる理由が分かりません。

    かなり簡単なプログラムだと思いますが、関数内で出力した場合と、呼び出し側で出力した場合で値が異なります。理由が分からないので教えていただけますか? #include <stdio.h> #include <stdlib.h> Table(int num, double ltable) { double temp[] = { 0.99852, // 1 0.99410, // 2 0.98677 // 3 }; ltable=temp[num]; printf("%f\n",ltable); } main (int argc, char *argv[]) { int num ; double ltable ; num=1; Table(num, ltable); printf("%f\n",ltable); } 実行結果 0.994100 0.000000

  • 戻り値について

    ただ今、c言語の勉強をしている者です。 本を読んでいて分からないところがあったので ご指導して頂ければと書き込みました。 それは、最初と最後のところです。 int main(void) { ・ ・ 処理 ・ ・ return 0; >int main(void) このintというのは 戻り値が整数だと言うことだと思うのですが 戻り値が文字の場合ということも あるということですか? 例えば、 char main(void) ということもあるのでしょうか? また、voidというのは 他の名前にしたらいけないのでしょうか? > return 0; というのは、 正常に終わったら戻り値を0にしろということですか? ご指導して頂ければと思います

専門家に質問してみよう