自由配列をポインタで渡す


投稿ツリー



前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 | 投稿日時 2013/7/15 13:12
MJun 
#code(d){{{
import std.stdio;

void Load(int a[]){
int i;
a[0] = 1;
a[1] = 2;
a[2] = 3;

writefln("in Load");
for(i = 0; i < 3; i++){
writef("%d ",a[i]);
}
writeln();

}

void main(){
int a[3];
int i;

Load(a);

writefln("in main");
for(i = 0; i < 3; i++){
writef("%d ",a[i]);
}
writeln();

readln();//終了させないための入力待ち
}
}}}
上のプログラムは正しく動くのですが
14行目を動的配列で宣言して、配列の要素数をLoad内で決める形にしたいですが出来ません。
どうすればいいでしょうか?

あと、4~6行目の部分を初期化の時のように、a[3] = [1,2,3]みたいには書けないでしょうか?
投票数:1 平均点:0.00
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013/7/16 16:29
SHOO  管理人   投稿数: 658
行数がチョット違う?ようですが勝手にエスパーして解答します。

> %%14%%18行目を動的配列で宣言

やり方はいろいろありますが…単純に ~= で配列を拡張しながら要素を追加していけば目的は果たせるかと思います。その場合Load関数の引数はrefが必要になります。以下参照。

#code(d){{{
import std.stdio;

void Load(ref int a[]){
int i;
a ~= 1;
a ~= 2;
a ~= 3;

writefln("in Load");
for(i = 0; i < 3; i++){
writef("%d ",a[i]);
}
writeln();

}

void main(){
int a[];
int i;

Load(a);

writefln("in main");
for(i = 0; i < 3; i++){
writef("%d ",a[i]);
}
writeln();

readln();//終了させないための入力待ち
}
}}}

> あと、4~6行目の部分を初期化の時のように、a[3] = [1,2,3]みたいには書けないでしょうか?

書けますが、書き方が違います。以下のようにします。

#code(d){{{
a[0..3] = [1,2,3];
}}}

なお、「D言語らしい」書き方は以下のようになります。ご参考になさると良いと思います。

#code(d){{{
// std.array: std.array.appenderのため
import std.stdio, std.array;

// Load -> load : D言語ではlowerCamelCaseな文化があります
// int[] は戻り値にする(戻り値でUFCS使えるように)
int[] load()
{
// 添字の定義はここでは不要
//int i;

// 配列を拡張しながら追加していく時は、appenderが効率的で便利
//a[0] = 1;
//a[1] = 2;
//a[2] = 3;
auto app = appender!(int[])();
app ~= 1;
app ~= 2;
app ~= 3;

// 書式が不要の場合はwritelnを使う…
// あれ、これってチョット昔はwriteflnだとコンパイルエラーになったような…。
//writefln("in Load");
writeln("in Load");

// この書き方はC言語では一般的ですが、D言語ではあまりやりません。
// これよりもっと簡単な書き方がいくつも用意されているからです。
//for(i = 0; i < 3; i++){

// auto i = 0; ...て書けば添字の宣言も同時に行えて楽。けどこれは使わない
//for (auto i = 0; i < 3; i++)

// ↑の文法はよく使うので、より簡単な書き方として以下の書き方が提供されてる
// けどこれも使わない
//foreach (i; 0..3)
//{
// writef("%d ",a[i]);
//}

// 要素を1つ1つ参照する場合は以下のやり方が楽。
// だけどこれも使わない
//foreach (e; app.data)
//{
// writef("%d ", e);
//}

// writeflnには配列を出力する時用の書式が用意されてるのでそれを使うと便利
writefln("%-(%d %)", app.data);

// 改行はすでに出力済みなので以下不要
//writeln();

// 戻り値は追加が完了した配列
return app.data;
}

void main()
{
// loadの戻り値を受け取るときにautoで推論効かせてやったほうが楽。
// あと、D言語では int[3] a; のほうが一般的な配列の定義の仕方です。
// 一応C言語での書き方もできるようになっています。
//int a[3];
// 同上の理由で添字の定義不要
//int i;

//Load(a);
auto a = load();

// 同上の理由
//writefln("in main");
writeln("in main");

//for(i = 0; i < 3; i++){
// writef("%d ",a[i]);
//}
//writeln();
// 同上の理由
writefln("%-(%d %)", a);

// 以下のような最後に無駄に入力を求めることでプログラムを停止させるの
// は一般的にあまり良くないって言われています。(って私はどっかで見ました。)
// コンパイルした実行ファイルをわざわざWindowsのエクスプローラー上で
// ダブルクリックして実行しているなら、
// コマンドライン上で、 dmd -run main.d とかしましょう。
// readln();//終了させないための入力待ち
}
}}}
投票数:0 平均点:0.00
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2013/7/16 17:50
majiang 
appender を使わずに
int[] a;
a ~= 1;
a ~= 2;
a ~= 3;
とするのに対して、どの程度「効率的」なのでしょうか?
投票数:0 平均点:0.00
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2013/7/16 20:23
SHOO  管理人   投稿数: 658
現在の実装によると、appenderを用いることによって、配列を追加する際に増加するメモリの拡張の頻度と、その拡張がにともなって発生するデータコピーの頻度を低減する効果を期待出来ます。
ほかにもGCの挙動を追加が高速に行われるように細かく制御しているようです。
一応ドキュメントには、多くの要素を配列に追加する場合、 ~= で追加するより効果的です、とだけ書かれています。
(なので今回のように3個程度の追加だと実際効果はあまりないと思われます)
投票数:0 平均点:0.00
返信する
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2013/7/17 0:54
MJun 
SHOOさん解答ありがとうございます
特に「D言語らしい」書き方、Cとはやはり色々違いますね
便利な関数も色々知れたので、これから積極的に使っていきたいと思います
投票数:0 平均点:0.00
返信する

このトピックに投稿する

題名
ゲスト名
投稿本文

  条件検索へ


メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu