12

だから、char const *、char * const、char const * const の違いを知っています。それらは:

char* the_string : the_string が指す文字を変更でき、それが指す文字を変更できます。

const char* the_string : the_string が指す文字は変更できますが、それが指す文字は変更できません。

char* const the_string : the_string が指す char は変更できませんが、それが指す char は変更できます。

const char* const the_string : the_string が指す文字を変更することも、それが指す文字を変更することもできません。

( const char * const 対 const char *?から)

さて、私の質問は次のとおりです。たとえば、渡された C 文字列を変更しない関数を書いているとしましょう。

int countA(??? string) {
    int count = 0;
    int i;
    for (i=0; i<strlen(string); i++) {
         if (string[i] == 'A') count++;
    }
    return count;
}

では、ヘッダーはどうすればよいでしょうか。

int countA(char const * string); 
int countA(char const * const string);

ポインター自体も配列の内容も変更しないため、2 番目のものを使用する必要があると思います。しかし、標準関数のヘッダーを見ると、最初の関数が使用されています。例

char * strcpy ( char * destination, const char * source );

なんで?

(実際char const *には、抽象文字列について考えている場合、文字列を変更していchar const * constないため (したがって、ポインターも内容も変更していないため)、私には意味がありません。文字列 (したがってchar *、内容を変更する可能性があり、より多くのメモリを割り当てる必要がある可能性があるため、ポインターを変更する必要がある場合があります)

誰かが私にこのすべてを明確にしてくれることを願っています。ありがとう。

4

5 に答える 5

6

この場合、ポインタ自体がconstであるかどうかは問題ではありstrcpyません。値渡しであるためですsource。オリジナル。ポインターが指すものではなく、ポインター値について話していることに注意してください。これはソースパラメーターであるため、明らかに変更しないでください。strcpysource

char dest[10];
char const * source = "Hello";
strcpy( dest, source );
// no matter what strcpy does, the value of source will be unchanged

内では、 andがstrcpy指す配列に対してポインターを反復処理する必要があります。パラメーターを const として宣言しないと、関数は最初に値をコピー/キャストすることなく、スタックから直接値を使用できます。destinationsource

于 2012-07-23T11:27:27.213 に答える
5

const char * 持つことは契約を表します。関数がそのポインターを使用して、ユーザーから渡されたコンテンツを変更しないことを約束します。ポインター自体が定数であるかどうかはあまり重要ではありません。

したがって、呼び出し元にとっては、ポインター自体が存在するかどうかはconstまったく関係ありません。

多くの実装では、「文字列」関数は、内容を変更せずに渡されたポインタを定期的に変更します。仕様 (C 標準) でポインター自体が定数であることが義務付けられている場合、それはすべての実装の制限要因となり、呼び出し元には何のメリットもありません。


const補足として、すべてを作成してから、それを回避するべきではないと思います。関数を変更する理由がないと思われるconst場合、何かを作成してください。要するに、const に夢中にならないでください。これは特効薬ではなく、フラストレーションの原因になる可能性があります。

于 2012-07-23T11:27:41.230 に答える
3

関数パラメーターをとして宣言する場合const char * const、呼び出し元と違いはありません。呼び出し元はconst char *、とにかくすべて「値渡し」であるため、そのポインターで何をするかを気にする必要はありません。

2つ目constは、ユーザーではなく、あなたのためにあります。そのポインタを変更しないことがわかっている場合は、必ずそれを宣言してconst char * constください。コードを管理しているあなたや他の人が後でエラーをキャッチするのに役立ちます。

標準ライブラリに関してはconst char * const、poitnersを変更する機能が必要だったため、作成したくなかったと思います。

char * strcpy ( char * destination, const char * source ) {
    char *res = destination;
    while (*destination++ = *source++)
        ;
    return res;
}
于 2012-07-23T11:34:13.783 に答える
3

非定義宣言:

int countA(char const * string);
int countA(char const * const string);
int countA(char const * foobar);
int countA(char const *);

はすべて同等です。パラメータは、string(実際には) の実装内のローカル変数に名前を付けますcountA。実装がその変数を変更するかどうかは、呼び出し元の仕事ではなく、関数の署名には影響しません。

関数が の参照先を変更するかどうかは呼び出し元の仕事なので、最初の const が重要ですstring変数に名前を付けるのは呼び出し元の仕事ですが、これは、宣言内のパラメーターに、その使用目的のヒントとして名前を付けることが慣例であるためです。ドキュメントは、名前ではなく、各パラメーターの意味を完全に伝える方法です。

ルールが必要な場合: 2 番目の を省略しconstます。これは、呼び出し元に何の役にも立ちませんが、宣言が乱雑になるためです。

関数定義に含めることもできますが、そうするといくつかの問題があります。定義を使用してヘッダーを最新の状態に保つ必要があります (この場合、呼び出し元に影響しない実装の詳細の変更により、ヘッダーを変更することがあります)。または、ヘッダーが定義と一致しないことを受け入れる必要があります。

int countA(char const * const string) {
    return 0; 
}

ヘッダーで を検索するint countA(char const * const string)か、逆にヘッダーを参照してソースを検索します。彼らはよりスマートな検索語を必要としています。

于 2012-07-23T11:32:02.663 に答える
2
  • char const *s:sへのポインタconst charです。
  • char *const s:sへの定数ポインタcharです。

が関数パラメータの場合s、最初の表記の方が 2 番目の表記よりも便利です。

  • ではchar const *、ポイントされた値を変更できません。
  • ではchar *const、ポインタの値を変更できません。関数パラメーターの場合と同様int constです。パラメーターに対して直接操作を行うことはできません。call 関数については何も変更しません。(現在、コンパイラーにとってはほとんど役に立ちませんが、プログラマーにとっては意味があります)
于 2012-07-23T11:50:39.450 に答える