char (*p)[10];
>>>char型の要素を10個持つ配列へのポインタ!
これの使い道がわかりません。
C
1int (*arp)[10]; 2 3// アドレスを入れるときは以下のように入れます。 4 5int array_ten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 6arp = &array_ten;
普通に、int *arp = array_ten; で良いような気がします。
わざわざ要素数が固定のポインタに渡す必要性が見えません。
「あ!ポインタのポインタの初期化に使えるかな?」と思い、以下のようにしてみました。
C
1char buf[3][100] = { 2 "nononono!!", 3 "I love you!", 4 "Thanks" 5 }; 6 7 char **p; 8 // char *q[3] = {buf[0], buf[1], buf[2]}; こっちは成功 9 char (*q)[100] = buf; 10 p = &q;
これをやると、warningが出てきて、さらに落ちます・・・・
なぜかわかりませんが・・・
char (*p)[10];
関数に2次元配列を渡す時と、列を動的確保したい時ぐらいしか、出番がないような気がするんですが・・・・
char (*p)[10];
この子の他の使い方はあります??
プログラムの例を見ているとよく出てきます。
printf("p[1] : %p, p[1][0] : %p\n", p[1], &p[1][0]);
おまけに2次元配列のようにアクセスもできています・・・・!?
正直、よくわかってないです。
どなたか教えてください!
[追記]
char array[4][10]
char (*arp)[10] = array;
たとえば、こうなった場合・・・
arpという1つのポインタが4つの配列の先頭アドレスを指しているということですよね?
・・・・??
なんかおかしくないですかね?
たった1つしかないポインタが同時に4つのアドレスを指しているなんて・・・
どういうことですか??
[追記2]
ポインタのポインタの初期化について、考察してもらっている方もいらっしゃるのですが、
char array[4][10]
char (*arp)[10] = array; ← arpはポインタで要素数4つの配列の先頭アドレスを持っていると思います。
つまり・・・・・一次元配列・・・ということになりますよね??
arp[0], arp[1] ・・というのが、要素数10個ある配列の先頭を表すことで、あたかも2次元配列のようになる
と解釈しました。
しかし、
char ii[4] = "GHYU"; char *qq = ii; char **pp = &qq; // char *pp = &qq; これは無理!
これは、問題がありません。
ポインタのポインタを初期化できています。
char (*arp)[10]; はこれに似ていと思います。
あたかも「char ii[4] = "GHYU";」+「char *qq = ii;」これを1つにしたような感じです。
G, H, Y, U が要素数10個配列の先頭の文字だと想像してください。
なのに、最初の質問のように・・・
char (*q)[100] = buf;
p = &q
これができない理由が・・・見当たらないです。
「データ構造が違うから初期化できない」
上記のプログラムができているので、むしろ初期化できないとおかしいような気がします。
[修正]
大変申し訳ありません。
int型とchar型を混合してしまいました。
修正しまいした。
すべてchar型です。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答9件
0
int型は4バイト、int[10]型は40バイトだから
int型のポインタはポインタ演算で4byte進もうとするけど
int[10]型のポインタは40byte進もうとするんだ
C++
1#include <iostream> 2using namespace std; 3 4int main() { 5 int *singlep = 0; 6 int (*arrayp)[10] = 0; 7 cout << (unsigned int)singlep << endl << (unsigned int)(singlep+1) << endl; 8 cout << (unsigned int)arrayp << endl << (unsigned int)(arrayp+1) << endl; 9 return 0; 10}
この小さなコードを実行してみて欲しい。
こんな感じで結果がでるはずだ。
0 4 0 40
ポインタにも細かい型の違いがあるんだよ
ポインタと配列が違うっていう人もいるけど、この動きは配列の時でも何も変わらない
C++
1#include <iostream> 2using namespace std; 3 4int main() { 5 int array[2][10] = 0; 6 cout << (unsigned int)array << endl << (unsigned int)(array+1) << endl; 7 return 0; 8} 9 10> 4290089120 11> 4290089160
追記
ポインタはアドレスの先頭を指している。一つのint型は4バイト使うので、もしも隣接する要素もint型なら次の4バイトは4バイト先のアドレスから始まる。型の大きさはプログラミングする上で重要な要素なんだ。受け取ったポインタが配列だった場合、次の要素の位置を簡単に指し示すことができるからね。
C++
1#include <iostream> 2using namespace std; 3 4int main() { 5 char str[12]; 6 char *p = str; 7 *(p+0) = 'H'; 8 *(p+1) = 'E'; 9 *(p+2) = 'L'; 10 *(p+3) = 'L'; 11 *(p+4) = 'O'; 12 *(p+5) = ' '; 13 *(p+6) = 'W'; 14 *(p+7) = 'O'; 15 *(p+8) = 'R'; 16 *(p+9) = 'L'; 17 *(p+10) = 'D'; 18 *(p+11) = '\0'; 19 cout << str; 20 return 0; 21} 22 23> HELLO WORLD
C++
1#include <iostream> 2using namespace std; 3 4int main() { 5 char str[3][100] = { "Line1", "Line2", "Line3" }; 6 char *p = (char *)str; 7 cout << p << endl << p+1 << endl; 8 9 p = (char*)((int)p + 100); 10 cout << p << endl << endl; 11 12 char (*arrayp)[100] = str; 13 cout << *arrayp << endl << *(arrayp+1) << endl; 14 15 return 0; 16} 17 18> Line1 19> ine1 20> Line2 21 22> Line1 23> Line2
型情報には、アドレスをどうシフトさせたら次の要素が参照できるのかが得られるだけの差別化がある。
**
ポインタのポインタは4バイトシフトするポインタだが、要素数100のchar型の配列のポインタは100バイトシフトするポインタなわけで、全然別ものなんだよね。
C++
1#include <iostream> 2using namespace std; 3 4int main() { 5 char *p = 0; 6 char **pp = 0; 7 char (*ap)[100] = 0; 8 cout << (unsigned int)(p+1) << endl; 9 cout << (unsigned int)(pp+1) << endl; 10 cout << (unsigned int)(ap+1) << endl; 11 12 return 0; 13} 14 15> 1 16> 4 17> 100
更に追記
どんな時に使うのかが質問だった。
まず、char **p
とchar (*p)[100]
の違いはなんですかって質問を見つめなおそう。
こいつはね、ポインタのポインタ
と配列のポインタ
の違いを聞いてる。
これはもっと抽象化すると、ポインタのポインタ
とある型のポインタ
の違いを聞いてる。
これがわかるかどうかはstrike君次第だけど…
記法よりも、何をしているのかに着目してほしい。
これはプログラミングっていうより国語の問題だ。
ポインタのポインタ
とある型のポインタ
は根本的に別物だよ。
char **p
とint *p
の違いはなんですかって言ってるのと本質的には大差無い。
ある型のポインタ
の型
には配列の型
も指定できるんだよ。それがchar (*p)[100]
って記法だ。
だから、あるポインタをある配列のポインタに変換することもできる。
C++
1char c[100*5]; 2char (*ap)[100] = (char(*)[100])c; 3 4char a[5][100]; 5char *cp = (char*)a;
このコードはコンパイル通るし、お互いの範囲内で使う分には安全だよ。
cもaも変数としては連続した500バイトのメモリアドレスを確保していてどのようにアクセスするかが違うだけだ。
下記は今じゃまず使わないけどこのサンプルで配列型のポインタの使い方を示しているつもりだ。
C++
1#include <iostream> 2using namespace std; 3 4void char100print(char (*str)[100], int length) 5{ 6 for (int i = 0; i < length; i++) 7 { 8 cout << *str++ << endl; 9 } 10} 11 12int main() { 13 char value[][100] = {"test1", "test2", "test3", "test4"}; 14 15 char100print(value, 3); 16 17 return 0; 18} 19 20> test1 21> test2 22> test3
より具体的なサンプルも示そう。
昔は固定長のファイルが多かった。
今でも現役の固定長フォーマットに全銀協制定フォーマットがある。
銀行でお金を振り込んでくださいってことをするファイルだ。
これは120バイト(固定)を1行として使うファイルなんだ。
ファイルの読み書きは行単位ではなく、120バイト単位にしなきゃならない。
C++
1ZENGIN ReadZenginFormat(const char *p, int record_num); 2 3ZENGIN ReadZenginFormat(const char (*p)[120], int record_num);
このサンプルは上下で情報量が全然違うよね。
でも動作原理はまったく一緒だし、読み取るための関数だから参照先アドレスを編集することがないのでconst
属性がついてる。
record_num=5の場合、pはとあるアドレスを参照しており、そこから連続した600バイトのメモリが確保されている。
一方、以下は全く意味が異なる。
C++
1ZENGIN ReadZenginFormat(const char **p, int record_num);
pは…ポインタのポインタの配列なんだろう。読み取り専用だしね。
でもそうなると、ポインタそのものは5行であったとしたら、pのアドレスから確保されているバイト数はわずか4*5バイト=20バイトだ。
その20バイトの中に、5つの文字列のポインタが入っているわけだ。
使い方を示すとこうだ。
C++
1char *p[5]; 2p[0] = malloc(120); 3p[1] = malloc(120); 4p[2] = malloc(120); 5p[3] = malloc(120); 6p[4] = malloc(120); 7 8ReadZenginFormat(p, 5);
ポインタそれぞれに別の文字列の参照を持つ。
p[0]からp[4]で参照しているメモリアドレスは別に連続したメモリ空間じゃない。
一旦次のポインタに移動して、そこから別の文字列を参照する。
これは配列のポインタ
とは構造が全く異なるんだよ。
ポインタのポインタ
と配列のポインタ
には互換性が無いんだ。
互換させる場合はこうなる。
C++
1char a[5][120]; 2char *p[5]; 3p[0] = a[0]; 4p[1] = a[1]; 5p[2] = a[2]; 6p[3] = a[3]; 7p[4] = a[4]; 8 9ReadZenginFormat(p, 5);
わかるかな。
a[0]は先頭アドレスを指している。
a[1]はその120バイト先のアドレスを指しているが、a[1]には大きさがあるわけではない。
a[1]で指示される場所が120バイト先のアドレスというだけだ。
一方、p[1]はアドレスを保存するための変数として4バイト確保されている。
そこに代入している。
投稿2017/01/24 07:52
編集2017/01/24 11:15総合スコア1593
0
こんにちは。
普通に、int *arp = array_ten; で良いような気がします。
私もそう思います。
折角頑張って要素数を付けても、C/C++では直ぐに要素数が抜け落ちて単なる要素へのポインタに成り下がってしまいますので、コンパイル・エラーの元になりがちです。
C++で特殊なケースで使ったことありますが、上記問題で頭が痛かったことがありました。
printf("p[1] : %p, p[1][0] : %p\n", p[1], &p[1][0]);
おまけに2次元配列のようにアクセスもできています・・・・!?
pは「char型10個」へのポインタです。ポインタは配列に読み替えることができますね。なので、p[1]はp[0]の「次」の「char型10個」の要素です。
「char型10個」は10バイトですからp[0]のアドレスに+10したらp[1]のアドレスになります。
まじで解りにくいですね。可能な場合はstruct element { char data[10]; };
などとして、element* p;
と定義した方が読みやすいし、バグりにくいと思います。
投稿2017/01/23 03:47
総合スコア23274
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
前の質問で
char buf[3][100] = { "you will make me happy", "I love you!", "Thanks" }; char **p; char *q[3] = {buf[0], buf[1], buf[2]}; p = q;
char **p = buf; こんな事をしたいというのがありましたが
char (*p)[100]=buf; こんな風に使います。
int main() { char buf[3][100] = { "you will make me happy", "I love you!", "Thanks" }; char(*p)[100] = buf; printf("%s\n", p[0]); printf("%s\n", p[1]); printf("%s\n", p[2]); return 0; }
ネットなどの多くの解説で「配列とポインタはよく似ている」「配列でもポインタでも同じ処理を書ける」などの文章から感覚が同じものの様になっているのではないでしょうか。
その結果が
char **p = buf;
2次元配列をダブルポインタに入れようとしていることではないかと思ってしまいました。
配列とポインタは相互に入れ替えできる部分はあっても別物です。
投稿2017/01/23 03:39
総合スコア350
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
これをやると、warningが出てきて、さらに落ちます・・・・
なぜかわかりませんが・・・
手元のGCCでコンパイルするとp = q;
の行で、
"warning: assignment from incompatible pointer type ..." となりました。「pとqでは互換性が無い(?)のに、代入して大丈夫なのか?」という警告です。要するに「型が違う」のだから、warningを消す手立ては、まずキャストでしょう。即ち、
C
1 char **p; 2 3 p = (char**)q; // キャストする
これでwarningが消えますが、手立ては他にもあります。ポインタpの宣言を変更すれば良い。即ち、
C
1 char (*p)[100]; // p を、こう宣言する 2 3 p = q; // キャスト不要
以上は、char **
とchar (*)[100]
を、コンパイラは型として扱っている事、しかも明確に異なる型だと区別している事を示しています。
char **
は、ポイントしてる先のcharが、1個なのか10個なのか、それとも100個なのか、サイズの指定はありません。
それに対して、char (*)[100]
は、個々の要素は同じくcharだけど、「100個のcharをひとかたまり(100バイトを一つのデータ型)と見るポインタ」だという宣言です。こちらにはサイズの指定があるので、区別がつきます。
一般的に言えば、「固定長の配列」を一つの型として扱える…そう考えれば、そのようなデータ構造は、決して珍しくないはずですから、そうした管理がふさわしければ使う価値があると思います。ただ実際は、通常の(サイズ指定をしない)ポインタでアクセスも操作も可能なので、いまいち出番が少ないかもしれませんね。
投稿2017/01/23 11:57
総合スコア1382
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
intと同じでよろしければ
c
1 int (*arp)[10]; 2 3 int array_ten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 4 arp = &array_ten; 5 printf("%d \n",(*arp+1)[2]); 6 7 char buf[3][100] = { 8 "nononono!!", 9 "I love you!", 10 "Thanks" 11 }; 12 13 char (*q)[3][100]; 14 q = &buf; 15 printf("%s \n",(*q)[1]); 16 17 char **p = (char **)(*q)[1]; 18 printf("%s \n",p); 19
int (arp)[10];arp1は、intの配列(要素10)へのポインタなので、代入の場合キャスト(int ()[10]) intの配列(要素数10)でポインタに変換する。
c
1int main() { 2 3 char ii[4] = "GHYU"; 4 char *qq = ii; 5 char **pp = &qq; 6 int array[4][10]={{1,2,3,4,5,6,7,8,9,0},{10,11,12,13,14,15,16,17,18,19}}; 7 int (*arp)[4][10] = (int (*)[4][10])array; 8 printf("%d \n", (*arp)[0][5]); 9} 10
実はこの方のページ を参考とさせて頂いています。
投稿2017/01/23 03:31
編集2017/01/24 08:13総合スコア4070
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
やはり、char (*p)[10];
1、列の動的確保
2、2次元配列で初期化できる → 関数に2次元配列を渡す!
この2つくらいしか、使い道が思いつきません・・・です。
投稿2017/01/25 19:40
総合スコア651
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
たとえば列数固定の行列を確保したいとき。
C++
1 // N行10列の行列を確保する 2 float (*p)[10]; 3 p = (float (*)[10])malloc(N * 10 * sizeof(float)); 4 ... N行10列の行列 p[i][j] として使う 5 free(p);
投稿2017/01/23 04:45
総合スコア16612
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ポインターのポインターでありさえすればいいのであれば
int **argp;
でよいわけですが、「10要素の配列へのポインター」であることを明確にしたいときに有用です。
int (*argp)[10];
と宣言することで10要素でない配列へのポインターを代入しようとしたとき(つまりバグ)コンパラーが警告を発してくれます。
C
1int b[9]; 2argp = &b; // <= 警告: 互換性のないポインタ型からの代入です
投稿2017/01/23 03:26
総合スコア18404
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
具体的にどんな時に使うかは人それぞれだと思いますが、
charポインタを10個ほしい時に使います。
投稿2017/01/23 03:18
総合スコア91
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/24 07:56
2017/01/24 08:38 編集
2017/01/24 11:12
2017/01/24 11:16
2017/01/24 11:20
2017/01/24 11:29
2017/01/24 11:36 編集
2017/01/24 11:42
2017/01/24 11:45
2017/01/24 11:48
2017/01/24 11:53
2017/01/24 12:03
2017/01/25 10:06 編集
2017/01/25 11:06
2017/01/25 11:20
2017/01/25 11:22
2017/01/25 11:30
2017/01/25 11:36
2017/01/25 11:39
2017/01/25 11:44
2017/01/25 11:51 編集
2017/01/25 11:48
2017/01/25 11:51
2017/01/25 12:02 編集
2017/01/25 11:54
2017/01/25 11:55
2017/01/25 12:05