• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:【C言語】戻り値が構造体の関数)

【C言語】戻り値が構造体の関数

このQ&Aのポイント
  • C言語で構造体の戻り値を扱う関数について質問があります。
  • 特定の関数で構造体を返す際にエラーが発生し、正しい返り値の扱い方を知りたいです。
  • 関数名に存在する間接演算子についても疑問を持っています。

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.6

ポインタはややこしいですが、&や*が付いたらどんな型になるかを落ち着いて考えましょう。 > Person *bin_search( const Person *key) *がbin_search, keyに付いてますが、考え方としては 「Person *」を返す関数「bin_search」 「const Person *」型の引数「key」です。 とすると、 「&key」は「『const Person *』型へのポインタ(const Person **)」になるので、戻り値の「Person *」とは一致しません。それが > return from incompatible pointer type (互換性の無いポインタを返した)というエラーです。 「*key」は「『const Person *』型(= const Personへのポインタ)から参照される実体(const Person)」になるので、戻り値の「Person *」とは一致しません。そもそもポインタでは無いので、エラーメッセージも違っているはずです。 では、「key」はなにか、と言えば、「const Person(=変更できないPerson)へのポインタ」です。 戻り値は「Person(=変更もできるPerson)へのポインタ」なので「一致しません」 Person * → const Person *は暗黙の型変換が行われます。これは、参照先を読み書きできるように扱うか、読み込みのみで扱うかの違いなので、問題はありません。 しかし、逆はできません。 対処法は次のようなものがあります。それぞれに一長一短です。他の部分との組合せ等から、適切なものを選んでください。 ・戻り値をconst Person *にする。 ・引数をPerson *にする。 ・return時に Person *へキャストする。 > warning: function returns address of local variable これは別の話しです。 keyは、この関数が呼ばれたときに確保され、関数から戻ったら解放される「(関数内で自動の)ローカル変数」です。 &keyは、そのローカル変数のアドレスを示します。 そのローカル変数が解放されたら、その領域がどうなるかはわかりません。すぐに別の変数がその領域を使ってしまうかもしれません。 なので、「受け取ったアドレスが無意味になってるかもしれませんよ。大丈夫ですか?それを意図したプログラムですか?」という警告です。

stiyl
質問者

お礼

丁寧で細かい説明ありがとうございました。 おかげでプログロムは無事実行することが出来ました。

その他の回答 (11)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.12

bsearchそのものを実装する場合でも、 void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); なので、最後に結果をreturnするときには同じ問題に直面します。 今回の問題に関して言えば、 return (Person*)key; とするのが一番妥当です。 仮引数にはconstが付いているけれども、返却値にはconstがないのは、Cでは普通の仕様です。 bsearchだけでなく、strchr, strrchr, strstr, memchrなども同様です。 引数で指定した配列の内容を破壊しないことを保障する意味で仮引数にconstを付けているわけですが、実引数がconst修飾されているかどうかは関数側からはわかりません。 const修飾無しの返却値を返すことで、const修飾無しの変数でもconst修飾ありの変数でも結果を受けることができるようになります。

stiyl
質問者

お礼

丁寧で細かい説明ありがとうございました。 おかげでプログロムは無事実行することが出来ました。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.11

もちろん、そんな関数に意味があるとは私も思ってないです>#10 でも#2の補足を読む限りは質問者さんはそういう仕様を考えていらっしゃるようなので。 検索キーはnameだったりするんじゃないかなと。

stiyl
質問者

補足

質問内容には関係ないと思い省略したのですが、細かく表記するべきだったでしょうか。 実際に作る関数は Person *bin_search( const Person *key, const Person *base,         size_t nmemb,       int (*compar)(const Person *, const Person *) ) で宣言され、引数keyはキー値へのポインタ、baseは比較対象へのポインタ、nmembは探索対象となる配列要素数、comparは比較用関数へのポインタとし、 Person *p; で宣言したpに結果を代入するものです。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.10

よしんば「実際に検索をする」関数であっても, 「検索キーをそのまま返す」検索関数に意味があると思えないのです>#8. ふつうは「検索して見付けたもの」を返すのでは?

回答No.9

詳細な説明はほかの方がしてくれているので、別の意見を。 とりあえず、プロトタイプは Person *bin_search( const Person *key, Person *data, size_t num) でないとまずいんじゃないかな。 それとプロトタイプからconstを外すというのが一番よいと思いますが プロトタイプでconstをつけるのは関数の中で値を書き換えないことの 意思表示でもあるので検索系の関数だし、 constをつけたままにして return するときに(Person *)で キャストしてしまうとか、戻り値そのものを int にして、配列の番号を返す仕様に変更する案もありかと思います。

stiyl
質問者

お礼

課題として関数宣言は指定されているので、constは外せなかったんですよ…… 説明ありがとうございました。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.8

検索せずにキーをそのまま返す検索関数って意味あるの?

noname#208507
noname#208507
回答No.7

関数名の前に付いている * は、戻り値のデータ型の一部です。つまり、この関数の戻り値のデータ型は Person * です。 引数は const Person * なので、警告文  return discards qualifiers from pointer target type はデータ型に付いている const を、戻り値で捨てている点を警告しています。 (たぶん、使われているのは gcc でしょうか) 下のように探索結果を返せば警告は出なくなります。key の内容は変えない方が分かりやすいプログラムになるでしょう。戻り値を free() することを忘れないよう注意してください。 Person *bin_search( const Person *key) {   Person *value = malloc(sizeof(Person));   if (value != NULL) {     ... 二分探索で見つけた値を value にセット ...   }   return value; } 話はそれますが、「二分探索」が課題なのですね。がんばってください。二分探索はシンプルなのに正しく作ることが難しいことで知られています。(最初にアルゴリズムが発表されてから、バグのないプログラムが出版されるまでに16年もかかっている!) 「珠玉のプログラミング」(ジョン・ベントリー, ピアソンエデュケーション, 2000) 「C言語による最新アルゴリズム事典」(奥村晴彦, 技術評論社, 1991) などの書籍が参考になります。

stiyl
質問者

お礼

丁寧で細かい説明とエール、ありがとうございました。 おかげでプログロムは無事実行することが出来ました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.5

>Person *bin_search( const Person *key) bin_search関数の戻り値はPerson型へのポインターですね。よって、 >return (&key); // 戻り値の型はPerson **型 >return (*key); // 戻り値の型はPerson 型 これらが正しくないのはわかるのですが、 >return (key); これもダメでしたか? そのときのエラーメッセージは、どういう内容でしたか? # 関数ポインターという用語があることは間違いないが、このシチュエーションで使うものかどうかは微妙。

stiyl
質問者

補足

「return (key);」の場合、 return discards qualifiers from pointer target type という警告文が表示されました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

「関数ポインタ」ってなんでしょうか>#3.

  • DarkMoon
  • ベストアンサー率21% (225/1046)
回答No.3

*bin_search( const Person *key) 関数の前に*がついていると、関数ポインタになります。

stiyl
質問者

お礼

回答ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

その「bin_search」とやらは何をする関数なんでしょうか? ことと次第によっては「bin_searchでkeyを返したい」が既にはずれである可能性もあります.

stiyl
質問者

補足

元は、ライブラリ関数のbsearchを自作しようというものでした。 仮引数もいくつかありましたが、最終的にはkey(と同じ構造体の配列)を返せればよいので、このような形にしました。