質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

5回答

1042閲覧

n次元ポインタはどのように定義(宣言)すればよいのでしょうか?

YUKI007

総合スコア10

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2021/05/25 14:24

例えば,3次元の char 型ポインタでしたら,

char ***ptr;

と表現すれば良いと思うのですが,これが例えば,次のソースコードのように変数dimの値によって,dim次元の char 型ポインタを定義したい場合,どのように記述すればよいのでしょうか?

void func(int dim) { // dim次元の char 型ポインタ ptr を定義したい return; } void main(void) { int dim=3; func(dim); }

どなたかわかる方いらっしゃいましたら,教えていただきたいです.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/05/25 22:58

なぜそのようなことが必要になったのでしょうか?
YUKI007

2021/05/26 05:05

n次元配列のメモリ確保をする関数を作成したく,その際に,整数引数dimによってdim次元ポインタを定義する必要がありました. 例えば,3次元配列のメモリ確保関数ですと,次のようになります. define ALLOC_CUBIC(T,U,V,W) (T***)AllocCubic(sizeof(T),U,V,W) void*AllocCubic(int s, int u, int v, int w) { int i,j; int t=s*w, p=sizeof(char*); char ***a,**b,*c; a=(char***)malloc(p*u + p*u*v + s*u*v*w); if(a){ b=(char**)(a+u); c=(char*)(b+u*v); }else return 0; for(i=0;i<u;i++){ a[i]=b; for(j=0;j<v;j++){ b[j]=c; c+=t; } b+=v; } return a; } 3次元とわかっていれば, char ***a,**b,*c; また,4次元とわかっていれば, char ****a,***b,**c,*d; と定義すればよいのですが,dim次元の場合,どのように定義すればよいのか知りたく,質問させていただきました.
thkana

2021/05/26 12:19

一応... 型 **a;は二次元配列とは関係ありませんし、 型 ***b;は三次元配列とは別物です。 *がn個ついたポインタはn次元のデータ構造を表すのに使えますがn次元のポインタとは呼びませんし、それで表されるデータ構造はCの用語において決して「n次元配列」と呼ばれるものではありませんので勘違いなきよう。 (Javaだったらちょっと事情は違うかもしれませんが。)
yominet

2021/05/27 12:20

コーディング段階で動的な次元数のポインタ変数の定義はできないといったことは、 他の方の回答で済んでいると思うので、動的な次元数を扱う選択肢の提案を。 使用が許されるのであれば、OpenCVのMatを使うという手も。 データにアクセスするためのat()等も準備されてます。 内部的には連なったメモリでアクセスも早いと思います(計っていないですが)
guest

回答5

0

文字通りにはどうしようも無いので、void *で宣言しておいて、参照の際に必要に応じてキャストするのでしょうか。

投稿2021/05/25 15:20

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

実行速度などの要件がシビアでなければHow can i create an n-dimensional array in cでの回答はいかがでしょうか。

  • 常に1次元の領域を確保する。
  • n次元→1次元上の配列位置を算出してアクセスする。

とする手法です。

投稿2021/05/26 10:05

can110

総合スコア38341

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asm

2021/05/26 10:14

むしろCPUが上手いことやってくれそうな分 多重ポインタよりも速く、ポインタ分省メモリ と要件シビアなほど1次元化が有利な気がしますね (乗算器がない場合などには話変わりますが・・・)
can110

2021/05/26 10:29

コンパイル後のコードやCPUなどの低水準の知識がないので、位置算出のコストが大きくなりそうで気になったのですが、そうなんですね。 提示URLでも走査パターンやアルゴリズムを工夫することで位置算出コストを減らすことができる可能性があることも示されていますから、案外よい手法かも。
guest

0

C++初心者なので,下記はクソみたいなコードですが,
何かこんな感じのをもっとまともに作れないものですかね?

C++

1class SomeDimArray 2{ 3public: 4 //ctor 5 //各次元のサイズと,何次元なのかを指定 6 SomeDimArray( const size_t *Sizes, size_t Dim ) 7 : m_Dim(Dim) 8 { 9 if( Dim>1 ) 10 { m_LowerLV.assign( Sizes[0], SomeDimArray( Sizes+1, Dim-1 ) ); } 11 else 12 { m_Vals.assign( Sizes[0], 0 ); } 13 } 14 15 size_t Dim() const { return m_Dim; } 16 17public: 18 //要素アクセス手段(const版は省略) 19 //1次元じゃないときは()でアクセスし, 20 //1次元のときは[]でアクセスするという… 21 SomeDimArray &operator()( int idx ){ return m_LowerLV[idx]; } 22 int &operator[]( int idx ){ return m_Vals[idx]; } 23 24private: 25 size_t m_Dim; //次元 26 //以下のどっちかを持つ 27 std::vector<int> m_Vals; //自分が1次元だったらここにデータ値を持つ 28 std::vector<SomeDimArray> m_LowerLV; //自分が (k>1)次元 だったら, (k-1)次元のやつらをここに持つ 29}; 30 31//main 32int main(void) 33{ 34 //3次元配列を作ってみるよ 35 size_t Sizes[] = { 2,3,4 }; 36 SomeDimArray A( Sizes, 3 ); 37 38 //要素アクセス. 39 A(0)(1)[2] = 9; //嫌な書き方だ… 40 41 return 0; 42}

投稿2021/05/27 05:17

編集2021/05/27 05:31
fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C/C++では型はコンパイル時に決定していないといけませんので
ご質問のように仮引数によって動的に型を決定する事はできません。


C++においてはテンプレートによって作れました。
が、前述のようにコンパイル時にDimが決定されている必要があったりと実用的かは微妙です

c++

1#include <array> 2 3template <typename T, size_t Dim> 4struct NPtr{ 5 typedef NPtr<T,Dim-1>::type* type; 6}; 7 8template <typename T> 9struct NPtr<T,0>{ 10 typedef T type; 11}; 12 13template<typename T, size_t Dim, typename... Args> 14NPtr<T, Dim>::type AllocDim(Args... _width){ 15 static_assert(Dim == sizeof...(_width), "sizeof...(_width) must equal Dim"); 16 std::array<size_t, Dim> width = {_width...}; 17 size_t elements = 1, points = 0; 18 for(size_t i = 0; i < Dim; i++) { 19 points += elements; 20 elements *= width[i]; 21 } 22 points -= 1; 23 size_t size = elements * sizeof(T) + points * sizeof(void**); 24 void* result = malloc(size); 25 if(!result) 26 return nullptr; 27 void** it = (void**)result; 28 char* data = (char*)(it+points); 29 size_t memo = 0; 30 size_t t = 1; 31 for(size_t i = 0; i < Dim-2; i++) { 32 size_t w = width[i], diff = width[i+1]; 33 memo += w; 34 t *= w; 35 void** base = it; 36 for(size_t l = 0; l < t; l++) { 37 *it++ = (void*)(base + memo + l * diff); 38 } 39 } 40 size_t last = width[Dim-1]; 41 for(size_t i = 0; it < (void**)data; i++) { 42 *it++ = (void*)(data + last * i * sizeof(T)); 43 } 44 return (typename NPtr<T, Dim>::type) result; 45} 46 47int main(){ 48 char*** ptr = AllocDim<char, 3>(3,2,2); 49}

投稿2021/05/26 10:39

編集2021/05/27 00:18
asm

総合スコア15149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そもそもの問題として、STLのvectorを使ってはだめでしょうか。
使ってよいのであれば、いちいち、AllocCubicなどの実装する必要はありません。

例えば、3次元であれば以下になります。
STLのstringを使った版も入れてあります。

c++

1#include <string> 2#include <vector> 3using namespace std; 4 5int main(void) { 6 int U, V, W; 7 int size; 8 // 3次元 9 vector<vector<vector<vector<char>>>> s1( 10 U, vector<vector<vector<char>>>( 11 V, vector<vector<char>>(W, vector<char>(size)))); 12 // stringを使用 13 vector<vector<vector<string>>> s2( 14 U, vector<vector<string>>(V, vector<string>(W))); 15 return 0; 16}

投稿2021/05/26 09:53

akiruno-oneone

総合スコア815

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/05/26 10:05

> 例えば、3次元であれば… とのことですが, 本件の問題点とは「その次元が未知である(動的に与えられる)ときに,どうすればよいのか?」という話と見えます. その点を解決する回答になっているのでしょうか?
akiruno-oneone

2021/05/26 11:33

そもそもとお断りをしたのは、型は動的に宣言できないと思います。 質問のなかで、3次元配列ををマクロで定義されています。 vectorを使用すれば、いちいち質問のなかで回答されているような新しい関数を定義する必要はないと考えます。 その使い方から、別の案を提示しました。
fana

2021/05/27 04:33

[質問への追記・修正、ベストアンサー選択の依頼] にて示されている AllocCubic/ALLOC_CUBIC は, 「3次元とわかっていれば」このような実装ができるが… という話の上での例でしかなく,このAllocCubicの別の形の実装が必要とされているわけではありません. 「静的に定まる次元数3の配列」をvectorを用いて実現する話というのは, 例えば, 「動的に与えられる場合は無理です.(←とりあえずこれが回答だとして)  ところで,それはそれとして,そのAllocCubicのようなものはvectorを用いれば…」 みたいに触れられるような,質問への回答ではないサブの話題かと.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問