
#include <stdio.h>
#include <string.h>int main(void)
{
char str[] = "12345""\0""67890";
char* p = strchr(str, '\0');
printf("|%s|\n", str);
printf("|%s|\n", p + 1);
*p = '!';
printf("|%s|\n", str);
}
上のプログラムの
char* p = strchr(str, '\0');
のpに*がついていますが、これはpに掛かっているのではないですよね?
個人的にヌルになる手前から最初の文字列の先頭のアドレスが渡せれば良いと考えたので char p = strchr(str, '\0');で良いとしましたがエラーが起きます。
なぜ今回char*が必要なのでしょうか?
strchrのせいでしょうか?なぜstrchrを使うだけ*pになるのか知りたいです。
No.5ベストアンサー
- 回答日時:
あー、ちなみに、だ。
例えば
char* p, q;
って宣言したとする。
pはポインタになるんだけど、じゃあqはどうか、と言うと実はこれはポインタにならない。単なるchar型の変数になる。
フツーに考えればqもポインタになりそうなモンなんだけど、それが「ならない」ってのがCのポインタ周りの文法の腐ってるトコ。
こういう「直感に反した」事柄がやたら起こるのがCって言語で、結局、実際問題、Cを最初に設計した時に実は「真面目に設計しなかった」と言う事です。
元々「他人に使ってもらおう」とか「普遍性があるように設計しよう」と言う意図では作られてなく、要するに「一時凌ぎで作ってみて」、あとで色々とアドホックに追加が行われた、ってのがC言語の正体です。
ちなみに、文字列の最後は'\0'で〆る、ってのも実装で考えると殆ど最悪の決定なんだけど、これも元々は、オリジナルのC言語が実装されたPDP-7と言うミニコンが扱う文字列がそういう仕様だったからそうなった、ってだけ、です。実は特に意味がない。
と言うか「プログラミング言語の設計に関する深淵なる考慮」でそうなったわけでも何でもない。ぶっちゃけ、やっつけ仕事です。
要するに「別のミニコンで動かす」とか、今みたいにパソコンで使用する、って前提は全く考えてなかった。ですが、PDP-7で扱うには丁度良かった、ってだけですね。
世の中には別の文字列の実装法があり、例えば有名なのが、通称「Pascal文字列」と呼ばれる実装法です。これはかつてCのライバルだったプログラミング言語、Pascalで採用されてる文字列実装法です。
Cで言うと、例えば
char str[] = {'\013', 'H', 'e', 'l', 'l', 'o', ',' ,' ', 'W', 'o', 'r', 'l', 'd', '!'};
みたいな実装方法で、配列の最初に「文字の長さ」を明示させて入れる方式。そうすると終端に'\0'みたいな文字は必要ないし、長さを知る為にシーキングする必要もない。配列の最初の数値をチェックすれば自ずと文字列の長さが分かるわけです。
まぁ、この方法も実は欠点があって、それは原理的には文字列の長さは最大で255しか許容出来ない、と言うモノ(まぁ、バイト設定に依りますが)。
ルーピングでシークして時間がかかっても、原理的にはどんな長さの文字列も(メモリが許す限り)使えるようにするべきか、あるいは長さを制限しても速さを優先すべきか、ってのはなかなか難しいトコですがね。
余談ですが、Microsoft Excelの文字列はこの方法(Pascal文字列)で実装されている、と言う話です。
No.4
- 回答日時:
> これはpに掛かっているのではないですよね?
pにかかってんの。
char* p
も
char *p
も同じよ?
だから言ったでしょ。「Cのポインタ周りの文法は腐ってる」って。
あと、仕様書読みました?読んで質問してる?
> なぜ今回char*が必要なのでしょうか?
平たく言うとstrchrの返り値がアドレスだから、です。
これもstrchrの定義見てみれば一発でしょう。
strchr():
https://www.k-cube.co.jp/wakaba/server/func/strc …
自分で少しは調べんかなぁ。
> 文字列からヌルを探すために一アドレスずつ進み、ヌルを見つけたらヌル手前から文字列のはじめまでの文字列の先頭の文字を*pに送るのですか?
全然違う。
> ヌルを見つけたらヌル手前から文字列のはじめまでの文字列の先頭の文字を*pに送る
って何が言いたいんだろ。
ポインタpに代入出来るのは「一つのアドレス」のみ。それ以上でもそれ以下でもない。
> char* p = strchr(str, '\0');
で分かるのはpに入ってるのはstrの「\0の位置情報」だけ。
それ以上何も無いですよ。
もう何度言っても理解してないみたいだけど、もう一回書いておきます。
1. C言語には文字列なんぞ無い。
2. 従って、C言語には文字列を纏めて扱うような機能もない。
以上です。
余談:
気の利いたCの入門書だと「文字列」なんて記述は一切せず、「文字配列」と言う言い回しをしてる。
事実上、Cにあるのはそのまま「文字」の「配列」だからだ。
printf("%s", str)が「文字列を扱えるように見える」のは、実際は内部で一文字一文字ルーピングしながら表示してるから。終了条件がstr[i] == 0で動作を止めるからに他ならない。
No.3
- 回答日時:
>個人的にヌルになる手前から最初の文字列の先頭のアドレスが渡せれば良いと考えたので char p = strchr(str, '\0');で良いとしましたがエラーが起きます。
C言語では変数は必ず宣言する必要があります。
宣言することでその変数の型と必要なメモリ領域が確保されます。
今回の場合、文字型変数のポインタを代入する必要がありますので
char* p;
と宣言しなければなりません。このように宣言することでpは文字型変数へのポインタとして決められ、そのデータを格納するために必要なメモリ領域が割り当てられます。
そうしてから
p=strchr(str, '\0');
とアドレスを入力することで初期化します。
で、今回の場合、宣言と初期化を同時にやろうとしています。
この場合はポインタであると宣言するため左辺は
char* p
でなければなりません。*がついていないとpがポインタ型にならないのです。
で、同時に初期化するには、=アドレス、と入力することになります。
一見宣言のためのcharを除くと
*p=アドレス;
となり、おかしく見えますが、これは宣言と初期化を同時にやっているために仕方なく許された書き方なのです。例外的なものなので納得するしかありません。

No.1
- 回答日時:
Cの関数を解説してるサイトなどで仕様をよく読むようにしてください
char *strchr(const char *s, int c);
となってますのでポインターへ返すことが決まりとなってます
strchr
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/ …
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringからchar*への型変換に...
-
isalpha()関数について
-
文字列strの中から文字cを探す...
-
C言語でポインターで詰まってい...
-
警告
-
VBからCで作成されたDLL...
-
char*を初期化したいのですが
-
構造体のメンバーの静的なサイ...
-
メモリを0クリアする方法について
-
new charとnew char[N]の違いは?
-
構造体・ビットフィールドのvol...
-
動的メモリの初期化方法について。
-
Excelですべての組合せ(重複組...
-
C言語において、 配列要素をひ...
-
C言語 配列の長さの上限
-
配列を使わずに、変数名を動的...
-
C言語の配列のサイズ
-
Integer変数をカラにしたいので...
-
Run-Time Check Failure #3とい...
-
リッチテキストボックスの中身...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
C言語にて構造体のメンバがNULL...
-
fstream型オブジェクトを関数の...
-
char型にint型の数値を代入する。
-
char 文字列型 の表現範囲が-12...
-
文字列を比較するプログラムな...
-
ostringstreamではまりました
-
文字列内の数字削除
-
C言語のプログラムについてです
-
csvファイルをfscanfで読み込む...
-
エクセルのMID関数は、C言語では?
-
ポインタを使って回文かどうか...
-
C言語でポインターで詰まってい...
-
文字列の途中から途中までを抽出
-
new charとnew char[N]の違いは?
-
文字列str内の全ての数字を...
-
以下のようなプログラムを書い...
-
char AA[]{"全角文字"};から"全...
おすすめ情報
ちなみに、char* p = strchr(str, '\0');とは
文字列からヌルを探すために一アドレスずつ進み、ヌルを見つけたらヌル手前から文字列のはじめまでの文字列の先頭の文字を*pに送るのですか?
文字列の先頭のアドレスを渡すならわかるのですが、それとも例外で*をつけても文字列の先頭のアドレスを受け取れるように出来ているのでしょうか?