色彩を教える人になるための講座「色彩講師養成講座」の魅力とは>>

char* p
char p
&pの違は
char *pはポインタでアドレスを指定したり扱う。(その後はpと置くだけでアドレスを扱える。)
char pはただのpという文字や文字列を扱う変数
&pはchar *pで扱われたアドレスをprintfなどで表示するさいに使わられる。
であるため、


また、char* p = strchr(str, '\0');で、なぜ以下のプログラムでchar *pかというと関数strchr(str, '\0');の返り値のアドレスを得るためですね

#include <stdio.h>#include <string.h>int main(void)
{
char str[] = "12345""\0""67890"
;
char* p = strchr(str, '\0');//★strchr関数によりchar* pはポインタpとして扱われ、上と同じような処理になる
//しかしstrchr関数によりchar* pでありながらポインタのアドレス、ではなくアドレスの指す数値を扱うというのに違和感があります。
//これはstrchr関数がそういうものだからと納得するしかないのでしょうか?
printf("|%s|\n", str);
printf("|%s|\n", p + 1);

*p = '!';
printf("|%s|\n", str);
}

合っているでしょうか?

質問者からの補足コメント

  • char *p = strchr(str,'¥0')
    (やchar *pなど)と
    変数宣言をした後、pはポインタ変数であり、このように変数宣言したため、*pはポインタが指定したアドレスの値を操作でき、
    pは上の変数宣言によりポインタと扱えるためアドレスを扱える。そして、余談ですが&pはポインタ自体のアドレスを表している。
    まぁ、たしかにchar pはただのポインタに全く関係ないpのchar型の変数宣言で、変数pに1バイトの1文字が入る?だけですよってだけですからね。今までpとすればなんでもポインタのアドレスだと思っていましたが誤解が解決しました。本当にありがとうございます。

      補足日時:2021/02/19 15:05
  • ちなみに、仮に一文字ではなく、文字列を表したい場合は先程のポインタで先頭アドレスを得てprintfと%sで表示するなり、配列char str[ ]のどちらかで表せばよいのですからね。
    とりあえず正しいでしょうか?
    結構考えてやっと出来たことなので、あまりきついことを言わずにとりあえず正しいといいなと、思います。

      補足日時:2021/02/19 15:05
gooドクター

A 回答 (5件)

うーん、やっぱ「コンパイラが云々」以降は要らないかなぁ。

    • good
    • 1

> どうでしょうか?



ん〜。まぁ及第点かしらん。
細かいとこ言えば、

> ポインタのアドレスの指す1つの値や1文字を扱う変数として扱える

「ポインタのアドレスの指す」じゃなくって「ポインタが指すアドレス」かな。
そもそも、ポインタ、ってのは別にウルトラ警備隊の専用車の事じゃない。文字通り「pointer」、つまり「指し示す者」です。ポインタが指してる、のです。うん、ヘンな日本語だな。
そしてこの場合のアドレスは特定のメモリ番地を意味する。
まぁ、その辺は既に理解してる、って思いたいですが。

> コンパイラ的にpを選んだのだろう。

ここはちょっと意味分からんかな。
    • good
    • 0
この回答へのお礼

★ポインタpについて。

char* p = strchr(str, '\0');においては、変数宣言も兼ねているため、また、char pだとただの1バイトの文字を表す変数pとなりポインタとは全く関係ないものとなる。
なので、ポインタが指すアドレスを扱うための変数とするために型とアスタリスクようはchar *が必要だったのだ。
char *pとすることではじめてpがポインタのアドレスを操作する変数として扱え、他には*pはポインタが指すアドレスの中身の1つの値や1文字を扱う変数として扱えるのだ。
今回は、char* p = strchr(str, '\0');はポインタを使うための変数宣言char* p と*pが被ったためポインタのアドレスの指す値を扱えるものと混乱したのだろう。
ただ、それは間違いで、
char* p と宣言することで、それによりpが扱えた。仮に*pだとしても1つの値や1文字しか扱えないため、コンパイラ的にpを選んだのだろう。
というのも、仮に*pだとしたら1つの値や1文字しか扱えないためchar* p = strchr(str, '\0');のchar*pの変数が*pならばコンパイルエラーになる。
そのため、コンパイラの方である人曰く、
char* p = strchr(str, '\0');は
char* p ;
p = strchr(str, '\0');とも書けるため、
コンパイラがchar* p = strchr(str, '\0');を上のように分解したのかも知れない。strchr(str, '\0');からの返り値のアドレスを受け取れるのはポインタpであるために。

お礼日時:2021/02/19 16:54

> ちなみに、仮に一文字ではなく、文字列を表したい場合は先程のポインタで先頭アドレスを得てprintfと%sで表示するなり、配列char str[ ]のどちらかで表せばよいのですからね。



☓ 文字列を表したい => 文字列として表示したい

どっちがいいか、と言うのはお好きなように。
実態はどっちも変わんないんで。

あんまこういう書き方したくない(アブナイから)んだけど、例えばscanfを勉強した?時に。

int a;
scanf("%d", &a);

と「intの変数aにキーボードから入力した数値を代入したい」場合、scanfの第二引数には変数aをアドレス演算してから入れなアカン、って習ったでしょ?
でも

int x[2];
scanf("%2d", x);

と、配列xにキーボードから数値を代入する場合、配列xにはアドレス演算は必要なかった。何故なら配列名を与える場合、常に先頭アドレスが与えられる事を意味してたから、です。
それで考えると

char* str = "Hello!";

だろうと

char str[] = "Hello!";

だろうと結果変わんないんですよ。
「自分で分かりやすい方を」選べば良いだけ、です。

んで、結局Cがポインタだ、配列だ、で抽象化してるように見せかけてるモノが何を操作してるか、と言うと、極論何も操作してない。
あるのは単に、ハードウェアとしてゴロっとそこに転がってるむき出しのメモリなんですよ。メモリを「配列」だとか「ポインタ」で包んでるように見せかけてますが、物理的にそこにある「メモリ」は結局動かせないのです。
他の言語だともっと上手く抽象化してたりしますが、Cのように、メモリがそこにゴロっとあるだけ、が実体だとすれば、strtokなんかも「文字列をトークンに分割してるわけじゃない」。
何故なら物理的にメモリは分割出来ませんからね。そんな事したらパソコンが壊れちゃいます。
だから0をぶち込んで「トークンに分けたように」見せかける。実際は他の情報はそこにそのまま残ってるんですよ。
そして「動かせない以上」代入も不可能です。しょーがねぇんで、何かヒント(結局だから先頭、を何とかマーキングしてその情報だけを頼る)を利用して「メモリのどっかにこれこれこれ、って連続した記録があるらしい」って言うしかない。ケツも良く分からん。動かせないわ、ケツは分からんわ、基本的にはプログラマがその辺数えろ、とか言うかなり投げやりな事をやるしかないのです。
そう言うかなり低レベル・・・って言って悪けりゃ抽象化が不十分な言語を相手にしているわけです。
    • good
    • 0
この回答へのお礼

ありがとうございます。
一応自分なりにまとめました。
どうでしょうか?
★ポインタpについて。

char* p = strchr(str, '\0');においては、変数宣言も兼ねているため、また、char pだとただの1バイトの文字を表す変数pとなりポインタとは全く関係ないものとなる。
なので、ポインタのアドレスを扱うための変数とするために型とアスタリスクようはchar *が必要だったのだ。
char *pとすることではじめてpがポインタのアドレスを操作する変数として扱え、他には*pはポインタのアドレスの指す1つの値や1文字を扱う変数として扱えるのだ。
今回は、char* p = strchr(str, '\0');はポインタを使うための変数宣言char* p と*pが被ったためポインタのアドレスの指す値を扱えるものと混乱したのだろう。
ただ、それは間違いで、
char* p と宣言することで、それによりpが扱えた。仮に*pだとしても1つの値や1文字しか扱えないため、コンパイラ的にpを選んだのだろう。

お礼日時:2021/02/19 16:11

> 今更ですがポインタpであるアドレスの先頭を確保する場合の書き方



何度も言いますが、単にcharのポインタpを宣言する場合、

char *p;

と書くだけ、です。目的はアドレスを代入する為。
「アドレスの先頭」(って何の?)を入れたいか入れたくないか、は貴方が決める事です。
「書き方」は当然その辺は全然支配/コントロールしていません。

例えば、

int n = 3;

と書いた時、

> 変数nは3を確保する場合の書き方ですか?

とか訊かれたら

「違うでしょ」

ってなるでしょ?
それと同じです。3を代入するかしないか、は貴方が決める事であって、「書き方」がそれを決めてるわけじゃあない、ってのと同じです。

> そう定義したあとに*pはポインタpが示すアドレスに入っている数値を表しているのでしょうか?

まぁ、まだるっこしい書き方ですが、その通りです。

うーん、どうしようか。
あんま専門用語使わずに平易に説明する、って考えてたんだけど。
しょうがねぇ。

実はポインタ宣言時点で使われる「*」とプログラム本体内でポインタに付けて使われる「*」は全く違う機能です。
と言うのも、実はこれらは名前が違う。名前が違うから機能が違う。名前も機能も違うのに使う記号が全く同じだと言う。
ふざけんな、ナメとんのか、ってのがCの文法が狂ってるトコです。
変数宣言部(ってのは今のC規格じゃホントは無いんですが)の

char* p = strchr(str, '\0');

で使われてる「*」を仕様上、「ポインタ宣言子」と言います。読んで字の如く、「ポインタを宣言する為の記号」ですね。
一方、プログラム本体内の

*p = '!';

の「*」を「間接参照演算子」と言います。読んで字の如く「間接的に参照して演算する記号」ですね。なんのこっちゃ。
要するにこの2つは「同じ記号を使ってる」のに、機能が全く違う。別物なのに同じ記号。だから混乱するんです。

char* p = strchr(str, '\0'); /* 宣言部での「*」はポインタ宣言子 */
*p = '!';         /* ポインタ使用時の「*」は間接参照演算子 */

つまり、

> そう定義したあとに*pはポインタpが示すアドレスに入っている数値を表しているのでしょうか?

ってのは

> ポインタpを間接参照演算した結果を表している

って事です。意味は貴方が言ってる通り、「ポインタpが持ってるアドレスが示すメモリの中身を取り出した」結果を表している。

間接参照演算、です。

練る前に10回くらい唱えてください。そしてこれはポインタの宣言時に使われてる「*」の機能とは全く関係ない、って事を(しょーがねぇんで)覚えてください。

こういうクソメンドくせぇ文法だからCが大っ嫌いなんだよ(笑)。
    • good
    • 0
この回答へのお礼

要はポインタpを使いたいときはchar *pやint *pと書く必要があるわけですね!補足にも書かせて頂きましたが。

お礼日時:2021/02/19 15:37

✗char pはただのpという文字や文字列を扱う変数



だからCには文字列、なんざ無いです。これも何度も言ってるけど。
char pは文字を扱うだけ、です。

そんなに文字列好きなら多分Javaやった方がエエんちゃうん?ってくらい文字列なんざ無いです。

✗&pはchar *pで扱われたアドレス

&pは「ポインタp自体のアドレス」になります。ポインタpに代入されたアドレスじゃないです。
これも自分で次のようなコードを書いて確かめてみれば良い。

#include <stdio.h>
#include <string.h>

int main(void) {
 char str[] = "12345""\0""67890";
 char *p = strchr(str, '\0');
 printf("%p\n", p);
 printf("%p\n", &p);
 return 0;
}

これも環境やコンパイラによって変わるけど、例えば

0x7fffffacb981
0x7fffffacb970

となって、値が違います。前者が「ポインタpに代入されたアドレス」、後者が「ポインタp自体のアドレス」。
全然違うでしょ?

あとは、多分そのままコピペしただけ、だろうから、間違いは既に指摘済み、です。
    • good
    • 3
この回答へのお礼

ありがとうございます。
今更ですがポインタpであるアドレスの先頭を確保する場合の書き方は
char *pですか?
そして、そう定義したあとに*pはポインタpが示すアドレスに入っている数値を表しているのでしょうか?

お礼日時:2021/02/19 14:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

gooドクター

このQ&Aを見た人がよく見るQ&A

このカテゴリの人気Q&Aランキング