![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
構造体をmain()からアドレス渡しで別関数(test.cpp)に渡し、その関数の中だけでの別関数test1()にその構造体を、値渡しでもアドレス渡しでも、渡せるのでしょうか?
ちなみにmain.cppと、test.cppと、myhead.hとして分割コンパイルでやりました。
/*---------main.cpp--------*/
//ヘッダファイルで構造体宣言、test()のプロトタイプ宣言済み
void main()
{
struct data dt[10];
・・・・・・
test(dt); //test.cppのtest関数に構造体を渡す。
}
/*---------test.cpp---------*/
void test1(??????); //test1()のプロトタイプ宣言
void test(struct data *p) //構造体をアドレス渡しで受け取った
{
・・・・・
test1(?????); //test.cppで宣言したtest1関数に構造体を渡したい
}
どうかよろしくお願いします。
No.2ベストアンサー
- 回答日時:
構造体だと考えるからややこしく思えるのです。
構造体でなく、単なるintで考えてみて下さい。Cにとっては「引数に渡せる物」は構造体もintも一緒です。
void main()
{
int dt[10];
・・・・・・
test(dt); //test.cppのtest関数にintを渡す。
}
/*---------test.cpp---------*/
void test1(int para); //値渡しtest1()のプロトタイプ宣言
void test2(int *para); //アドレス渡しtest2()のプロトタイプ宣言
void test(int *p) //intをアドレス渡しで受け取った
{
・・・・・
test1(*p); //test.cppで宣言したtest1関数にintを値で渡したい
test1(p[0]); //こう書いても同じです
test2(p); //test.cppで宣言したtest1関数にintをアドレスで渡したい
test2(&p[0]); //こう書いても同じです
}
上記の「int」を「struct data」に置き換えても、Cは同じ事をします。
test1には「値が1つだけ」渡ります。渡るのは配列の1つの要素だけです。0~9番目をまとめて全部渡す事は出来ません。
test2には「アドレス」が渡ります。渡るのは配列の先頭アドレスなので、アドレスを元に0~9番目にアクセス出来ます。
「配列の10個の要素をまとめて値渡ししたい」と言う場合は、その配列をメンバにもつ構造体を新たに定義し、配列をラップした構造体で値渡ししましょう。
御回答ありがとうございます。
確かに"構造体で"という考えにしばられていました。
試してみましたら思い通りに動きました。
的確なアドバイス、ありがとうございました。
No.5
- 回答日時:
> どういったやり方(書き方)で渡せるのか知りたかったので。
ファイル名から察するにC++でしょうか?
mainの返却値の型がvoidなので、非標準処理系か規格合致自立処理系ですね。非標準処理系の場合は分からないので、規格合致自立処理系だと解釈して回答します。
まず、アドレス渡しというのは正確には存在しません。存在するのは「ポインタ渡し」と「参照渡し」です。質問文で挙げられているのはポインタ渡しですね。
「どういったやり方」を回答する前に、まずは用途について考えてみましょう。
単に値渡しより効率がよいからというだけの理由であれば、ポインタ渡しにするより(const修飾付きの)参照渡しにする方が得策です。その場合、
void test1(const data& r);
void test(const data& r)
{
...
test1(r);
...
}
とします。
配列ごと参照で渡したいのであれば、
void test(const data (&r)[10])
のようにするとよいでしょう。配列の要素数をハードコーディングしたくないのであれば、
template<std::size_t N>
void test(const data (&r)[N])
とすれば、要素数が変わってもそのまま使えます。
要素数が動的に変わるのであれば、std::vectorクラステンプレートの使用を検討することをお勧めします。あるいは、Boost C++ Librariesが利用できるのであれば、boost::arrayクラステンプレートを、TR1ライブラリが利用できるのであれば、std::tr1::arrayクラステンプレートを使用してもよいでしょう。
なお、CとC++で共用するのであれば、#4さんの回答のように、サイズを別に渡した方がよいと思います。
次に、空ポインタを渡す可能性があるからポインタ渡しにするのであれば、やはりconst修飾した上で、
void test1(const data* p);
void test(const data* p)
{
...
test1(p);
...
}
とすることになります。あるいは、先に紹介した参照渡しと、引数なしの2種類を多重定義してもよいでしょう。
なお、ポインタ渡しの場合でも、配列へのポインタとして渡すことも可能です。
void test(const data (*p)[10])
あるいは、
template<std::size_t N>
void test(const data (*p)[N])
のようにです。
渡した構造体の内容が、呼び出し先の関数で書き換えられるのであればconst修飾子を付けることはできませんので外してください。
No.4
- 回答日時:
本題とは少し離れますが、配列を関数に渡す場合に
その配列のサイズを渡すほうが良いと思います。
でなければ、関数内で配列にアクセスする場合、
どこまでアクセスして良いのか分からなくなります。
特に今回のように、関数内で定義された配列のサイズは
呼び出し元しかそのサイズを知る明確な方法がありません。
サイズをつけることで、アクセスできる範囲を明確にし、
さらに、引数を見るだけでポインタが、
単なるポインタを要求しているのか、
配列へのポインタを要求しているのかの区別が容易になります。
今回の場合だと
>void test( struct data *p)
↓
void test( stuct data *p, size_t size )
など。
No.3
- 回答日時:
★確かに『出来ます』はい。
・構造体のポインタをそのまま渡すとアドレス渡しですよね。
だから『*』演算子を使えば構造体の実体を意味しますのでこれを渡せばよいだけです。
回答者 No.2 さんのアドバイスを引用すると
>構造体でなく、単なるintで考えてみて下さい。
>Cにとっては「引数に渡せる物」は構造体もintも一緒です。
その通りです。すごく分かりやすいです。
・上記のを踏まえると下のサンプルのようになります。
サンプル:
int main( void )
{
struct data dt[10];
test1( dt ); ←ここは当然アドレス渡し
return 0;
}
// test.cpp の test1() 関数
void test1( struct data *dt )
{
sub1( dt ); ←これはアドレス渡し
sub2( *dt ); ←これが値渡し
}
// アドレス渡しの関数
void sub1( struct data *dt )
{
:
}
// 値渡しの関数
void sub2( struct data dt )
{
:
}
最後に:
・構造体のポインタを特別扱いしないで普通の単純変数(int*,long*,double*)のポインタと
同じような考えで行えるのです。
ちなみに構造体のポインタのメンバ参照は
(1)tag->member
(2)(*tag).member
の両方とも正しくアクセスできますが(2)はなぜ『.』演算子でアクセスできるかが分かれば
『*』演算子の使い方が分かってくると思います。
・以上。
いつも御回答下さりありがとうございます。非常に助かっています。
アドレス渡しされたものを、さらにアドレス渡しするというのは、
考え方がややこしいのでおおよそ不可能だと思っていました。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 質問です 下記のコードを分かりやすく解説お願いします 初心者です #include ‹stdio.h 3 2022/05/26 22:03
- Java java final 1 2022/06/10 22:49
- PHP $_SESSIONについて教えて下さい。 2 2023/03/02 09:18
- その他(プログラミング・Web制作) VScodeでpythonプログラムの関数を実行したい 2 2022/07/13 19:24
- JavaScript test.jsの関数testから別のtest2.jsの関数testをよびだす方法はどのようにするので 3 2023/03/30 11:11
- ドライブ・ストレージ HDDのチェック方法 6 2022/05/04 09:49
- その他(学校・勉強) Japanese schools tests 1 2022/08/19 14:41
- 中学校受験 Japanese schools 1 2022/08/22 15:53
- PHP PHP一覧表示した項目にリンクをはりたい 1 2023/07/12 17:08
- Excel(エクセル) Excelの置換が上手くいかない Microsoft® Excel® 2019 MSO (バージョン 5 2022/08/17 22:26
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
セグメントエラー
-
戻り値で構造体を返すことは可...
-
C言語のポインタに直接アドレス...
-
Run-Time Check Failure #3とい...
-
init関数の意味
-
fopne で失敗する原因
-
LPSTR型の初期化について
-
ExcelVBAでのkernel32(64bit)
-
NULLポインタが0でない処理系と...
-
PASCALとFARの意味
-
bsearch関数の呼び出しで
-
#define NULL ((void *)0) の弊害
-
C++とWIN32APIとゲームプログラ...
-
コンストラクタでnewを失敗した...
-
C言語で構造体の参照渡しができ...
-
アプリを32bitから64bit移行
-
NULLとブランクの違い
-
CImage GetBitsメソッドについて
-
不適切なポインタ
-
VC++6.0 MFC ダイアログバーを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
init関数の意味
-
C言語のポインタに直接アドレス...
-
fopne で失敗する原因
-
Run-Time Check Failure #3とい...
-
C言語の関数と配列に関する質問
-
LPSTR型の初期化について
-
戻り値で構造体を返すことは可...
-
参照型で受け取った引数をポイ...
-
構造体とfscanf
-
ExcelVBAでのkernel32(64bit)
-
アプリを32bitから64bit移行
-
Cで作成したDLL関数をVBから呼...
-
C言語でのconstを返す関数
-
main(int argc,char **argv[])...
-
DLL<->VB間での受け渡し(文字...
-
エラーの意味
-
PASCALとFARの意味
-
ハンドルはポインタか
-
CWnd::EnableWindow()の扱い方
おすすめ情報