これは実際にはC標準のstrchr()
関数の定義の欠陥だと思います。(間違っていることが証明されてうれしいです。)(コメントに答えて、それが本当に欠陥であるかどうかは議論の余地があります。私見ではまだデザインが貧弱です。安全に使用できますが、安全に使用するのは簡単すぎます。)
C規格の内容は次のとおりです。
char *strchr(const char *s, int c);
strchr関数は、 sが指す文字列内で最初に出現するc ( char
に変換)を検索します。終了ヌル文字は文字列の一部と見なされます。
つまり、このプログラムは次のようになります。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *s = "hello";
char *p = strchr(s, 'l');
*p = 'L';
return 0;
}
文字列リテラルへのポインタをへのポインタとして注意深く定義していますが、文字列リテラルを変更するため、未定義の動作があります。少なくともgccはこれについて警告せず、プログラムはセグメンテーション違反で終了します。const
char
問題はstrchr()
、引数を取ることです。つまり、-を指すconst char*
データを変更しないことを約束しますが、呼び出し元が同じデータを変更できるようにするプレーンを返します。s
char*
別の例を示します。未定義の動作はありませんが、キャストなしで修飾されたオブジェクトを静かに変更しconst
ます(さらに考えてみると、未定義の動作があると思います)。
#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *p = strchr(s, 'l');
*p = 'L';
printf("s = \"%s\"\n", s);
return 0;
}
つまり、(あなたの質問に答えるために)のC実装は、結果をに変換するか、同等のことを行うstrchr()
ために結果をキャストする必要があると思います。const char*
char*
これが、C ++がC標準ライブラリに加えるいくつかの変更の1つでstrchr()
、同じ名前の2つのオーバーロードされた関数に置き換えられる理由です。
const char * strchr ( const char * str, int character );
char * strchr ( char * str, int character );
もちろん、Cはこれを行うことはできません。
strchr
別の方法は、2つの関数に置き換えることでした。1つはaを取り、const char*
を返し、const char*
もう1つはaを取り、char*
を返しchar*
ます。strchr
C ++とは異なり、2つの関数は異なる名前(おそらくと)を持つ必要がありstrcchr
ます。
(歴史的には、すでに定義されたconst
後にCに追加されました。これは、おそらく既存のコードを壊さずに維持する唯一の方法でした。)strchr()
strchr()
strchr()
この問題を抱えているのは、C標準ライブラリ関数だけではありません。影響を受ける機能のリスト(このリストは完全だと思いますが、保証はしません)は次のとおりです。
void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strpbrk(const char *s1, const char *s2);
char *strrchr(const char *s, int c);
char *strstr(const char *s1, const char *s2);
(すべてで宣言されてい<string.h>
ます)および:
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
(で宣言されてい<stdlib.h>
ます)。これらの関数はすべてconst
、配列の最初の要素を指すデータへのポインターを受け取り、その配列の要素への非const
ポインターを返します。