#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abc";
char * p1 = "abc";
printf("%d %d", p, p1);
}
2つのポインタの値を出力すると、同じアドレスが出力されます。どうして?
#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abc";
char * p1 = "abc";
printf("%d %d", p, p1);
}
2つのポインタの値を出力すると、同じアドレスが出力されます。どうして?
p
とのアドレスを取得した場合p1
、これら2つのポインタが2つの異なるアドレスに格納されていることに気付くでしょう。それらの値が同じであるという事実は、この場合は無関係です。
p == p1
(違いはありません)が&p != &p1
(違いはあります)。
回答:
同じ内容の2つの異なる文字列リテラルを同じメモリ位置に配置するか、異なるメモリ位置に配置するかは、実装によって異なります。
同じアドレスを指している場合とそうでない場合があるためp
、常にとp1
を2つの異なるポインタとして扱う必要があります(同じ内容であっても)。コンパイラの最適化に頼るべきではありません。
C11標準、6.4.5、文字列リテラル、セマンティクス
それらの要素が適切な値を持っている場合、これらの配列が異なるかどうかは指定されていません。プログラムがそのような配列を変更しようとした場合、動作は定義されていません。
印刷の形式は%p
次のとおりです。
printf("%p %p", (void*)p, (void*)p1);
理由については、この回答を参照してください。
i modify one of the pointer, will the data in the other pointed also be modified
は変更できますが、文字列リテラルは変更できません。たとえばchar *p="abc"; p="xyz";
、未定義の動作をchar *p="abc"; p[0]='x';
呼び出すのに対し、完全に問題ありません。これはとは何の関係もありませんvolatile
。使用するかどうかにかかわらvolatile
ず、ここで関心のある動作を変更するべきではありません。volatile
基本的に、毎回メモリからデータを読み取るように強制します。
p
、文字列リテラルの点"abc"
とp[0]='x'
、文字列リテラルの最初の文字を変更することを試みます。文字列リテラルを変更しようとすると、Cの未定義の動作である
char []
Cにあることです。したがって、(const char*
C ++の場合のように)読み取り専用にするには、タイプも変更する必要があります。[続き]
"Strings are no longer modifiable, and so may be placed in read-only memory"
、文字列リテラルは、その歴史的証拠使用;-)変更可能であること
あなたのコンパイラは非常に賢いようで、両方のリテラルが同じであることを検出します。また、リテラルは定数であるため、コンパイラーはそれらを2回格納しないことを決定しました。
これは必ずしもそうである必要はないことを言及する価値があるようです。参照してくださいブルームーンさん、この上の答えを。
ところで:printf()
ステートメントは次のようになります
printf("%p %p", (void *) p, (void *) p1);
as"%p"
はポインタ値を出力するために使用され、タイプのポインタに対してvoid *
のみ定義されます。* 1
また、コードにはreturn
ステートメントが欠けていると思いますが、C標準は変更の過程にあるようです。他の人は親切にこれを明らかにするかもしれません。
* 1:void *
ここへのキャストは、char *
ポインターには必要ありませんが、他のすべてのタイプへのポインターには必要です。
==
strcmpy()
関数を使用てください。AlkがPSに答えたように、他のコンパイラが最適化を使用していない可能性があるため(コンパイラ次第-実装は依存しません)、BlueMoonはそれについて追加しました。
あなたのコンパイラは「文字列プーリング」と呼ばれる何かをしました。同じ文字列リテラルを指す2つのポインタが必要であると指定したため、リテラルのコピーは1つだけ作成されました。
技術的には:ポインタを「const」にしないことについて不平を言うべきでした
const char* p = "abc";
これは、Visual Studioを使用しているか、-WallなしでGCCを使用していることが原因である可能性があります。
それらをメモリに2回保存することを明示的に希望する場合は、次のことを試してください。
char s1[] = "abc";
char s2[] = "abc";
ここでは、文字への2つのポインターではなく、2つのc文字列文字配列が必要であることを明示的に指定します。
警告:文字列プーリングはコンパイラ/オプティマイザの機能であり、言語の側面ではありません。そのため、さまざまな環境でのさまざまなコンパイラは、最適化レベル、コンパイラフラグ、文字列がさまざまなコンパイル単位にあるかどうかなどに応じて、さまざまな動作を生成します。
gcc (Debian 4.4.5-8) 4.4.5
を使用していても、文句を言わない(警告)-Wall -Wextra -pedantic
。
const
は文字列リテラルに使用しないことについて警告しません。警告はオプションで有効になります-Wwrite-strings
。これは明らかに(のような他のオプションで有効になっていない-Wall
、-Wextra
または-pedantic
)。
他の人が言っているように、コンパイラはそれらが同じ値を持っていることに気づいているので、最終的な実行可能ファイルでデータを共有することを決定しています。しかし、それはより巧妙になります:私が以下をコンパイルするとgcc -O
#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abcdef";
char * p1 = "def";
printf("%d %d", p, p1);
}
それ4195780 4195783
は私のために印刷します。つまり、のp1
3バイト後に開始するp
ため、GCCはdef
(\0
ターミネータを含む)の共通サフィックスを確認し、表示したものと同様の最適化を実行しました。
(コメントするには長すぎるので、これは答えです。)