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

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

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

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

Q&A

解決済

6回答

10248閲覧

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

ikuo-biyori

総合スコア56

C

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

0グッド

0クリップ

投稿2017/01/11 21:39

いつもお世話になっています。C言語初心者でただいま勉強中です。構造体のポインタ配列とポインタ配列について質問させていただきます。
ポインタ配列の解釈は、以下でただしいでしょうか?
ex1)char *p[4];
char *p[4]は、書き込みができないだけで同じようにchar p4として使える。
配列名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 p4として使える。
配列名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で表すから(構造体変数とポインタ変数の名前が同じ)
この解釈であっていますか?

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

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

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

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

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

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

guest

回答6

0

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

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

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

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

投稿2017/01/11 22:47

maisumakun

総合スコア145186

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

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

0

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

投稿2017/01/15 16:07

編集2017/01/15 16:14
HidekoSaeki

総合スコア42

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

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

0

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

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

投稿2017/01/12 02:34

Take-y

総合スコア91

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

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

0

こんにちは。

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

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

全くの別物です。

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 p4として使える。

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が配列ならそもそもその記述はコンパイル・エラーになりますのでできません。(配列名は変数ではなく定数ですので、配列名への代入はできません。)

投稿2017/01/12 02:00

Chironian

総合スコア23272

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

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

0

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

char *p[4]は、書き込みができないだけで同じようにchar p4として使える。

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

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

投稿2017/01/12 01:28

ttyp03

総合スコア16998

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

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

0

ベストアンサー

ex1)char *p[4];

char *p[4]は、書き込みができないだけで同じようにchar p4として使える。

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

c

1char *p[4]; 2char a[4] = {'A','B','C','D'}; 3*p=a; 4*(p+1)=&a[1]; 5*(p+2)=&a[2]; 6*(p+3)=&a[3]; 7printf("%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 p4として使える。

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

c

1typedef struct{ 2 int x; 3 int y; 4}A; /*Aという構造体の型を作る。*/ 5A *p[4]; 6A B[4]={{10,11},{20,21},{30,31},{40,41}}; 7*p=&B[0]; 8*(p+1)=&B[1]; 9*(p+2)=&B[2]; 10*(p+3)=&B[3]; 11printf("%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/12 01:06

編集2017/01/13 09:47
A.Ichi

総合スコア4070

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

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

ikuo-biyori

2017/01/13 08: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にはアドレスをいれるから)には&変数名を代入しないといけないと自分では解釈していたんですが。 すみませんが、教えて下さい。よろしくお願いします。
ikuo-biyori

2017/01/13 09: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]のアドレスを示す。ということは、ポインタがポインタを示す。この解釈であっていますか?
A.Ichi

2017/01/13 10:13

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

2017/01/17 09:58

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問