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

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

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

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

Q&A

解決済

6回答

5204閲覧

ポインタ関数に際して、*(アスタリスク)を付けたり付けなかったりするのは

Heizo

総合スコア16

C

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

0グッド

0クリップ

投稿2020/03/17 07:06

現在「C言語10課 ポインタ編」という書籍を見ながら、C言語の勉強をしております。

以下のコード、関数内の2行目にて、
aのような変数と、ポインタ変数を区別するため、アスタリスクを付けて*pとするのは理解できます。

一方、
次の行のaを指す場合は、p=&a;というふうに、アスタリスクを付けないpとし、
次の次の行では、p=5;として、再びアスタリスクを付けたp としています。

この場合、両方ともアスタリスクを付けた*p、あるいは両方とも付けない方がスッキリするのですが、
片方は付け、片方は付けない、のは、どう解釈すれば良いでしょうか。

「変数を指す場合は、付けない決まりなんだよ」と言われれば、その通りなのですが..
なにか特別な事情があったりするのでしょうか。よろしくお願いいたします。

c

1# include <stdio.h> 2 3int main(void) 4{ 5 int a; 6 int *p; 7 p=&a; 8 *p=5; 9 return 0; 10}

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

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

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

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

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

rubato6809

2020/03/17 08:13

タイトルを修正してください。 「ポインタ関数に際して…」は「ポインタ変数に際して…」が正しいようです。
guest

回答6

0

aのような変数と、ポインタ変数を区別するため、アスタリスクを付けて*pとするのは理解できます。

そういう考え方ではないです。

*pは、「ポインタ変数pの値であるアドレスの指し示す先の変数」を意味します。

2つの宣言は、
int a;aint型変数を宣言
int *p; ⇒ 「ポインタ変数pの値であるアドレスの指し示す先の変数」がint型変数であるような変数pを宣言
という意味です。

p=&a;は、変数pに「変数aのアドレス」を代入しています。

*p=5;は、「ポインタ変数pの値であるアドレスの指し示す先の変数」に、5を代入しています。
変数pには「変数aのアドレス」が入っていますので、
これは、「変数aのアドレスの指し示す先の変数」となり、結局「変数a」のことです。

「ポインター変数には*を付けるのか付けないのか?」という考えを捨てましょう。
「アドレスの指し示す先」を扱いたいのであれば付けます。「アドレス自体」を扱いたいときは付けません。

よく考えるか、頭の中で考えてわからない場合は、「ポインターとは何か」を復習した上で絵を描いてみましょう。

投稿2020/03/17 07:26

otn

総合スコア84423

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

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

maisumakun

2020/03/17 07:38

宣言は別に扱ったほうがわかりやすいかもしれないですね。
otn

2020/03/17 07:42

それは、相手のレベルによりますね。同じ意味だと説明して、理解できない場合にでしょうか。
rubato6809

2020/03/17 08:50

変数宣言(変数定義?)と、処理では、文法が違うのですから、最初から「別に扱った」ほうが良いと思います。 変数宣言の「*」は、その変数がポインタだということを示します。 一方、処理の際につける「*」は、ポインタ変数が指すメモリをアクセスすることを意味します。 この区別が曖昧なままでいると、こういう問いがなくならないと思います。
otn

2020/03/17 09:46 編集

文法というか、*の扱いについては同じですよ。
rubato6809

2020/03/23 02:59 編集

いや、同じと解釈するのは危険です。こんな記事が見つかりました。 http://white-bear.info/archives/583 <ここ(変数定義)での * は「この変数はポインタ変数ですよー。アドレスが格納される特殊な変数なんですよー」とお知らせする単なる記号> *p = 5; はポインタが指すメモリに5を代入しますが、 int *p = &a; で &a というアドレスが代入される先は、p が指し示す先ではなく、p そのものです。 変数定義(宣言?)と処理で文法が異なる、もうひとつ明確な例は int n[5]; この [5] は要素数を示すもので、添字ではありません。
otn

2020/03/23 03:27

実行文と宣言文で、構文が異なるのは当たり前です。 変数宣言で =で書くのは変数の初期化なので、あくまで初期化されるのは変数です。 (=は代入演算子の=ではなく、初期化宣言子を構成する構文の記号です) 言い換えると、int *p = &a; は int *p; p = &a; と同じであることを理解すれば良いかと思います。 > *の扱いについては同じですよ。 というのは、「int *p; の*の意味と、*p = 10; の*の意味は同じ」という意味です。
kazuma-s

2020/03/23 06:18

「int i;」という宣言について見てみましょう。 まず、宣言は C++ では文にもなりますが、C では文になりません。 if (1) int i; // C ではエラー 宣言 int i; において、int は宣言指定子、i は宣言子です。 宣言指定子は、一般には次のものを順不同で並べたものです。 ・記憶域クラス指定子(extern や static など) ・型修飾子(const や volatile など) ・型指定子(int、char、doulbe、long、unsigned など) static const unsigned long long int は long int long unsigend const static と書いても同じです。 宣言子には宣言される識別子が含まれています。 「int i, a[3], *p;」なら、i、a[3]、*p がそれぞれ宣言子で、 a[3] は配列宣言子、*p はポインタ宣言子です。 i の型は int。a の型は int[3]。p の型は int*。 int、int[3]、int* は型名です。 ここでの * や [] は宣言の構文要素であって、演算子ではありません。 宣言は、「宣言指定子 宣言子; 」であって「型名 識別子 :」ではありません。 int* p; と書いてもかまいませんが、int[3] a; とは書けません。 以上は私の記憶に頼って書いていて、最新の C の規格では変更されているかもしれません。
otn

2020/03/23 06:40

今までのコメントとの関連がわかりませんが、これはこれで良いのではないでしょうか。 私は、回答欄で、 > int *p; ⇒ 「ポインタ変数pの値であるアドレスの指し示す先の変数」がint型変数であるような変数pを宣言 という意味です。 > *p=5;は、「ポインタ変数pの値であるアドレスの指し示す先の変数」に、5を代入しています。 と、宣言文、実行文どちらも、*p を同じ文章「ポインタ変数pの値であるアドレスの指し示す先の変数」で説明していますが、これをどう変えるべきというご意見でしょうか?
rubato6809

2020/03/23 08:10

kazuma-sさん ご指摘ありがとうございます。私の認識を修正するには時間がかかりそうですが、手がかりが得られたと思います。 otnさん 最初から回答の内容に異論があったのではないです。 宣言と実行文の違いを意識したほうが良い(良さそうだ)、と思ってますので、コメントの中で、特に「*の扱いについては(宣言も実行文も)同じ」と書かれたことがひっかかったのです。同じと言われれば誤解する人が出るだろう(そういう人を見てきた)、ちょうど私の思いと重なる意見があったのでコメントしました。 お騒がせいたしました。
otn

2020/03/23 09:09

そもそも、宣言文と実行文では構文もコンテキストも異なるという前提無しの人に言うと混乱しそうだというのは、了解です。 > int *p = &a; で &a というアドレスが代入される先は、p が指し示す先ではなく、p そのものです。 (中身がまだ入っていない)pの指す先(どこ?)に代入されると思った人がいたと言うことですよね。。。 久々に使ってみますが→ orz
rubato6809

2020/03/23 09:41

> 中身がまだ入っていない)pの指す先(どこ?)に代入されると思った人がいた 整理してみればそういう誤解ですが、果たしてそう考えたかどうかもよくわからない事が多いです。リンク先の人は「どう質問すれば良いのかがわからず」ハマったと書いてるのは結構正直だと思いました。誤解あるいは混乱はそればかりではなく十人十色でしょう。書き方を学んだ当初はわかったつもりでも、自分で書こうとすると混乱する人もいます。この質問者は *p と p があると気づいてますが、常に *p と書くのがポインタ変数だ…というような(ここも曖昧ですが)誤解もあると見ています。
guest

0

次のようなコードがあったとします。

C

1#include <stdio.h> 2 3int main(void) 4{ 5 char s[4] = "abc"; 6 printf("%s\n", s); 7 printf("%c\n", s[1]); 8}

質問
s を char変数と区別して配列変数とするために [] を付けて s[4] とするのは理解できます。
一方、printf の行で、[] を付けない s と、[] を付けた s[1] を使用しています。
この場合、両方とも [] 付けた s[1]、あるいは両方とも付けない方がスッキリするのですが、
片方は付け、片方は付けない、のは、どう解釈すれば良いでしょうか。

回答
使用目的が異なります。
・[] を付けない s は "abc" 全体の値を使用するため。
・[] を付けた s[2] は "abc" の中の 'b' の値を使用するため。

元の質問に対する回答
使用目的が異なります。
・* を付けない p = &a は、p 自身に a のアドレスを設定します。
・* を付けた *p = 5 は、pの指しているものである a に 5 を設定します。

投稿2020/03/19 01:32

編集2020/03/19 03:16
kazuma-s

総合スコア8224

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

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

0

感覚的になってはしまいますが、理解のきっかけにでも使っていただければという「お話」として
int * p;
という宣言を区切った時、区切った左と右の型が同じもの、というのはいかがでしょう。

int *p pは、int *(intへのポインタ)型、です。なので、pはintへのポインタ(アドレス)を扱います。p=の右辺にはポインタ(アドレス)を置いて下さい。

int* p *pは(これを一体と見て) int型です。なので、*pは数値を扱えます。*p=の右辺には数値を置いて下さい。

(カッコがついたり複雑になると通用しない場合もあるでしょうが、この「感じ」を掴んでおけば理解の助けにはなるのでは)

投稿2020/03/17 21:56

thkana

総合スコア7610

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

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

0

y_waiwaiさんのお答えが舌足らずだと思ったので。

p=&a;というふうに、アスタリスクを付けないpとし

操作対象がポインタ変数ならアスタリスクは不要です。p = &a; は(a のアドレスを)ポインタ変数pへ代入します。代入した結果、どこの値が変化するかと言えば、ポインタ変数 p それ自身です。この時、アスタリスクは不要です。

p=5;として、再びアスタリスクを付けたp としています

操作対象がポインタ変数が指すメモリならアスタリスクが必要です。*p=5;で値が変化するのは、ポインタ変数 p ではありません、ポインタ変数 p が指す先の a という変数(a というメモリ)です。いわゆる、ポインタ変数を使った間接参照などと呼びます。このためにポインタ変数があります。
この時、アスタリスクが必要です。

片方は付け、片方は付けない、のは、どう解釈すれば良いでしょうか

  • 操作対象がそのポインタ変数ならアスタリスクは不要
  • 操作対象がそのポインタ変数が指すメモリならアスタリスクが必要

操作とは次の3つを念頭に置いています。

  • 値を読みだす
  • 値を書き込む(代入)
  • 演算を施す(例:a++ なら変数 a の値を1増やす)

さて、ここで私も質問者に訊いてみましょう。
int *p; p = &a; をひとつにまとめると
int *p = &a; と書けることをご存知ですか?
ここにアスタリスクを書く(アスタリスクがある)のは何故ですか?

追加の問い。int *p; と定義されたポインタ変数 p がある時、

  • x = *p;
  • y = p;

はどちらもありうるコードですが、 x, y の変数定義が無いとコンパイルエラーになります。x, y の変数定義を補ってみてください。それぞれ、どんな動作をしますか?

投稿2020/03/17 12:31

編集2020/03/17 21:29
rubato6809

総合スコア1380

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

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

Heizo

2020/03/18 03:58

1番めの問い int *p; p = &a; の場合、 int *pにて宣言をし、p=&a;にて値(aのアドレス)がポインタ変数に代入される。 int *p = &a;の場合、 ポインタ変数が(aのアドレスで)初期化される、 こんな感じでしょうか。 2番めの問い、については、「 C言語10課 ポインタ編」を読みだした程度の理解度のゆえ、質問の意味が分かりませんでした〜。
rubato6809

2020/03/18 11:59

1番目の答えは文句なしです。 2便目の答えは、どなたか答えてくれる先輩が出てくることを期待しましょう。 3番目は、2番目ほど難しくないので、じきに答えが見つかると思います。
guest

0

宣言のところは,スペースの位置を変えてみれば,型が違うということが若干わかりやすくなる感.

int a; //【int】型 int* p; //【int*】型 int** q; //【int**】型

(正式な言葉(?)として「int*型」とかいう記述がOKかどうかは知りませんけども…)

投稿2020/03/17 07:47

fana

総合スコア11634

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

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

Y.H.

2020/03/17 08:54

解りやすくはなりますが、 int* p, ptr2; // 【int*】型 とかやってしまいがちなので、この記法は推奨しないですね。
fana

2020/03/17 09:26

この話を「記法」と考えるならば,そこらへんは int* p, * q; //宣言時には変数名と*の間にはスペースを開けろというのがルール? とかになってしまいそうで,見栄え悪いですね.
rubato6809

2020/03/17 12:37

> 「int*型」とかいう記述がOKかどうか 理解の便法としてならこの書き方はアリですが、コンパイラには「int* 型」が無いことは Y.H.さんの指摘の通りです。 空白を入れない int*p; も 空白を入れまくる int * p ; も、コンパイラには違いがありません。
fana

2020/03/18 03:44

> 「int*型」とかいう記述がOKかどうか というのは,ソースコード上での記述のことではなくて, 単に,型名の表記として「int*」って書くと正式ではないかも? みたいな話です. (コンパイラのエラーメッセージとかだと「int *」としてスペースが入りますので,そっちが正当かな?とか.)
rubato6809

2020/03/18 11:53

int* p, ptr2; のようなことをしなければ済む話かもしれません。 白状すると私も普段「このポインタはint*型なんだから〜」みたいなことをよく言います。 アドレスと型があってのポインタです。"int*型"という呼び方は相応しいと思います。
fana

2020/03/19 01:22

> int* p, ptr2; のようなことをしなければ済む あえて(?)そう書く人には,そもそもこんな話が不要でしょうし.
rubato6809

2020/03/23 02:21

今頃になって大事なことを思い出した。 キャストは「(型名)」であり、「(int*) ptr」という書き方をするのだから、「int *」は型名でよさそうだ。
guest

0

ベストアンサー

提示の例では、
つけないのはアドレスを示し、つけるのは、アドレス先の内容を示します

投稿2020/03/17 07:09

y_waiwai

総合スコア87719

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

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

Heizo

2020/03/17 07:13

たぶん、理解できたと思います。ありがとうございますー
kazuma-s

2020/03/17 07:33

Heizoさん、本当に理解できていますか? では次の質問に答えてください。 int変数 a に際して、& を付けたり付けなかったりするのはどのように解釈しますか?
Heizo

2020/03/17 08:18

&aで表されるアドレスがポインタに代入されたんだと思いますが..違いましたかー
Zuishin

2020/03/18 02:44

> int *p; 内容って何ですか? 宣言時の値は不定です。
Zuishin

2020/03/18 03:25

質問者さんは理解できたかどうか聞かれた意味がわかっていますか? この回答は初心者でなくとも首をかしげるような回答で、なぜそれを初心者が理解できるのか不明なので、どういう理解をしたのかを聞かれているんです。
kazuma-s

2020/03/23 06:18 編集

間違ってこちらにコメントしてしまいました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問