ページ 11

配列引数のサイズを調べる

Posted: 2009年9月30日(水) 20:14
by チルチル
void main(){
int a[20];
int i;

for ( i = 0 ; i < sizeof(a) / sizeof(int) ; i ++ )
a = i;
}

上のように書くと配列の要素数だけループしますよね
しかし関数の引数に配列を渡した場合は先頭のアドレスが渡されるだけなので
sizeof演算子は要素数を返してくれません
何か良い方法は無いでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 20:47
by box
要素数も引数に加えてあげてください。

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 20:54
by zwi
こんな感じですかね。
void func(int a[/url],int size)
{
int i;
for ( i = 0 ; i < size ; i ++ )
a = i;
}
}
int main(){
int a[20];
func(a,sizeof(a) / sizeof(int));
return 0;
}

ちなみに、呼び出しをこうする方法もあります。
#define FUNC(array) func((array),sizeof((array))/sizeof(int))
int main(){
int a[20];
FUNC(a);
return 0;
}

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:22
by チルチル
あ~すいません説明不足でした
要素数を別に渡さなくてもできる方法は無いでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:26
by zwi
C言語の引数の受け渡しの仕組みでは無理です。
オブジェクト指向言語のJavaやC#なら言語仕様自体で配列の仕組みが違うので必要ないですが。
C++でもクラスを使えば擬似的には可能です。

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:31
by チルチル
う~ん無理ですか・・
ちなみに擬似的にとはどんな感じでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:34
by zwi
STLのvectorを参照渡しで使います。
すいません、いま説明している時間が無いので検索してみてください。
分からなければ、明日またお答えします。

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:43
by チルチル
あ~残念ですが今回のコードはSTLとの相性が最悪なので無理そうですね・・
どうもありがとうございました

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:49
by array
配列の要素数は一般的に以下の形式が多用されてるみたいです。
int main() {
    int array[20]; 

    // num は20になる
    int num = sizeof( array ) / sizeof( array[0] );

    return 0;
}
また、define定義を用いれば

#define array_sizeof(p) ( sizeof( p) / sizeof( (p)[0] ) )

int main() {
    int array[20]; 

    // num は20になる
    int num = array_sizeof(array);

    return 0;
}

これでプログラムがすっきりすると思います。

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:56
by array
本文読み直したら、勘違いしていました^^;

関数に配列を渡しても、要素数は引き継げないっていう話でしたね・・・・申し訳ないです。

関数先にC++のテンプレートを用いれば、要素数も引き継いでくれるのですが、一応解決された
みたいなのでまたの機会に。

Re:配列引数のサイズを調べる

Posted: 2009年9月30日(水) 21:57
by チルチル
これは結構画期的ですね
まあ呼ぶ時には確定しているので定数で行ってみます

Re:配列引数のサイズを調べる

Posted: 2009年10月01日(木) 14:58
by GPGA
C++でtemplateを使用すれば、引数をサイズを渡す必要はありません。
#include <iostream>

template<class T, int N>
void func(T (&ar)[N]) {
	for (int i = 0; i < N; ++i) {
		std::cout << ar << std::endl;
	}
}

int main() {
	int data[/url] = { 0, 1, 2, 3 };
	func(data);
}

Re:配列引数のサイズを調べる

Posted: 2009年10月01日(木) 17:06
by たかぎ
C++の次期規格であれば...
template <typename T, std::size_t N>
constexpr std::size_t count(T (&arg)[N])
{
    return N;
}
とすれば、定数式として扱うこともできますね。

Re:配列引数のサイズを調べる

Posted: 2009年10月01日(木) 17:08
by チルチル
これも使えそうですね
どういう仕組みになっているのでしょうか?
解説サイトとかあったら教えてください

Re:配列引数のサイズを調べる

Posted: 2009年10月01日(木) 21:30
by Justy

>解説サイトとかあったら教えてください

 少し古い記事ですが

テンプレート引数の一致
ttp://msdn.microsoft.com/ja-jp/library/cc440189(VS.71).aspx

Re:配列引数のサイズを調べる

Posted: 2009年10月01日(木) 23:17
by チルチル
う~ん良くわかりませんでしたね・・

ちなみに
template<class T, int N>
のclassとintの違いは何でしょうか?

あとTに入る型が全て同じの場合に
Nだけにする事はできないでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 00:04
by 組木紙織
>あとTに入る型が全て同じの場合に
>Nだけにする事はできないでしょうか?

部分特殊化を使えばOK.
#include <iostream>
using namespace std;

//int 型バージョン
template<std::size_t N>
void func(int (&ar)[N])
{
	std::cout << "int " << std::endl;
	for(int i=0; i<N;++i){
		std::cout << ar  << std::endl;
	}
}

//なんでも型バージョン
template<class T, std::size_t N>
void func(T (&ar)[N]) {
	std::cout << "not int" << std::endl;
	for (int i = 0; i < N; ++i) {
		std::cout << ar << std::endl;
	}
}

int main() {
	//int型の配列
	int data[/url] = { 0, 1, 2, 3 };
	//const int型の配列
	const int data2[/url]={0, 1, 2, 3};
	func(data);
	func(data2);
	return 0;
}

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 01:32
by チルチル
これは良いですね、最初に比べてかなり短くなりました
template<int N>
int Draw(int (&Graph)[N]){
	int i;
	for( i=0;i<N;i++ );
	return i;
}
これは練習で作った関数ですが
どこまで短くできるか気になりますね

そこで
>template<int N>
>(int (&Graph)[N])
ここをもっと短く書けないでしょうか?

あとテンプレートの柔軟性に期待して
関数を呼ぶ前に配列を作成しないで
引数の(と)の中に数値や変数を並べて渡せないでしょうか?

つまり
Draw({1,2,3,4,5});
見たいな事はできないでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 02:55
by 組木紙織
>これは練習で作った関数ですが
>どこまで短くできるか気になりますね
意図が見えないのですが、
ループ回さずにreturn N;
で十分なような気が。。。
テンプレートのところは短くできないです。


>Draw({1,2,3,4,5});
>見たいな事はできないでしょうか?

次期C++ならできるような気もしますが、現在はマクロを併用して擬似的にするしかないのかな、
配列を引数にと考えなければ可長変引数を使えばできますけど、安全性に不安が出てきますね。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 07:40
by たかぎ
> 部分特殊化を使えばOK.

関数テンプレートの部分特殊化はできないので、これは単なる多重定義ですね。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 17:26
by チルチル
簡略化はこの辺が限界みたいですね
でも当初の目的は達せたので助かりました

これから実装してみるので少々お待ちください

ちなみに
>現在はマクロを併用して擬似的にするしかないのかな
これはどんな感じでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 17:32
by たかぎ
こんな風にして定数式にすることもできます。
template <typename T, std::size_t N>
char (*count_helper(T (&array)[N]))[N];

#define count(array)  sizeof(*count_helper(array))
マクロであること自体も問題点を除けば、結構優れものかもしれません。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 17:48
by チルチル
う~ん良くわからないですね・・
どんな感じで使うのでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 20:58
by たかぎ
> どんな感じで使うのでしょうか?

そんなに難しく考える必要はありません。
int a[7];
std::size_t n = count(a);
とすれば、nに7が代入されるはずです。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 21:04
by チルチル
なるほど、確かにそうなる気がしますね
しかしこれでDraw({1,2,3,4,5});
が擬似的に実現できるのでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 21:41
by たかぎ
> しかしこれでDraw({1,2,3,4,5});
> が擬似的に実現できるのでしょうか?

それを目指したものではありません。

Draw({1, 2, 3, 4, 5})を実現するには、C99かC++の次期標準でなければ無理です。GCCでも何とかなります。
多少シンタックスを変えてもよいなら実現することは可能ですが、オーバーヘッドが大きくなります。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 21:48
by チルチル
これは無理ですか・・

Draw({1,2,3,4,5});は無理だとしても
予め配列を作成しておかなくても良いような方法は無いでしょうか?

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 22:15
by たかぎ
> Draw({1,2,3,4,5});は無理だとしても
> 予め配列を作成しておかなくても良いような方法は無いでしょうか?

要素数の上限があらかじめ決まっているのであれば、make_tupleを使う方法もありますし、
template <typename T> void Draw(const T& e1);
template <typename T> void Draw(const T& e1, const T& e2);
template <typename T> void Draw(const T& e1, const T& e2, const T& e3);
...
のように、数だけ多重定義しておく方法もあります。

可変個数引数を使う方法もありますが、あまりお勧めはしません。

Re:配列引数のサイズを調べる

Posted: 2009年10月02日(金) 22:20
by チルチル
う~んこういうのは無理がありそうですね・・

実装しているうちに何か変わるかもしれませんから色々やってみます

Re:配列引数のサイズを調べる

Posted: 2009年10月03日(土) 16:14
by チルチル
うまく行きました
どうもありがとうございます

Re:配列引数のサイズを調べる

Posted: 2009年10月04日(日) 18:38
by 組木紙織
遅くなってしまいましたが、

>> 部分特殊化を使えばOK.

>関数テンプレートの部分特殊化はできないので、これは単なる多重定義ですね。

正しくないことを書いてしまってすみませんでした。