一回も披露したことのない豆知識

#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);
}
をcやc++でデバックしたら、char* p = strchr(str, '\0');の部分がcharと*pになると思ったらchar*とpに分かれていました。
理由がわかりません。
どなたかわかる方はいますでしょうか?
また、char*型とはポインタ型のcharだとわかりました。しかし、だからなんだという感じで、ポインタ型のcharとはなんなのですが?

どうか基礎を固めたいのでどうかよろしくお願い致します。

A 回答 (3件)

str*p


とか
str p
とかって, なんなのさ.

「ポインタ型のchar」も全く意味不明だ. どこにそんなことが書いてあるんだろう.

ちなみに C の文脈で
1byteですよ。数値にすると(符号無しとしたら)0〜255までしか入らん。
と決めつけるのはよくない>#2. char は 1個 1バイトだけどさ.
    • good
    • 0

> str*pにかんしては単純に関数から出る返り値がアドレスであるためなのかなと思っていましたが、だったらchar pでいいじゃんと考えコンパイルすると関数strchrが受け付けないとかでエラーが出ました。



そりゃそうでしょ。
char pで宣言したら変数pは「文字を受け付ける」と言う前提。
前にも書いたけど、静的型付け言語の場合は、左辺と右辺の型が一致してないといけない。
しかも、

> char型 -> 1byte

って書いたでしょ?char型が要求するバイト数っていくら?
1byteですよ。数値にすると(符号無しとしたら)0〜255までしか入らん。16進数だとffです。
ってこたぁ、例えばさっき挙げた例、

0x7ffd753b91f

だと10進数だと何だ、8795410643231か?こんなん入るわけがない。
幼女を強姦するようなモンです。

「らめぇ、大きすぎて無理ぃ」

と言うエロ漫画でお馴染みの展開になる。
そりゃ無理でしょ、と。
    • good
    • 1
この回答へのお礼

単純にアドレスを得るためにchar *pとしたんですね。

お礼日時:2021/02/19 03:51

> しかしstrchr関数によりchar* pでありながらポインタのアドレス、ではなくアドレスの指す数値を扱うというのに違和感があります。



アドレスの指す数値、って何だろ。アドレスが数値ですよ。メモリの番号。
もう一回言うけど、strchr関数が返すのはアドレスなんです。アドレスをポインタpに代入している。
気になるなら、

printf("%p\n", p);

でも

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

の後に差し込んで印字してみればいい。
そっちのマシンやコンパイラとは違う数値が印字されるだろうけど、例えばコッチでは

0x7ffd753b91f

と言うのが出てきます。これが「アドレス」。メモリの0x7ffd753b91f番目、って事だな。
だからポインタpにはstrchrから渡ってきたアドレスが入っている。
そして

0x7ffd753b91f

と言う番地には0が格納されてる、ってのがstrchrの機能からの性質です。
何も難しい事はない。

> char* p = strchr(str, '\0');の部分がcharと*pになると思ったらchar*とpに分かれていました。

もう何言ってんだかサッパリ分からんけど、以前書いたの理解してないのかしら。
char *p も char* pも宣言上同じ意味です。256回くらい言いましたが「Cのポインタ周りの文法は腐ってる」。
単に貴方が使ってる環境のデバッガの作者がchar* pって書く方が好きだ、ってだけでしょ。
何にも難しい話じゃない。

> char*型とはポインタ型のcharだとわかりました。しかし、だからなんだという感じで、ポインタ型のcharとはなんなのですが?

うん。だから何だ、ってのは正しい。
アドレスが整数な以上、別に何だって話になるわな、そりゃ。
その感想は正しい。

要するにCにはポインタ演算って言う狂った機能があります。
ポインタpを

p++

として進めたり、p+1したり。
じゃあ、例えばp+1した時、ポインタのアドレスに1足してるのか?って問題がある。
実は違う。
int型もchar型も要求するメモリの容量ってのが違うわけですね。

int型 -> 4byte
char型 -> 1byte

そうすると、「ポインタを一個進めます」って言った場合、型によりその「一個」の量が違う、ってこった。intは4byte進めるけどcharは1byteしか進めない。これが仮に「全く同じ量だけ進める」のならメチャクチャになる。
あるいは、プログラマ側が一個一個手で計算してメモリの塊を跨いでいく、なんつー事をやっても良いんだろうけど・・・考えてみただけでメンド臭い。アセンブリとか機械語出来る人は「そっちの方が明解だ」とか言うかもしれないですけどね(笑)。

だから試しに次のような簡単なコードを書いて確かめてみれば良い。

#include <stdio.h>

int main(void) {
 int int_array[] = {1, 2, 3, 4, 5, 6};
 char char_array[] = {'H', 'e', 'l', 'l', 'o', '\0'};
 int* p, i;
 char* q;
 p = int_array;
 q = char_array;
 for (i = 0; i < 6; i++) {
  printf("%p ", p);
  p += 1;
 }
 printf("\n");
 for (i = 0; i < 6; i++) {
  printf("%p ", q);
  q += 1;
 }
 printf("\n");
 return 0;
}

// ここまで

intの配列int_arrayとcharの配列char_arrayを用意する。
で、intのポインタpとcharのポインタqの両方を用意する。
pにはint_arrayを代入(正確に言うとint_arrayの先頭のアドレスが代入される)。
そしてqにはchar_arrayを以下同文。

さて、forループでそれぞれのポインタを+1しながらそのアドレスを印字する。
これも実際自分で書いて動かして確認して欲しいんだけど、こっちだとこうなる。

0x7fffa94b5060 0x7fffa94b5064 0x7fffa94b5068 0x7fffa94b506c 0x7fffa94b5070 0x7fffa94b5074
0x7fffa94b505a 0x7fffa94b505b 0x7fffa94b505c 0x7fffa94b505d 0x7fffa94b505e 0x7fffa94b505f

上半分ががpを+1した結果。下がqを+1した結果。上は4づつ増えてるけど下は1づつ増えてるのが分かる?まあ、16進数だから読みづらいんだけど。
このように、ポインタで「型情報」が必要なのは、単純に整数(アドレス値)を代入する、って場合はそれは要らない。けど、ポインタ演算で「1進める」とか「2進める」とかやった場合、「型によって進む"量"が違う」んで、型情報が必要なんですよ。
分かりましたか?
    • good
    • 1
この回答へのお礼

色々ありがとうございます。
str*pにかんしては単純に関数から出る返り値がアドレスであるためなのかなと思っていましたが、だったらchar pでいいじゃんと考えコンパイルすると関数strchrが受け付けないとかでエラーが出ました。
strchrはアドレスを返り値として相手にあげるだけなのにstr pじゃなんでダメなんだろうって感じです。

お礼日時:2021/02/19 02:50

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