
構造体を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で質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ExcelVBAでのkernel32(64bit)
-
Run-Time Check Failure #3とい...
-
C言語のポインタに直接アドレス...
-
参照型で受け取った引数をポイ...
-
戻り値で構造体を返すことは可...
-
コンストラクタでnewを失敗した...
-
どうしてエラーになるかわかり...
-
ポインタのポインタとrealloc
-
ハンドルはポインタか
-
引数のポインタについて
-
#define NULL ((void *)0) の弊害
-
セグメントエラー
-
自作関数の引数
-
変数の中身がごみかどうか判定...
-
C++で変数の型を途中で切り替え...
-
C言語の文字列?処理 strcpyやl...
-
TCHAR文字列内の検索について
-
配列を使わずに、変数名を動的...
-
C# DataGridView のヘッダーセ...
-
Integer変数をカラにしたいので...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
Run-Time Check Failure #3とい...
-
ExcelVBAでのkernel32(64bit)
-
セグメントエラー
-
#define NULL ((void *)0) の弊害
-
fopne で失敗する原因
-
LPSTR型の初期化について
-
トリプルポインタが必須!とな...
-
戻り値で構造体を返すことは可...
-
c言語で任意のファイルから読み...
-
参照型で受け取った引数をポイ...
-
ポインタについて
-
アプリを32bitから64bit移行
-
ハンドル、アドレス、ポインタ...
-
ポインタが文字化けしてる?!...
-
NULLポインタが0でない処理系と...
-
ハンドルはポインタか
-
リトルエンディアンというもの...
-
【C言語】戻り値が構造体の関数
おすすめ情報