プロトタイプ宣言と戻り値について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ゆーずぃ

プロトタイプ宣言と戻り値について

#1

投稿記事 by ゆーずぃ » 16年前

こんにちは。
以下のソースなのですが、どういったプロトタイプ宣言をしたら良いでしょうか?
それこそ覚えていないくらい(汗)の様々なパターンを試してみたのですが
どうやっても何かしらのエラーが出てしまいます。また、自作関数をmainの前に持ってくれば
プロトタイプ宣言が無いとの警告は出ますが無事にコンパイルできます。

他のint型系のプロトタイプ宣言は試行錯誤(一発ではできません;;)の後に
なんとか成功したのですが・・・
なんといいますか、プロトタイプ宣言の戻り値がいまいち理解できていません。
私の理解では、戻り値とは関数内で宣言したローカル変数をグローバルに使えるようにする
ものかなと思っています…。
なので、もし宜しければ戻り値の説明もお願いできませんでしょうか?

宜しくお願いいたします。

#include <stdio.h>
  char donaiyanen[20];
main(){
	SAKUHYOU("どないやねん");
return 0;}

  char SAKUHYOU(donaiyanen){
	printf("\n%s\n ENTERで終了",donaiyanen);
        getchar();
return 0;}

初級者

Re:プロトタイプ宣言と戻り値について

#2

投稿記事 by 初級者 » 16年前

#include <stdio.h>

void SAKUHYOU(char *s);

int main(void)
{
    SAKUHYOU("どないやねん");
    return 0;
}

void SAKUHYOU(char *s)
{
    printf("\n%s\n ENTERで終了", s);
    getchar();
}


今回は戻り値はありません。よってvoid。

たかぎ

Re:プロトタイプ宣言と戻り値について

#3

投稿記事 by たかぎ » 16年前

関数定義の側で関数原型(プロトタイプ)がありませんので...
char SAKUHYOU();
とせざるを得ないでしょう。
ただし、仮引数donaiyanenはint型として扱っていますので、int型とchar*型のサイズが異なる処理系では誤動作します。

理想的には、
char SAKUHYOU(const char*);

char SAKUHYOU(const char *donaiyanen)
{
  ...
}
と記述すべきです。

ゆーずぃ

Re:プロトタイプ宣言と戻り値について

#4

投稿記事 by ゆーずぃ » 16年前

>初級者様

早速の返信をありがとうございます。
二つ程質問をさせて下さい。
*s を使っていますが、これは宣言する必要が無いのは何故でしょうか?
また、return 0はたしか正常終了という意味ですよね?なんとなくで関数の最後には入れなければならないものだと思っていたのですが、こちらでは省いていますね。試しにreturn 0;を入れてコンパイルしてみたらエラーになりました。これは当たり前のことなのでしょうが、ますます分からなくなってしまいました。もともとreturn 0;を入れる理由というのは何なのでしょうか?わかり辛い質問で申し訳ありませんが(質問をする私が良くわかっていないので;;)、ご教授願います。

>たかぎ様
こちらも早速の返信をありがとうございます。
三つほど質問をさせて下さい。
戻り値にchar型を使用していますが、初級者様はvoid型でいいとおっしゃっていました。char型を用いたのは私の元ソースを尊重して作成してくださったからでしょうか?そうではなく、たかぎ様のお考えでchar型を使用したのであれば、戻り値がcharとvoidで食い違う理由を教えて頂けませんでしょうか。
二つ目ですが、constは定数を書き換えられないようにするものですよね。もしこの関数を引数を変えて何度も使用するといった場合でもちゃんとそれぞれの引数が反映されるのでしょうか?
また、ここでconstを使う理由・メリットとは何でしょうか?
三つ目ですが、
>仮引数donaiyanenはint型として扱っていますので
とありますが、何故int型として扱われるのですか?何か暗黙のルール等があるのでしょうか?
宜しくお願いします。


>ご回答頂く皆様
なにぶん理解がいたっていませんもので、長々と質問をしてしまうかもしれませんが、お時間の許す限りでいいのでお付き合いください。宜しくお願いいたします。

non

Re:プロトタイプ宣言と戻り値について

#5

投稿記事 by non » 16年前

たかぎさんへ

>ただし、仮引数donaiyanenはint型として扱っていますので

型を省略した場合はintと判断されるのでしょうか?

たかぎ

Re:プロトタイプ宣言と戻り値について

#6

投稿記事 by たかぎ » 16年前

> 戻り値にchar型を使用していますが、初級者様はvoid型でいいとおっしゃっていました。char型を用いたのは私の元ソースを尊重して作成してくださったからでしょうか?そうではなく、たかぎ様のお考えでchar型を使用したのであれば、戻り値がcharとvoidで食い違う理由を教えて頂けませんでしょうか。

元がchar型だったからです。

> 二つ目ですが、constは定数を書き換えられないようにするものですよね。

ここでは、ポインタの参照先が更新不可になります。よって、文字列の内容を書き換えるような操作を禁止できます。

> もしこの関数を引数を変えて何度も使用するといった場合でもちゃんとそれぞれの引数が反映されるのでしょうか?

反映されます。

> また、ここでconstを使う理由・メリットとは何でしょうか?

例えば、文字列定数を渡した場合、実際には文字列の書き換えを行うことはできませんので、間違った操作をするとコンパイルエラーにすることができます。
間違った処理を記述したときには、実行時よりリンク時に、リンク時よりコンパイル時にエラーにしてしまう方が得策です。

> >仮引数donaiyanenはint型として扱っていますので
> とありますが、何故int型として扱われるのですか?何か暗黙のルール等があるのでしょうか?

すみません。これは不正確でした。
関数宣言子に(仮引数並びではなく)識別子並びがある場合、関数宣言子と関数本体の間に、識別子並びの描く識別子に対応した宣言が必要になります。
↓こんな感じに
char SAKUHYOU(donaiyanen)
  const char *donaiyanen;
{
  ...
}
通常、識別子並びだけでその後の宣言を省略した場合は勝手にint型とみなされる場合が多いのですが、正確には未定義の動作になるようです。

SCI

Re:プロトタイプ宣言と戻り値について

#7

投稿記事 by SCI » 16年前

ゆーずぃさん

>*s を使っていますが、これは宣言する必要が無いのは何故でしょうか?
プロトタイプで宣言する必要がないのはなぜか、という意味ですね?
プロトタイプ宣言では関数名と戻り値・引数の型を知らせているので、具体的にそこで使う変数名(仮引数名)
は必要の無い情報なんです。「関数定義」ではもちろん必要になりますけどね。
もちろん書いてもいいです。分かりやすいですし。

>また、return 0はたしか正常終了という意味ですよね?
はい、確かにそうなんですけど、C++言語規格で定められているのは「main関数は正常終了時にint値を返す」で、
慣習的(規格ではなかったような)に「プログラム(main)の正常終了時に0を返す」となっています。また、省略するとmainは0を返します。
ですから、自分で作った関数なんかは自分の好きなものを返していいんですよ。
例えば、atoi()なんて、ちゃんと処理ができたら10とか100とか返しますよね?

>戻り値にchar型
これはソースを最小限の変更にとどめただけだと思います。上で述べた通り、何か意図がない限り戻り値の型を固定する必然性はありません。

>ここでconstを使う理由・メリットとは何でしょうか?
「呼び出された先で値が変更されないようにする」というのが理由でしょうね。
SAKUHYOU("どないやねん")とした結果、「なんでやねん」と表示されたら困りますよね(笑)
仮引数にconst修飾子をつけると関数内部で値の書き換えができなくなります(コンパイルエラーになります)。
ただし、SAKUHYOU("あ")とかSAKUHYOU("い")とか、呼び出すときに渡す実引数は自由ですよ。

>何故int型として扱われるのですか?
C言語規格に「規定の実引数拡張」というのがあって、型情報のない実引数に対して整数なら汎整数拡張、
実数ならfloat→doubleに拡張される、というようなものがあったのですが、C++では未定義だったような・・・
C言語の場合、func()とfunc(void)は別物(前者は型関知なし)なのですが、C++では一緒だった気がします。
どっちにしろ、型が決定できるような関数なら、原則として型は省略しない方がいいでしょう。思わぬバグになってしまうので・・・

SCI

Re:プロトタイプ宣言と戻り値について

#8

投稿記事 by SCI » 16年前

盛大に被りました。私のは気にしないでやってください(笑)

初級者

Re:プロトタイプ宣言と戻り値について

#9

投稿記事 by 初級者 » 16年前

関数のプロトタイプ宣言、実引数、仮引数、戻り値について、
入門書を隅から隅まで読んでじゅうぶん理解してください。

ゆーずぃ

Re:プロトタイプ宣言と戻り値について

#10

投稿記事 by ゆーずぃ » 16年前

返信が遅くなり、申し訳ございませんでした。今しばらくお付き合い頂ければ幸いに思います。

>たかぎ様
大変分かりやすい回答をありがとうございました。これからもお世話になるかとは思いますが、宜しくお願い致します。

>SCI様
気にするなだなんて、滅相もございません!本当に有難うございます。
せっかくお越し頂いたので、もう少し私の質問地獄にお付き合い下さい(><;)笑

>>*s を使っていますが、これは宣言する必要が無いのは何故でしょうか?
という私の質問なのですが、これはプロトタイプ宣言時に、ということではなく*s に関係する変数の宣言自体が行われていないようでしたので、*sを使うにあたって*sという変数を宣言する必要は無いのかなと思ったのです。

次にreturn 0;についてなのですが、main関数は正常終了時に0を返すというのはわかりました。ですが、
>ですから、自分で作った関数なんかは自分の好きなものを返していいんですよ。
例えば、atoi()なんて、ちゃんと処理ができたら10とか100とか返しますよね?
とおっしゃっていましたが、

1.自分で作った関数に返した好きな数字は何に使われるのですか?好きに返したreturnの結果を何かで参照して使ったりするのでしょうか? それとも元々何の意味も持っていない為に、何事も無かったかのように消滅して終りなのでしょうか??

2.私の淡い知識では -1はEOFだと認識しておりましたが、それはmain関数に限ったことなのでしょうか?もし自作関数のテキトー戻り値に-1を入れても問題はないのですか?

3.atoi()についてなのですが、これはint型に変換する為の関数ですよね。int型に変換するだけなのに何故テキトーな戻り値が発生するのでしょうか?というか発生させるのは人の手で、ですか?それともヘッダ内の処理でテキトーな戻り値を自動的に発生させているということでしょうか?


その他については理解しました。勉強になります。
なんだかものすごい的外れなことばかり言って大変に恐縮ですが、お手すきの時間がございましたら宜しくお願い致します。

>初級者様
勉強不足で申し訳ございません。ですが、入門書だけではわからない実際の動作や、実戦時に使える知識が欲しかったものでこちらに質問させて頂きました。(とはいえこの様な初心者が100年早い!のですが^^;)
暖かい叱咤と、貴重なソースをありがとうございました。

SCI

Re:プロトタイプ宣言と戻り値について

#11

投稿記事 by SCI » 16年前

なるほど、つまり
void SAKUHYOU(char *s)
{
    printf("\n%s\n ENTERで終了", s);
    getchar();
}
このとき、「なぜsが使えるか」ということですね?
宣言していないように見えるかもしれませんが、SAKUHYOU(char *s)で宣言されています。

>1.
自分で使いたいように使えばいいです。必要ないなら返さなくてもいい。
例えば、「失敗したら-1、成功したら0」というように「自分で決めておく」と、関数が成功したか失敗したか呼び出し元で知ることができますよね。

>2.
EOFも、fgetsとかfreadの仕様として組み込まれているだけです。これはmain関数とは関係のないことですね。
もちろん、自作関数が-1を返したって全然問題ないです。

>3.
テキトーというか、この例を出したのは「正常終了は0を返す」という文の否定として挙げただけです。
内部でテキトーな数値が作られているわけではありません。


「関数」や「戻り値」について調べてみてはいかがでしょう?

BEMANI

Re:プロトタイプ宣言と戻り値について

#12

投稿記事 by BEMANI » 16年前

例えば、ゆーずぃさんが、
整数だけしか計算出来ないとある友達に「1+1は?」と聞いたとます。
その友達は計算した結果をゆーずぃさんに教えるということにします。
すると、とある友達は「2だよ」と答えました。


ここで、関数は「とある友達」という事になります。
関数とはプログラム中に呼べば「何かしらの動作をする」ものですよね。

この場合ですと、とある友達(関数)が「1+1という計算をした」ということになります。
しかし、整数だけしか計算できない友達ですので「1.5+3.2は?」
のような小数計算をさせようとすると「型が違います」と怒られます。
小数を計算する用の友達(関数)が必要になるわけです。


そして引数はゆーずぃさんが、とある友達に「1+1は?」と聞いた時に出た数字のことですよね。
とある友達に、引数を二つ渡しています。(1と1)
今は小数を使わず整数ですので、整数ですよという意味のint型であったりと
型とは、そういった感じで使っていきます。


最後に戻り値ですが、とある友達が「2だよ」と答えました。
それが戻り値です。
とある友達(関数)から足し算の答えが返ってきた(戻り値)というだけです。
この答えをどう使うかは、関数を作った本人が一番理解していると思うので、
判断して使っていきましょう。

しかし、その友達がゆーずぃさんに答えを教えなかったとします。
すると、「戻り値がありません」と怒られます。
つまり、returnを書いていないからということです。

また、その友達が「2.0だよ」と小数で答えた場合、
「戻り値の型が違います」と怒られます。
関数を作るときは、型を揃えるよう気を付けてください。



流れとしては、
・何か処理したい。(関数を呼ぶ・関数を自分で作る)
・その為にはどうしたらいいでしょうか(引数がいるのかどうか)
・型があっているのか。
・その関数で得た結果を返してもらいたいのか(戻り値がいるかどうか)
という感じで考えればいいかなーと思います。


書き方としては、
戻り値 関数名(引数1、引数2)というのが基本ですので
よく見かける void main(void)は
戻り値なし、mainという名前の関数、引数なし
という意味になります。

int main(void)となると
戻り値int型、mainという名前の関数、引数なし
ということですので、この場合mainの最後に return で整数を返して下さい。
そうしないと、「戻り値はint型と言っているのに、何も返していない」と怒られます。

長くなりましたけど、最初に使う関数・引数・戻り値のイメージはこんな感じです。
(あくまでイメージとしてとらえてくださいね;)

ゆーずぃ

Re:プロトタイプ宣言と戻り値について

#13

投稿記事 by ゆーずぃ » 16年前

SCI様、BEMANI様

有り難いコメントを頂いたにもかかわらず、返信が遅れまして申し訳ありませんでした。

大変勉強になりました。SCI様が言われたように色々と自分でも調べてみましたが、まだまだ戻り値は奥が深そうです。ですが、皆様のお陰で靄が晴れた気分です。本当にありがとうございました。これからも様々な処で壁に突き当り、皆様にご迷惑をお掛けするかもしれませんが、その際は何卒宜しくお願い致します。

ゆーずぃ

Re:プロトタイプ宣言と戻り値について

#14

投稿記事 by ゆーずぃ » 16年前

チェックをつけ忘れましたが、これにて解決とさせていただきます。本当に有難うございました。

閉鎖

“C言語何でも質問掲示板” へ戻る