2017-01-23 7 views
6

理由はstrcpyの署名があるのはこれですか?strcpyがdestにconstポインタを使用しないのはなぜですか?これに代えて</p> <pre><code>char *strcpy(char *dest, const char *src); </code></pre> <p>:

char *strcpy(char *const dest, const char *src); 

私の知る限り、関数は決してポインタを変更しません。

私は何のconstポインタを使用すべきか誤解していますか?私の考えでは、私が書いた関数が(reallocなどで)変更されないポインタを受け入れると、それをconstポインタとしてマークするので、呼び出し側はそのポインタがポインタ上に移動しないことが保証されます。 (他の構造体/ etcが、そのポインタの場所を参照して古いものになっている場合)

これは問題ありませんか、それとも意図しない結果になりますか?

+0

の左側のconstによる制御でありますまたは宣言時に定義されます。 –

+0

この関数はポインタを変更することは決してありませんが、constがなくても 'strcpy'が' dest'を変更する方法はありません。 –

答えて

11

strcpyのソースコードは非常に大まかこれです:

char *strcpy(char *dest, const char *src) 
{ 
    while (*dest++ = *src++); 
} 

ここでは、実際にdestを変更しませんが、strcpy関数の内部で、destはローカル変数であるため、これは、発信者には結果がありません。

char *strcpy(char * const dest, const char *src) 
{ 
    while (*dest++ = *src++); 
} 

は、我々はこれを書くために必要があるでしょう:非必要temp変数を導入し

char *strcpy(char * const dest, const char *src) 
{ 
    char *temp = dest; 
    while (*temp++ = *src++); 
} 

destがconstのがあるので

しかし、次のコードはコンパイルされません。

+1

注:3つの例は、 'char * strcpy()'関数がそれらをUBに変換するための値を返しません。 Cライブラリで指定されている元の 'dest'を返す「不要な一時変数」を持たないコードを見るのは面白いでしょう。 – chux

+0

@chuxあなたは完全に正しいですが、デモンストレーションの目的にすぎません。 –

3

関数の引数の修飾子は、が完全に無視された宣言(プロトタイプ)のです。これはC言語で必要とされ、そのような修飾が関数の呼び出し側に与える可能性のある意味がないため、意味があります。

const char *srcの場合、引数srcは修飾されていません。それが指すタイプは修飾されています。 destの仮想宣言では、修飾子はdestに適用されるため、無意味です。

-1

私の知る限り、関数は決してポインタを変更しません。

はい、可能です。あなたはポインタを自由に変更することができます。 destポインタconstを作る必要はありません。例えば

:あなたが提案するよう

int main(void) 
{ 
    char *s = "Hello"; 
    char *d = malloc(6); 

    strcpy(d, s); 
    puts(d); 
    strcpy(d, "World"); 
    puts(d); 
} 
1

のconstとしてそれをマークすることは無意味です。 Cでは、関数の引数はコピーとして渡されます。これは、変数deststrcpy()であり、実際には同じ内容(ここではアドレス)を保持する新しい変数(スタックにプッシュされる)であることを意味します。この関数プロトタイプで

ルック:

void foo(int const a); 

我々はそれがコピーであるので、我々はfoo()に渡された元の変数を変更することができないことを知っているので、これは、何の意味値を持ちません。コピーのみが変更される可能性があります。 fooが復帰すると、元の変数aは変更されないことが保証されます。

関数のパラメータでは、関数が実際に変数の状態を永続的に変更できる場合にのみ、キーワードconstを使用します。例えば:

size_t strlen(const char *s); 

これはCONST変数としてs(アドレスsポイントにで保存し、即ち、値)の内容をマークします。したがって、strlenが返ってくると、文字列は変更されないことが保証されます。

2

char *foo(char *const dest, const char *src) { ... }は、ポインタdestが機能の本体で変更されないことを意味します。

destが指し示すデータが変更されることはありません。

const char *srcは、srcが指し示すデータが変更されないという呼び出しコードを保証します。

関数は、ポインタのそのコピーを変更した場合strcpy(d,s)またはfoo(d,s)のような関数を呼び出すには、呼び出し元のコードは気にしません。データがsまたはdが変更されたことで指されている場合、すべての呼び出し元のコードが気であり、それは私が一定では一度だけ定義/ assighned /初期化することができると思い*

char *dest,  // data pointed by `dest` may or may not change. 
const char *src // data pointed by `src` will not change change because of `src`. 
関連する問題