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

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

ただいまの
回答率

90.85%

  • C

    3201questions

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

構造体のポインタ配列とポインタ配列について

解決済

回答 6

投稿

  • 評価
  • クリップ 0
  • VIEW 1,508

ikuo-biyori

score 48

いつもお世話になっています。C言語初心者でただいま勉強中です。構造体のポインタ配列とポインタ配列について質問させていただきます。
ポインタ配列の解釈は、以下でただしいでしょうか?
ex1)char *p[4];
char *p[4]は、書き込みができないだけで同じようにchar p[4](文字型の配列)として使える。
配列名pは、p[0]のアドレスを指す。(p=&p[0])
よって、
*p=p[0];
*(p+1)=p[1];
*(p+2)=p[2];
*(p+3)=p[3];

ポインタpが、配列pを表す。

構造体のポインタ配列の解釈は、以下でただしいでしょうか?
ex2)typedef struct{
int x;
int y;
}A;/*Aという構造体の型を作る。*/
A *p[4];
A *p[4]は、書き込みができないだけで同じようにA p[4](構造体A型の配列)として使える。
配列名pは、p[0]のアドレスを指す。(p=&p[0])
よって、
*p=p[0];
*(p+1)=p[1];
*(p+2)=p[2];
*(p+3)=p[3];
したがって、
*p.x,*p.y
*(p+1).x,*(p+1).y
*(p+2).x,*(p+2).y

ポインタpが、構造体配列pを表す。

ex3)A B[4];
A *p;
配列名Bは、B[0]のアドレスを指す。(B=&B[0])
この構造体をポインタpで表したいから、p=&B[0]を
する。*p.x,*p.yで表せる。
ex2で、p=&p[0]をしなかったのは、構造体pをポインタpで表すから(構造体変数とポインタ変数の名前が同じ)

この解釈であっていますか?

自分の解釈があっているか教えて下さい。長文で失礼しました。よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 6

+1

いろいろ間違っています。

ポインタの配列である以上、a[1]*(a + 1)の型はポインタです。中身にアクセスしたければ、もう一回の逆参照が必要となります。そして、中身を入れるための領域も適宜確保する必要があります。

なお、どのような型の配列に対しても、配列arrと整数idxについてarr[idx] == *(arr + idx) == idx[arr]となります。むしろ、これが添字演算子の定義です(最後みたいな書き方はしないでしょうが)。

あと、構造体へのポインタpに対してメンバのmemberを使う場合、*で書くには演算子の優先順位の関係上*p.memberではなく(*p).memberと書く必要があります。実用上は、p->memberと書くことがほとんどです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

0

ex1)char *p[4]; 
char *p[4]は、書き込みができないだけで同じようにchar p[4](文字型の配列)として使える。 

*p[4]は、ポインターが4つの配列の定義で4か所別々に文字のアドレスを格納する事ができます、
char p[4]は、アドレスpから始まる連続した4文字を表します。

char *p[4];
char a[4] = {'A','B','C','D'};
*p=a;
*(p+1)=&a[1];
*(p+2)=&a[2];
*(p+3)=&a[3];
printf("%s %s %s %s",p[0],p[1],p[2],p[3]);

ex2)typedef struct{ 
int x; 
int y; 
}A;/*Aという構造体の型を作る。*/ 
A *p[4]; 
A *p[4]は、書き込みができないだけで同じようにA p[4](構造体A型の配列)として使える。

*p[4]は、構造体Aへのポインタを4つ定義する配列です。A p[4](構造体A型の配列)とは異なります。

typedef struct{
    int x;
    int y;
}A; /*Aという構造体の型を作る。*/
A *p[4];
A B[4]={{10,11},{20,21},{30,31},{40,41}};
*p=&B[0];
*(p+1)=&B[1];
*(p+2)=&B[2];
*(p+3)=&B[3];
printf("%d %d\n", (*p[1]).x, (*p[1]).y);

ex3)A B[4]; 

上記の様に(*p[1]).x, (*p[1]).yと表す事ができます。

ここの部分がわからないです。なぜp=a; (p+1)=&a[1]; (p+2)=&a[2]; (p+3)=&a[3]ではないのですか?

A *p[4];の意味は、構造体を指す事ができるポインターが4個格納できるエリアとして定義しています。
定義はしましたが、中のアドレスは空っぽなので構造体のアドレスを入れています。
ポインタ配列へのアドレス代入なので、p[0]=&a[0]; p[1]=&a[1]; p[2]=&a[2]; p[3]=&a[3]; と書く事ができます。
配列要素のp[1]は、*(p+1)とも書くことができます。(p+1)は、配列の2番目のアドレスなので変更は不可です。
例)printf("%d %d %d\n", (*p[1]).x, (*p[1]).y, (*(p+1))->x);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/13 17:39 編集

    すみません、
    *p=a; *(p+1)=&a[1];
    *(p+2)=&a[2];
    *(p+3)=&a[3];
    ここの部分がわからないです。なぜp=a; (p+1)=&a[1]; (p+2)=&a[2]; (p+3)=&a[3]ではないのですか?
    ex)double x,*p;
    p=&x;
    x=3.14;
    というようにp(pにはアドレスをいれるから)には&変数名を代入しないといけないと自分では解釈していたんですが。
    すみませんが、教えて下さい。よろしくお願いします。

    キャンセル

  • 2017/01/13 18:50

    p[0],p[1],p[2],p[3]は全てアドレスを示し、その中身は(*p[0]),(*p[1]),(*p[2]),(*p[3])で表せる。pはポインタであり、配列名である。
    配列名pはp[0]のアドレスを示す。(p,p[0]はポインタ)
    *p=p[0]とはp[0]の中身を示すのではなく、p[0]のアドレスを示す。ということは、ポインタがポインタを示す。この解釈であっていますか?

    キャンセル

  • 2017/01/13 19:13

    pは配列のポインタと考えて良いので解釈は合っていると思います。
    p[0]は配列の一番目の箱をさしていますので、p[0]=&a[0];で構造体アドレスを入れる事ができます。格納したポインタアドレスで参照する際は、(*p[1]).x, (*(p+1))->x で値をポイントできます。

    キャンセル

  • 2017/01/17 18:58

    ポインタがポインタをさすことや、ポインタ配列、構造体のポインタについてよく分かりました。教えていただき、ありがとうございました。

    キャンセル

0

色々と突っ込みどころはあるので、最初の方だけ触れておきます。

char *p[4]は、書き込みができないだけで同じようにchar p[4](文字型の配列)として使える。 

違います。
書き込みもできるし、文字型の配列ではありません。
p[n]にはアドレスを入れることができます。
p[n]は前述の通りアドレスが入るので、文字型の配列としては使えません。

char a[4]char *a[4]のサイズを見てみれば一目瞭然です。
環境にもよりますが、32bit環境であれば、前者は4、後者は16になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

この辺、難しいですよね。

ex1)
char *p[4]は、書き込みができないだけで同じようにchar p[4](文字型の配列)として使える。 

全くの別物です。

char *p[4]は「char型変数へのポインタ」の配列です。各要素は「char型変数へのポインタ」です。argvと同じですね。
char p[4]は「char型変数」の配列です。各要素は「char型変数1つ」です。

①C言語仕様上、例えばchar p[4];と定義した時、単独のpはchar型変数へのポインタとして取り扱われます。
②C言語の標準ライブラリはchar型変数へのポインタをNULL終端文字列として取り扱うものがほとんどです。

①は様々な混乱や問題を生むのですが、①②を合わせて単純な言語仕様で文字列を取り扱えるようにするための工夫です。言語仕様を単純に保ちつつ標準ライブラリで様々な機能を提供すると言う発想は非常に優れていると思います。C言語開発当時に主流であったFORTRANやCOBOLにはそのような発想がないため、言語を拡張できるのはコンパイラメーカだけでした。その状況を大きく変えた優れた発想です。

ex2)
A *p[4]は、書き込みができないだけで同じようにA p[4](構造体A型の配列)として使える。 

ex1と同様です。
A *p[4]は「A型へのポインタ」の配列です。各要素は「A型へのポインタ」です。
'A p[4]'は「A型変数」の配列です。各要素は「A型変数1つ」です。

なお、先述の①はchar型以外の全ての配列について適用されます。
しかし、②はchar型だけの特例ですので、'A p[4]'のpを「NULL終端文字列」と同様な方式(NULLが来るまで処理を繰り返す)で処理する標準ライブラリ関数は存在しません。

ex3)
配列名Bは、B[0]のアドレスを指す。(B=&B[0]) 
この構造体をポインタpで表したいから、p=&B[0]をする。*p.x,*p.yで表せる。 

*p.xはコンパイル・エラーになります。*の前置演算子と.演算子では優先順位は.演算子の方が高いため、'.'はpにかかります。pはポインタなので.演算子の対象ではありません。

ex2で、p=&p[0]をしなかったのは、構造体pをポインタpで表すから(構造体変数とポインタ変数の名前が同じ)

この文章の意味が分かりませんでした。pが配列ならそもそもその記述はコンパイル・エラーになりますのでできません。(配列名は変数ではなく定数ですので、配列名への代入はできません。)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

質問されている内容については他の方が回答しているので、「ポインタ」についてのみ書きます。
プログラム内ではデータ型や構造体を付けたポインタを定義しますが、要はポインタ=アドレス格納領域です。
ポインタで変数を宣言すると、その変数はアドレスを格納するだけの領域が確保されます。
ポインタ配列(例えばchar *p[4];)と宣言すると、配列数分のアドレス格納領域(例であれば
アドレスを4つ格納できる領域)を確保したことになります。
そのアドレス領域に宣言したデータ型や構造体の実体(質問者の言葉を使えば「書き込みできる」変数)の
先頭アドレスを格納して使用します。
データ型(構造体)の実体をmalloc()等で動的に確保し、その先頭アドレスをポインタの配列(ポインタの
ポインタ)に格納する等の使い方が多いように思います。

説明が下手で申し訳ないですが、質問文からポインタについては、なんとなくで理解されているように思います。
ポインタはC言語の肝(壁)なのでわからなくなったときは基本を見直して、ひとつひとつ理解を進めていくと
良いかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ポインタは主記憶のアドレスを格納するための変数です。
ですから、型に関係なくサイズは一定です。(たとえば32ビットとか)
ポインタの型というのは、格納されたアドレスに確保されている変数の型なのです。
ポインタに、宣言やmalloc関数などで確保されていない領域のアドレスが格納されていると、そのポインタを参照したときに暴走したりします。
ポインタに、ポインタのアドレスを代入することも出来ます。
ポインタに構造体のアドレスを代入することも出来ます。
その際、すでにご指摘されているように、*p.x ではなく、p->x もしくは (*p).x と記述します。
もちろん、p には確保された構造体のアドレスが入っていなければなりません。
コンパイルエラーは出ないけど、実行時にバグります。
ポインタ配列は、ポインタ変数が主記憶上に連続して確保されている領域です。
アドレス集みたいなものですね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.85%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    ポインタ渡しと文字列比較

    C言語初心者です。 文字列rawcがリストlistの中に入っていない(登録されていない)とき、 その文字列をリストの登録されている最後に格納する関数regを作成しました。 既に登

  • 解決済

    C言語の文字列がわかりません

    この p1 = str1 + strlen(str1) - 1;ていうのがわかりません 最初の文字に足していって最後の文字を示していますが、それだったら p1 = strlen(s

  • 解決済

    ポインタのポインタについて教えてください

    http://ppp-lab.sakura.ne.jp/ProgrammingPlacePlus/c/037.htmlの中の int compareStringFor_qsort

  • 解決済

    char *, char**, char***の違い

    とても疑問に思っていることがあります。 ウェブサイトでCharについて調べていると、"char * * "や"char* * *"と記載してあるコードがありました。 自分な

  • 解決済

    Char * * * 型の値の取得方法

    前提・実現したいこと 前回の質問で、char * と char * *, char * * * について質問致しました。 char * * * str にはアドレスが入って

  • 受付中

    ダブルポインタについて

    先ほど質問した内容と重複する部分もありますが、お許しください。初心者なので分かりやすく説明して頂けると助かります。 この関数を利用するために、下記①のように宣言しました。

  • 解決済

    C言語のポインタについて

    1、C言語のポインタについて以下のように書くとエラーが出る理由をおしえてください。 int *w; *w = 5; 2、なぜアドレスで初期化しないといけないんですか??

  • 解決済

    「&配列名」の意味について

    初質問です。 確認のための質問なのですが... 現在読んでいる本でchar array[];と宣言した1次元配列について、「&arrayはchar*型のarrayにアドレス演算子を

同じタグがついた質問を見る

  • C

    3201questions

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