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

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

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

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

Q&A

解決済

7回答

2528閲覧

p *p違いーポインタ

reotantan

総合スコア295

C

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

0グッド

0クリップ

投稿2015/09/02 11:38

intへのポインタ型
①でintへのポインタ型で変数pを定義する。
②でint型の変数xに20をいれる。
③変数pにxのアドレスをいれる。
④変数pの値を出力する
p と*pの明確な違いが分かりません。
どうやって理解すればいいでしょうか?

int main() { int* p ; ① int x=20; ② p = &x; ③ printf("%d", *p); ④ return 0; } コード

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

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

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

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

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

guest

回答7

0

int* p;という書き方が良くないです。int *p;と書いた方が良い。これは「*pがintである」という宣言です。
pがポインタで、*pがint(pがポイントしているメモリに入っている整数値)です。

補足:
1行目に書いたのは、空白をどこに入れるかの問題では無く、宣言文がどういう意味を持っているかという話です。
〇「pがintである」
×「pはint
である」・・・・「int*」という構文はありません

x = -y;を、x =- y;と書いて、「=-は符号反転して代入する演算子である」と主張すると変ですよね。空白の位置を変えても意味は変わらないし、今のCには=-という構文は無いし。
int*はintへのポインタを宣言する記法だ」はそれと同じくらい変です。

投稿2015/09/02 12:00

編集2015/09/02 14:33
otn

総合スコア84555

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

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

naga3

2015/09/02 23:37

自分int*の左寄せ派ですが、ポインタ宣言の*を右寄せにするか左寄せにするかは各人の自由かなと思います。 ちなみにC++作者のビャーネさんは左寄せ派だったと思います。
jimyo

2015/09/03 05:34 編集

個人的な考えですが、ぼくも左寄せ派です 特殊な「int型」とかんがえるよりは全く別物の「int* 型」と考えたほうがわかりやすいと思うからです。
mie

2015/09/03 06:21

個人的には右寄せに書いてしまうこともありますが、考え方としてはjimyoさんのように「 int* 型」(ポインタ型)と考え、「int 型」とは区別するほうがよいと思います。 typedef でポインタ型として定義することもありますし、 int* p = NULL ; と初期化する場合も明確になります。 コーディング規約で規定する場合やドキュメントでは、「左寄せ」に規定されることが多いように思います。
otn

2015/09/03 09:14

回答文中の補足に書きましたが、コーディングスタイルの話じゃなくて、初心者向けにC言語の文法の意味の話として書いています。文法的な意味をちゃんと理解している人が、コーディングスタイルを定める・従うのは別にかまわないと思います。 このあたりを、きちんと理解しておかないともっと複雑な型の理解で躓くと思いますので。
sharow

2015/09/03 10:06

他人に説明する場合には、好みだけの話ではないと思います。 例えば右寄せなら int *px, *py; と書けるものが、左寄せだと int* px, *py; とすべきなのか、int* px, * py; なのか、int* px; int* py; なのか、あるいはわざわざtypedef int* coord_ptr;とかするべきなのか、それらを説明(規定)しなければなりません。int* px, py; ではpyがポインタにならないことにも、初心者には一言必要でしょう。右寄せならその必要が無いので説明が楽です(*は識別子への修飾です、で済みます)。 文法上どっちが良い悪いという話ではなく、単に右寄せの方が初心者には説明が簡単ですという話です。 誰かのコーディング規約とか、えらい人がそうだから、ではなくて、初心者にまず必要なのは楽な方法だと思います。文法や構文を完全に分かった上でなら、完全に好みの話です。
reotantan

2015/09/03 11:25

なるほど、まず右寄せになれてみます。 ありがとうございました。
guest

0

p : pに格納されているメモリ上のアドレスを示す
*p: pに格納されているメモリ上のアドレスに格納されている値を示す

あなたが 東京都千代田区1-1-1に住んでいるとすると

p→東京都千代田区 1-1-1
*p→あなた

という感じです

投稿2015/09/02 11:50

編集2015/09/02 11:56
jimyo

総合スコア243

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

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

reotantan

2015/09/03 11:26

解説ありがとうございます
guest

0

ベストアンサー

以下の関係を知るには、コンピュータのメモリの扱いを知ることが不可欠だと思います。

p = *p

メモリは基本的に一次元の配列と同じです。
番地(アドレス)という形で、記憶領域(メモリ)は並んでいる順番に区画されています。
区画ごとの記憶容量は、基本的に1バイトです。

0x00番地からのメモリ内容が以下のようになっているとします。
(0x00 〜 0x07 の8バイトのメモリ内容を16進数表記しています。メモリ内容がすべて 0xFF になっているのは説明用だからです。実際はこの限りではありません。)

0x00: FF FF FF FF FF FF FF FF
0x08: FF FF FF FF FF FF FF FF
0x10: FF FF FF FF FF FF FF FF

仮にchar配列で 0x00番地からデータを定義した場合を考えます。

例1)

C

1char cNum[] = {0,1,2,3,4}; 2//配置されるデータ: 3//0x00: 00 01 02 03 04 FF FF FF

例2)

C

1char cNum[] = "01234"; 2//配置されるデータ: 3//0x00: 30 31 32 33 34 00 FF FF

例1の場合は、char配列に数値を格納しています。
{}の括りで配列に数値を収めた場合は、指定した値がそのまま配置されます。
ですので、0x00番地から5バイトの領域に 0x00〜0x04 が配置されます。

例2の場合は、char配列に文字列を格納しています。
文字列の場合は文字列データの最後に終端文字(0x0)が付されるので、実際のデータは {'0','1','2','3','4',0} と同じ意味を持つ記述になります。
従って、配置データの最後6バイト目に 0x0 がある事が分かります。(配置データは、文字列の表記より1バイト大きい。)

int型の場合は、コンピュータによってデータ幅が異なります。
最近のIntelCPUだと32bit幅が標準なので4バイトです。
(またIntel系のCPUはリトルエンディアンなので、メモリへは下位バイトから順に配置される点に注意。)

例3)

C

1int num[] = {0,1,2,3,4}; 2//配置されるデータ: 3//0x00: 00 00 00 00 01 00 00 00 4//0x08: 02 00 00 00 03 00 00 00 5//0x10: 04 00 00 00 FF FF FF FF

例4)

C

1int num = 0x1234_5678; 2//配置されるデータ: 3//0x00: 78 56 34 12 FF FF FF FF

p = *p についてもう一度考えますが、説明の都合、変数と変数のポインタを別々の変数定義にしてみます。

C

1int num1; 2int num2; 3int *pNum;

ここで num1 = 1; を行うと、メモリにはint値:0x0000_0001(32bit幅の数値:1)がセットされます。

0x??: 10 00 00 00 ..

仮に配置されるアドレスが 0x38 だった場合、pNum = # を実行すると pNum の値は 0x38になります。
(最近のCPUは32bitや64bit幅でのアドレス管理なので、実際にはもっと大きな数値が収まる。)

num2 = 0x10; を行うと、メモリにはint値:0x0000_0010(32bit幅の数値:0x10)がセットされます。
ここでnum2の配置されるアドレスが 0x3C だった場合、pNum = &num2; を実行すると pNum の値は 0x3Cになります。

この時のメモリの内容は以下の通りです。

0x38: 01 00 00 00
0x3C: 10 00 00 00

そして、この時 p = *p になる関係はどの変数になるかといえば、num2 = *pNum です。
pNum = 0x3C ですから、ポインタ:pNum のメモリにセットされた値は 0x10(=num2) です。

pNum = &num2; 直前だったらどうか。
pNum = 0x38 なので、num1 = *pNum です。pNumの指すアドレスの中身は 1(=num1)です。

具体的にメモリの配置をイメージする方が、多少は理解しやすいのではないかと思います。(何度も言いますが、動きを頭の中だけでトレースするのは大変なのでデバッガの利用がオススメです。)


違いですが、変数が値と1:1の関係であるのに対して、ポインタは1:nがあり得るところですかね。
プログラム中で利用する場合に変数の割り当て領域を覚えておくだけのものなので、別の変数にもなるワイルドカードみたいな扱いができます。

ちょっと違う視点で考えると、ポインタは「いろいろな種類の部品を取り付ける万能ジョイントの基本パーツ」です。型キャスト機能と併用すると異なるタイプの型も扱えるので、事実上なんでもポインタ経由で扱えるようになります。(それ故に闇の部分も濃いイメージが強いですが…)

その性質をどう利用するのか。という視点で見ると、いろいろ便利な実装が存在しますし、正直C言語にポインタがなかったら何ができるんだろう…というくらい、無いと幅が狭まってしまう機能です。

このあたりはC言語でいろいろプログラムを書いてみると有難味がわかってくるところだと思いますので、いっぱい実装を書くことが必要だと思います。

投稿2015/09/03 08:42

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

reotantan

2015/09/03 11:19

丁寧な解説ありがとうございました。 ポインタ奥深いですね、まだまだ勉強が足りないようです;;
guest

0

int *p はイント型ポインタです。
p = とすると p これに対して値を入れる、(アドレスが格納される)
*p = とすると *は覗き穴と覚えるとpの中身を見るてイメージですね。 *pは pの指すアドレスの中身です。

例文ですと
p = &x // p → x pはxを指す
print(*p) // は覗き穴だと考えてください p→x を指してるので p → x = 20 となっております
// pの中身は 覗き穴(
)p *p = 20

p → x
*p ||
↘ ||
20
図にするとこんな感じですね。

投稿2015/09/03 01:01

MasaakiIrie

総合スコア1021

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

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

reotantan

2015/09/03 11:19

のぞきあな、覚えやすい考え型ですね。 参考にさせてもらいます、ありがとうございました
guest

0

④変数pの値を出力する
printf("%d", *p);

よく見て下さい。本当に変数pの値を出力するなら、
printf("%d", p);
であるはずです。
ここでの*は間接演算子で、
*pと書けば、pの値(メモリ番地)に格納されている値を返します。

つまり④は
変数pが指す先の値(=*p)を出力する
です。

過去にも似たような質問があり、
ベストアンサーがとても分かりやすい説明だったので
参考にして下さい。


Cは紛らわしいことに*の意味が3つあります。
1.乗算a * b;
2.ポインタ型の宣言int* x;,int *x;
3.間接参照c = *p;

宣言ですが
int* xと書けば、xがintのポインタ型と言う意図を表わせ、
int *xと書けば、*xがint型と言う意図を表せます。
処理は一緒なので、しっくり来る方を使うといいです。

投稿2015/09/02 14:03

編集2015/09/02 15:10
ozwk

総合スコア13521

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

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

reotantan

2015/09/03 11:21

ポインタ型の宣言と間接参照で混乱していたみたいです。 分かりやすい解説ありがとうございました
guest

0

ためしに p を表示してみて
ください。

得体の知れない数字が
表示されると思いますが、
これは「変数xのアドレス」です。

*p は、p に格納されている
アドレスのメモリを参照する
という意味になります。

今、p には &x つまり x の
アドレスがセットされていますから、
*p は、x の値 20 を表示します。

投稿2015/09/02 13:51

umeaji

総合スコア101

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

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

reotantan

2015/09/03 11:21

解説ありがとうございました、やっと理解できました;;
guest

0

①でintへのポインタ型で変数pを定義する。

の文で「intへのポインタ型」が 「int*」で「変数」が「p」だと理解されているようですので、使い分ける時には

p : データが入っている入れ物を指す
*p : 入れ物の中に入っているデータを指す

とイメージしてみてはどうでしょうか。本来ならアドレスをからめて覚える方が正確に理解できると思いますが、とにかくイメージでもなんでも使い分けられるようにしていけば、だんだん理解できると思います。

ちなみに上記のイメージは私が仕事でC言語を最初に使ったときに先輩から教えてもらったものです。

投稿2015/09/02 12:00

編集2015/09/02 12:01
KoichiSugiyama

総合スコア3041

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

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

reotantan

2015/09/03 11:24

解説ありがとうございました、とても助かりました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問