C++で配列を返すにはどのようにしたらよろしいのでしょうか。
いろんなことを一応やってみましたが先頭の配列しか受け取ることができません。
また、受け取り方もよく分かってないのでその辺もお願いします。

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

A 回答 (8件)

もうひとつ



まず、CやC++の世界では、
関数の引数として配列を渡すような
表記は、単に、ポインタを渡してい
るだけなので、引数として指定した
場合には、受け渡しだけでは、要素
毎のコピーは発生しません。

たとえば、
http://www.kouno.jp/home/c_faq/c6.html#4
にある、「 なぜなら配列が渡された
ときに、関数が実際に受け取るのはポ
インター であるからである」



さて、それだけではなんなので、
単純にポインタを引数とせずに配列
を渡す形にした方がわかりやすい例
です。

関数の引数に配列表現を使うのは、
多次元(実際には配列の配列)を
使うときにわかりやすくなるという
効果があります。

たとえば

int color[1024][768];

というような配列を渡したいとき、
ポインタとしてやりくりするより、
シンプルに

void revers(int color[1024][768]);

のように渡して、関数内で配列として
取り扱う方がわかりやすいと思います。

ただ、厳密に言えば、

・Cには多次元配列はない
 (あるのは、配列の配列の……)
・関数の引数で書いた配列の
 要素数は無視される

というのがあって、一番内側の
数字は無視されます。

ですので、
void revers(int color[][768]);

でも同じです。
ただし、

void revers(int color[][]);
void revers(int color[1024][]);
はエラーになります。

また、たとえ、

void revers(int color[1024][768]);

と書いても、実際の配列の要素数は
チェックされませんので、注意が必要
です。

多次元配列はないという意味は、実は
int color[1024][768];
は、

・int [768] という配列の型があって
・それが、[1024] 個ある配列

という意味になります。

ですから、
void revers(int color[][768]);
の内側の [] は、配列の要素数なので
無視される(なくても良い)
外側の [678] は、int [768] という
型の一部なので、省略不可
ということになります。
    • good
    • 1

初心者とのことなので、理解できる可能性は低いですが...



結果を格納する配列を引数として渡す場合、一般的には強い例外安全保障ができなくなります。配列の要素のコピーコンストラクタが決して失敗しないか、決して失敗しないswapが用意されている場合だけ、強い例外安全保障が可能になります。その場合でも、正しく実装するには相応の知識が必要です。

具体的には、

void func(std::string array[10])
{
 std::string temp[10] = { ... };
 for (int i = 0; i < 10; i++)
  array[i].swap(temp[i]);
}

のようにしなければなりません。
つまり、関数内部で一通りのコピーが必ず発生します。
    • good
    • 0

再度補足です。



引数で配列を受け渡しする方法がわかりに
くいので。

関数の仮引数の形で、配列を指定する
表現方法があります。

void func(int a[]);

のようにすれば、この引数は、int の
配列であることを明示できます。

具体的な処理としても

void func(int a[])
{
int x = a[10];
// 呼び出したり、

a[11] = x + 1;
// 代入したり
}

できます。
このとき、引数を経由した操作は、
呼び出し側に反映されます(後述)

また、配列のサイズは直接渡されま
せんので、上記の場合、a[10] や、
a[11] が存在しなくてもコンパイラは
何も言いません。
(実行時に良くないことが起こるで
しょう)

この関数を呼び出すときには、配列名を
引数にできます。

main()
{
int x[100];

func(x);

のように
}

ただ、この場合は、本当は、配列を
引き渡しているのではなく、配列の
先頭を指すポインタを渡しているだ
けです。

ですので、

void func(int a[]);
は、
void func(int *a);
と同じだと考えて差し支えありません。

実際には、このように、アドレスを
渡しているので、関数側の操作が
呼び出し側に反映されてしまうわけで
す。
    • good
    • 0

補足です。


ANSI 以降のCでは、「構造体を返す」のは、
値をコピーするので処理コストがかかるとい
う以上の問題はありません。

処理スピードを問題にしなければ、返せる
値のサイズにも上限はありません。

「構造体を返す」場合は、単に、値のコピー
が発生するだけですから、メモリをどう確保
するかは、処理系にお任せすれば良いことに
なっています。

ただ、普通は、関数の返値として返すのでは
なく、引数として渡すことが多いですね。

int a[100];
に対して、

void func(a[])
{ ..... }

という関数に、

func(a);

と渡せば、関数内で、配列 a を操作できます。


あえて、(構造体経由で)配列を「返す」なら
たとえば、

a.h
-------
struct array_type
{
int a[1024];
};

array_type func(int v);
-------

a.cpp
------
#include "a.h"

array_type func(int v)
{
array_type wk;

for (int i = 0; i < 1024: i++)
wk.a[i] = v;

return wk;
}
------

b.cpp
------
#include "a.h"

int main()
{
arrya_type value;
value = func(3.14);
// ここで、値のコピーが発生する

// いろいろな処理
// value.a[i] などで、配列としては機能する
// でも、本当は、構造体
}
------

これで、あえて、メモリを明示的に確保すること
も、メモリリークを起こすこともなく、実行は
できます。

ただ、後で読む人が、「なぜここで構造体?」
と悩むことにはなると思います。

C++では、(明示的に定義してあれば)コピー
コンストラクタというのがあって、これが悪さを
するとか、これがないために、「単なる値のコピー」
が発生するとか、そういう話題はありますが、
普通に構造体を返すのは、上述のような、大きな
データのコピーという問題があるだけです。
    • good
    • 0

ネイティブコードはプリミティブな値(Max64ビット)しか返せません。


オブジェクト型を返す場合でも関数からの戻り値はポインタで、本体は
別のメモリ空間にあります。
そもそも、C言語では配列の次元、要素数の管理は利用者の責任で
行うことになっています。つまり、「配列の先頭だけ渡すから、あとは
勝手にやってくれ」なのです。故に、要素数を5個しか定義していない
配列に対し、インデックスが6でアクセスしてもエラーになりません。

個人的な意見ですが、C、C++で配列や構造体を戻り値の型にするのは
プログラムの効率的な作り方から見れば、「やってはいけない」の
代表格みたいなものです。

先ず、次のことを考えてみてください。
★呼び出されたメソッドが返す配列は何処に作られたものか?
 自動変数であれば、メソッドから返った時に解放されてしまい、
 内容は不定になります。また、メソッド内でアロケートしたもの
 であるなら、メモリを解放する責任は誰にあるのか?
★それでも、明示的にアロケートしているなら百歩譲って良しと
 しましょう。しかし、単に構造体なりを返すと、先に述べたように
 戻り値を保存しておくメモリを確保する内部コードが生成される
 ことがあります。(実際にそうなるケースが多い)
 すると、ソースコード上では見えないメモリを消費しますし、誰も
 解放しないので、繰り返し実行するとメモリストレスになります。

よって、配列や構造体を返す場合は呼び出し側が領域を確保して、
そのポインタを渡し、呼び出されたメソッドはそこに結果を記録
するべきだと思います。

この回答への補足

C++を学び始めて1ヶ月もたっていないのでよく分かりません。
やりたいことはa.cppとb.cppでbで作った配列をaで受け取れるようにしたいのですがどのようにしていいか分からず困っています。
よろしくお願いします。

補足日時:2009/05/27 11:17
    • good
    • 0

配列全体を直接返す方法はありません。


ただ、構造体は直接返すことができます。
これを応用すると、配列をメンバーにし
た構造体を返すことで、実質的に配列を
返すという手もあります。

同じく、配列は直接代入できないのでが、
構造体は直接代入できるので、配列をメ
ンバーとする構造体経由で、配列を代入
したりもできます。
    • good
    • 0

通常は ポインタを渡すしかないんじゃないのかな



古い考えなら呼び元で領域確保して処理側へ確保できたポインタを渡して終ったら確保された値を順に使う・・・
今は色々やり方は有るだろうけど大きくは変ってない筈・・・
    • good
    • 0

配列を直接返す方法はありません。


お勧めなのは、

std::auto_ptr< std::vector<int> > func();

のように、vectorをauto_ptrにして返す方法です。
auto_ptrにしておかないとvector全体のコピーが発生するため、効率が低下するとともに、例外が送出するリスクも発生します。
    • good
    • 0

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

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

このQ&Aを見た人はこんなQ&Aも見ています

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

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

Q関数から配列を返すには?

return で配列を返すにはどうしたらよいのでしょうか。
例えば以下のような場合です。

int main (){

char Value[] = "999";
int a;

 a = test(Value);

 printf ("%d", a);
 
}


int test(char *Value)
{
int nVal[255];

ここで nVal に適当な処理をして・・・

 return Value;

}


 int a を配列とかにしてみましたけど、コンパイラが
通りません。
要は配列数値を main で受け取って表示したいのですが、
本日C言語はじめたところなので、教えていただければありががたいです。

Aベストアンサー

戻り値は1つしか戻せません。
引数で配列の先頭のポインタが渡され、それを使って関数で配列の中身を
書き換えて戻ってきて、メインで配列を参照すればいいです。

参考urlの(3)を参考にしてください。

参考URL:http://www9.plala.or.jp/sgwr-t/c/sec11-3.html

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配列の要素数に変数を入れたいときには

よろしくお願いします。
配列の要素数には定数しか入れられないのですが,どうしても変数を入れたいときは,それを引数として関数を呼び出すしか方法はないでしょうか。
具体的には,scanfで手に入れたint型の変数を要素数とする配列を宣言したいのですが,どうすれば良いでしょうか。
ご教授ください。

Aベストアンサー

c99と呼ばれる最近の規格では、配列の大きさに変数を使用できます。
bccはc99に対応していないようです。

それ以前の規格では、動的領域確保関数 malloc や callocを使って領域を確保するか、効率等を無視してバカデカい配列を用意しておくかです。
「それを引数として関数を呼び出す」っていうのは、malloc/callocのことですか?

Qファイルやディレクトリの存在確認を行う方法

ファイルをオープンするのはfopenでOKですが、ファイルやディレクトリの存在確認を行う方法が知りたいです。

何か組み合わせて作るものなのでしょうか?
perlとか便利な演算子があるのですが、C/C++って器用ではないですね。
これは処理系?依存の内容ですか?

私の環境は VC6, VC2005 Windows2000です。

Aベストアンサー

int access(const char* path, int mode);
int stat(const char* path, struct stat* sb);

かな?
MSDN を引くと _access_s() を使えとか書いてあるけど。

Q戻り値で構造体を返すことは可能でしょうか?

perlでは以下のように2つの戻り値が可能ですが、C言語では
それができるのでしょうか?
my (ret1, ret2) = test1();

よくやるのは、引数にポインタを渡して、内容を書き換える手を使っていますが、戻り値を複数返せたら、直感的にわかりやすいかなと思いまして・・・

Aベストアンサー

C言語から遠く離れた者ですが、

>>> よくやるのは、引数にポインタを渡して、内容を書き換える手を使っています

これが常識でしょう。これが直感的に理解できるようにC言語を身に付ける必要があるのではないでしょうか。

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;
}
この場合は、呼び...続きを読む

Qint型からchar型への変換

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

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

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

Qfatal error LNK1120: 外部参照 1 が未解決です

またわからないことが・・・
教えて下さい。
以下をVC++2005でコンパイルすると、

MSVCRTD.lib(crtexew.obj) : error LNK2019: 未解決の外部シンボル _WinMain@16 が関数 ___tmainCRTStartup で参照されました。
C:\Documents and Settings\tomato\My Documents\Visual Studio 2005\Projects\a\Debug\a.exe : fatal error LNK1120: 外部参照 1 が未解決です。

と警告がでて通りません。
何のことでしょうか。

#include<stdio.h>
#include<process.h>

struct meibo{
  char name[20];
  char tel[20];
  char address[20];
};

void message( void );
void input( FILE *fp, int cnt , struct meibo *a, int *end );

void main( void )
{
  struct meibo a[20];
  FILE *fp;
  int cnt, end;

  if( (fp=fopen( "meibo.dat", "w" ) ) == NULL ){
    printf( "Can not open the meibo.dat.\n" );
    exit( 1 );
  }

  message();

  fprintf( fp, "番号, 名前, TEL, 住所\n" );
  fflush( fp );

  cnt = 0;
  end = 0;
  while( end == 0 ){
    input( fp, cnt, &a[cnt], &end );
    cnt++;
    fflush( fp );
    if( cnt == 20 ){
      printf( "人数が一杯です.終了します.\n" );
      end = 1;
    }
  }
  fclose( fp );
}

void message( void )
{
  printf( "名前, TEL, 住所, endを入力してください.\n" );
  printf( "継続の時はend=0," );
  printf( "中止の時は,end=1と入力してください.\n" );
}

void input( FILE *fp, int cnt, struct meibo *a, int *end )
{
  printf( "名前-->" );
  scanf( "%s", a->name );
  printf( "TEL -->" );
  scanf( "%s", a->tel );
  printf( "住所-->" );
  scanf( "%s", a->address );
  printf( "Exit? Continue:0 Exit:1 -->" );
  scanf( "%d", end );
  printf( "\n" );
  fprintf( fp, "%2d, %s, %s, %s\n",
    cnt+1, a->name, a->tel, a->address );
}

またわからないことが・・・
教えて下さい。
以下をVC++2005でコンパイルすると、

MSVCRTD.lib(crtexew.obj) : error LNK2019: 未解決の外部シンボル _WinMain@16 が関数 ___tmainCRTStartup で参照されました。
C:\Documents and Settings\tomato\My Documents\Visual Studio 2005\Projects\a\Debug\a.exe : fatal error LNK1120: 外部参照 1 が未解決です。

と警告がでて通りません。
何のことでしょうか。

#include<stdio.h>
#include<process.h>

struct meibo{
  char name[20];
...続きを読む

Aベストアンサー

http://www.a.math.ryukoku.ac.jp/~hig/course/compsci2_2005/man/faq.html
にある現象と同じではないでしょうか、一度お試しください。

QC++ vectorに配列をプッシュしたい

C++のstd::vectorが格納する要素として配列を指定することはできますか

vectorを使って2次元配列を表現したいときは,たとえば

std::vecor<std::vector<int>> v;

とすれば2次元配列が表現できますよね.

2次元配列の列方向の要素数が2で固定されていて,行方向の要素数が不確定のデータを扱いたいので,2次元配列を格納するvectorで扱えればなと思いました.
(2個で1組のデータがたくさんあるということなので,vectorの2次元配列ではありません)

std::vector<int[2]> v;

int a[2];
a[1] = 1;
a[0] = 2;
v.push_back(a);

という書き方ではコンパイルできなかったのですが,vectorに配列要素を格納させることはできないのでしょうか.
あるいは,もし可能ならどのように書けばよいのでしょうか.

結局は1組のデータセットを構造体化してそれをvectorにプッシュするやり方に落ち着いたのですが,疑問に思ったままモヤモヤしているので質問させて頂きます.

「vector 配列」などのキーワードで検索してみましたが,vectorの動的配列としての紹介記事が多くヒットしてしまい,自分ではうまく情報を発見することはできませんでした.
よろしくお願いします.

C++のstd::vectorが格納する要素として配列を指定することはできますか

vectorを使って2次元配列を表現したいときは,たとえば

std::vecor<std::vector<int>> v;

とすれば2次元配列が表現できますよね.

2次元配列の列方向の要素数が2で固定されていて,行方向の要素数が不確定のデータを扱いたいので,2次元配列を格納するvectorで扱えればなと思いました.
(2個で1組のデータがたくさんあるということなので,vectorの2次元配列ではありません)

std::vector<int[2]> v;

int a[2];
a[1] = 1;
a[0] = 2;
v...続きを読む

Aベストアンサー

コンテナに巣の配列を要素として入れることはできません.

C++11 (以降) なら std::array を使えばいい.

C++98 なら
・あきらめる
・Boost の boost::array を使う
・C++11 の std::array 相当のものを自作する
のいずれか, かな.

QDWORDの実際の型は何でしょうか

VC++.NETの環境です。
DOWRD dw1 = 1;
int i = 2; と定義し
ここで
if ( i > dw1 ){
何かの処理;
}
とコーディングすると
warning C4018: '>' : signed と unsigned の数値を比較しようとしました。
のワーニングがでます。
これは、DWORDがint型でなくunsigned int型のようにも見えます。
ある本によれば(VC++.V.NET逆引き大全500の極意)
DWORD はint型であると記述されています。
もし、int型ならこのワーニングはでないはずなのですが、
なぜでるのでしょうか。又、DWORDの実際の型は何なのでしょうか。ご存じのかたおりましたら、教えていただけませんでしょうか。

Aベストアンサー

型定義が知りたいのならば、宣言ファイルを見れば疑問を挟む余地もありません。
DWORD型はwindef.hで
"typedef unsigned long DWORD;"
と宣言されています。

Visual Studioを使っているのならば、知りたい型の上にマウスポインタを置いて右クリック、ポップアップメニューの「定義へ移動」または「宣言へ移動」で簡単に知ることが出来ます。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報