初めての店舗開業を成功させよう>>

構造体を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関数に構造体を渡したい
}

どうかよろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (5件)

構造体だと考えるからややこしく思えるのです。



構造体でなく、単なる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個の要素をまとめて値渡ししたい」と言う場合は、その配列をメンバにもつ構造体を新たに定義し、配列をラップした構造体で値渡ししましょう。
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

確かに"構造体で"という考えにしばられていました。
試してみましたら思い通りに動きました。

的確なアドバイス、ありがとうございました。

お礼日時:2007/07/24 12:59

> どういったやり方(書き方)で渡せるのか知りたかったので。



ファイル名から察するに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修飾子を付けることはできませんので外してください。
    • good
    • 0

本題とは少し離れますが、配列を関数に渡す場合に


その配列のサイズを渡すほうが良いと思います。

でなければ、関数内で配列にアクセスする場合、
どこまでアクセスして良いのか分からなくなります。
特に今回のように、関数内で定義された配列のサイズは
呼び出し元しかそのサイズを知る明確な方法がありません。

サイズをつけることで、アクセスできる範囲を明確にし、
さらに、引数を見るだけでポインタが、
単なるポインタを要求しているのか、
配列へのポインタを要求しているのかの区別が容易になります。

今回の場合だと
>void test( struct data *p)
   ↓
void test( stuct data *p, size_t size )
など。
    • good
    • 0

★確かに『出来ます』はい。


・構造体のポインタをそのまま渡すとアドレス渡しですよね。
 だから『*』演算子を使えば構造体の実体を意味しますのでこれを渡せばよいだけです。
 回答者 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)はなぜ『.』演算子でアクセスできるかが分かれば
 『*』演算子の使い方が分かってくると思います。
・以上。
    • good
    • 0
この回答へのお礼

いつも御回答下さりありがとうございます。非常に助かっています。

アドレス渡しされたものを、さらにアドレス渡しするというのは、
考え方がややこしいのでおおよそ不可能だと思っていました。

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

お礼日時:2007/07/24 13:06

できます。

この回答への補足

言葉足らずでした。すいません。

どういったやり方(書き方)で渡せるのか知りたかったので。

補足日時:2007/07/24 11:55
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q構造体を指すポインタからその中のポインタ変数が指す要素の参照

構造体を指しているポインタから、
その構造体内にあるポインタ変数の指している要素に値を代入する方法が、どうしてもわかりませんでした。
どなたか助けてください、お願いします。


struct Kouzou
{
int* p;
};

int main()
{
Kouzou kou;
Kouzou* k_p;

k_p = &kou;

k_p -> *p = 10; //エラー
}

Aベストアンサー

*k_p->p = 10;

ですけど、pが指す先を定義しておかないと
エラーになりますよ。

Q構造体の初期化方法について

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初期化したいと思っています。

よろしくお願い致します。

#define MAX 2000
//グローバル
struct tag{
int Npkt;
int gettime;
int rPkt;
int lossPkt;
}rdata[MAX];

main(){
  //for文で複数回実行処理
  for(i=0;i<=5;i++){
  //ここで構造体の初期化を記述する
//例として、5回プログラムを実行する
  }
}

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初...続きを読む

Aベストアンサー

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
memset( &rdata[i], 0, sizeof(struct tag) ); です。
※rdata[i]の1データだけ初期化します。

余談:
・『ZeroMemory』関数は Win32 API と分類されていますが、実体は『memset』関数に
 『#define』されているだけです。でも、戻り値を『VOID』型にキャストされているので
 『memset』関数のリターン値を取得できません。→第一引数のアドレスが『memset』関数
 ではリターンします。
・以上。おわり。

参考URL:http://taka.no32.tk/tips/Win32/ZeroMemory.html

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
m...続きを読む

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

Q文字列がNULLか空文字列かの判定

Visual C++で、Cのプログラムを作成しているものです。(OS:WinNT 4.0)
文字列の扱いについて、質問します。

関数 int func(char *str) があると仮定します。
パラメータとして、strは以下のような状態あるとします。
(strは関数が呼ばれる前にcalloc()で領域確保済み)
 シンボル名 値
 str      0x00000001 ""
上記の状態で、strがNULLか空文字列("")であることを条件式にしたいのですが、str == NULL は偽となり、strcmp(str, "") を使用すると異常終了します。
どうしたらよいのでしょうか。アドバイスをお願いします。

Aベストアンサー

No1の方の回答にあるように、calloc()で取れた領域のアドレスを正しく渡せてないように思えますが...

#defineERROR(-1)

int func(char *str)
{
  if( (!str) || (!strlen(str)) ) return ERROR;
  return strlen(str);
}

void main()
{
  char *p=(char*)calloc(10,10);
  printf("%d\n",func(p));
}

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Qfgetsなどのときのstdinのバッファを消すには?

こんにちは,今C(C++でない)を使用しています。
たとえば,
char str[20]
fgets(str,sizeof(str),stdin)
としたときに20字以上を打つと,stdinのバッファに20字以上の分が残ったままになります。

C++などでは
fflush(stdin)で,うまくいきますが,普通のCでは対応がされていないみたいでうまくいきません。

よろしくお願いします。

Aベストアンサー

あ,テキスト入力だからこんな大掛かりなことしなくてもいいんだ.
末尾に'\n'が出るまで掃出せばいいんですよね.

fgets(str, sizeof(str), stdin);
if ( str[strlen(str)-1] != '\n' ){
while( getchar() != '\n' );
}

でいいんだ.失礼しました.

Qprintf による16進表示について

C言語初心者です。

今作っているプログラムで、データを16進形式で表示しようとしています。
大体このような感じです。

/*入力時*/
char buf[5]={0x4e,0x94,0xa0,0x2b,0x78}

/*出力時*/
for (i = 0; i < 5; i++) {
printf("0x%02x\n",buf[i])
}

実際には入力後にある処理によってbufは更新されるのですが、printfの出力結果として、

0xffffff4e
0x94
0xffffffa0
0x2b
0x78

というように、'ffffff'が付加したものがいくつか出力されてしまいます。
これはどういった意味を持つのでしょうか?

なんか初心者ならではの漠然とした質問ですいません。。。

Aベストアンサー

出力は、
0x4e
0xffffff94
0xffffffa0
0x2b
0x78
ではありませんか?
char が符号付(-128~127)のため、0x80~0xffは負の数とみなされます。printfの引数になる時に 符号付charは符号付intに変換されますが、このCコンパイラの場合は、int が4バイトcharが1バイトのため、上位3バイトに負の数を示すffffffが入ります。
char x=255;
printf("%d\n",x);
だと255でなく、-1が表示されます。

対応としては、
unsingned char buf[5]={0x4e,0x94,0xa0,0x2b,0x78}
;
とするか、
printf("0x%02x\n",buf[i]&0xff);
にするかどちらかですね。

QC言語で文字列をかえす正しい書き方が知りたいです?

C言語で次の警告が表示されます。
文字列を返したいのですが、正しい書き方はどのようにすれば良いのでしょうか?


jci.h(20) : warning C4172; ローカル変数またはテンポラリのアドレスを返します。


char *test(char *a, int b)
{
char str[BUFSIZ];
return str; <------

}

Aベストアンサー

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び出し元でちゃんとfreeしましょう。

B-2.呼び出し元でメモリを確保するケース
(注意:同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{

...

return str;
}
これは#1の方の回答と同じです。

B-3.B-1/B-2の複合
(注意:NULL以外の同じアドレスを指定して複数回呼び出すと、メモリ内容は当然破壊されます)
char *test(char *str, ...)
{
if(str == NULL)
{
str = malloc(BUFSIZ);
if(str == NULL) return NULL; //エラー
}

...

return str;
}

こんなところですかね。

再入可能にするかどうかで、回答は変わります。

A.2度呼び出した場合に前のデータを破壊してもよいケース(再入不可能)

char *test(...)
{
static char str[BUFSIZ]; // static指定でメモリは静的に確保されます。

...

return str;
}

B.2度呼び出した場合に前のデータを破壊しないケース(再入可能)
B-1.mallocを使ってもいいケース
char *test(...)
{
char *str;
str = malloc(BUFSIZ);
if(str == NULL) return NULL; // エラー

...

return str;
}
この場合は、呼び...続きを読む

Qファイル出力の場所を指定

現在C++にてhtmlファイルを出力するプログラムを作っているのですが、出力場所を指定することはできるのでしょうか?(現在はそのプログラムソースが保存されている場所と同じファイル内に出力されますが、それをデスクトップに出力するなど。)
もし、方法がありましたら、教えてください。
ソースや参考HPのURLなどのせていただけたらありがたいです。
環境はVisualStudio.NET2003です。
よろしくお願いします。

Aベストアンサー

単にファイル名の前にパスを指定する。

絶対パス指定
fp=fopen("c:/temp/test.txt","w");

相対パス指定
fp=fopen("./hoge/test.txt","w");


デスクトップはOSやユーザによって場所が異なるので、少し面倒です。
XPの場合環境変数を利用してこんな感じで出来ると思います。

例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
FILE *fp;
char fname[1024];
strcpy(fname,getenv("USERPROFILE"));
strcat(fname,"/デスクトップ/test.txt");
fp=fopen(fname,"w");
//処理
fclose(fp);
}

Qグローバルな構造体のメンバ変数のアドレスの取得

グローバルな構造体のメンバ変数のアドレスはどうやって取得したらいいでしょうか?

Aベストアンサー

わざわざ MacroGetOffset を作らずとも, ISO C には offsetof というマクロが既に定義されてます>#2
ということで, オフセット (構造体の先頭から当該メンバまでの距離) はこれでわかります.


人気Q&Aランキング

おすすめ情報