char *とconst char *の違いは?


176

違いは何ですか

char* name

定数文字列リテラルを指す

const char* name

C(C ++ではない)の「定数文字列リテラル」とはどういう意味
ですか

1
... char * nameは定数文字列リテラルを指すように作成できます
Iceman

すべての文字列リテラルは理論的には定数エンティティであるため、「定数文字列リテラル」の定数は冗長です。定数または可変にすることができるのは、変数の内容です。「名前」が指す文字の内容を変更しようとすると、「const」宣言はコンパイル時エラーをスローするだけです
Cupcake

シンプル: "char * name" nameはcharへのポインタです。つまり、ここで両方を変更できます。"const char * name" nameはconst charへのポインターです。つまり、ポインターは変更できますが、charは変更できません。
akD 2017

これらを右から左に読んでください。
Jiapeng Zhang

回答:


405

char*ある可変へのポインタ可変文字/文字列。

const char*ある可変へのポインタ不変の文字/文字列。このポインターが指す場所の内容は変更できません。また、コンパイラーは、エラーメッセージを表示しようとするときに必要です。同じ理由で、からconst char *への変換char*は廃止されました。

char* constある不変ポインタ(それは他の場所を指すことができない)が、その点があるれる位置の内容を変更可能

const char* const不変の文字/文字列への不変のポインタです。


4
上記のステートメントの後に変数を使用すると、その変数を参照することで混乱を解消できます。
ankit.karwasra 2013年

3
@ ankit.karwasra、あなたはもう1つ逃しました:char const *
Pacerier

可変の文字/文字列を使用する2つのオプションは、セグメンテーション障害メモリを実行できるため非常に危険であると思います。本当に賢い場合は、コンピュータをハッキングする可能性があります。コンパイラが常にこれらの実装で警告を表示したのはそのためです
Daniel N.

1
char *実行中に変異するとセグメンテーション違反が発生しませんか?
Divyanshu Maithani 2017

1
それでconst、誤ってデータを忘れて変更した場合にコンパイラーにエラーを出させたい場合に使用しますよね?
会計士م '

43
char *name

nameポイントする文字、およびポイントする文字を変更できます。

const char* name

nameポイントする文字を変更できますが、ポイントする文字を変更することはできません。
訂正:ポインターは変更できますが、ポイントする文字は変更できませんnamehttps://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx、「例」を参照) )。この場合、const指定子はcharアスタリスクではなくに適用されます。

MSDNページとhttp://en.cppreference.com/w/cpp/language/declarationsによると、const*はdecl-specifierシーケンスの一部で、const*は宣言の一部です。
宣言指定子シーケンスの後には複数の宣言子を続けることができます。そのため、as およびasをconst char * c1, c2宣言します。c1const char *c2const char

編集:

コメントから、あなたの質問は、ポインターが文字列リテラルを指しているときの2つの宣言の違いについて尋ねているようです。

その場合、Undefined Behaviorが発生する可能性があるため、指すcharを変更しないでください。文字列リテラルは読み取り専用メモリ領域(実装が定義されている)に割り当てることができ、ユーザープログラムはそれを変更しないでください。そうしようとすると、未定義の動作が発生します。 name

したがって、その場合の唯一の違い(文字列リテラルでの使用法)は、2番目の宣言がわずかな利点をもたらすことです。2番目のケースで文字列リテラルを変更しようとすると、コンパイラーは通常警告を出します。

オンラインサンプルの例:

#include <string.h>
int main()
{
    char *str1 = "string Literal";
    const char *str2 = "string Literal";
    char source[] = "Sample string";

    strcpy(str1,source);    //No warning or error, just Undefined Behavior
    strcpy(str2,source);    //Compiler issues a warning

    return 0;
}

出力:

cc1:警告がエラーとして扱われる
prog.c:関数 'main':
prog.c:9:エラー: 'strcpy'の引数1を渡すと、ポインターのターゲットタイプから修飾子が破棄されます

コンパイラは2番目のケースについて警告しますが、最初のケースについては警告しません。


ありがとう..次のように定義される定数文字列リテラルと混合しました。char* name = "String Literal"; 「文字列リテラル」の変更は定義されていません。.–
アイスマン

@ user1279782:エラー、待って!ここで文字列リテラルを指すポイントについて話していますか?その場合、どちらの場合もポイントするcharを変更しないでくださいname。UBになる可能性があります。
Alok Save

はい、それがポイントでした。その場合、char * nameとconst char * nameは同じように動作しますよね?
アイスマン、

4
この答えは、非常にあいまいであるか、まったく間違っています。「名前が指す文字を変更することはできませんが、それが指す文字を変更することはできます」と解釈します。:ポインタ自体を変更することができるが、間違っていた、それを指していることメモリ位置を変更することができないようideone.com/6lUY9s:代替的に純粋なCのためideone.com/x3PcTP
shroudednight

1
@shroudednight:未定義の動作についてもう少し学び、区別する必要があります。:)
Alokが2013

16
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)

constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error

constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok

// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";

lcharp[0] = 'X';      // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error

// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X';          // compile error
((char*)astr)[0] = 'X'; // ok

1
質問のとおり、どのポインタも「定数文字列リテラル」を指していません。
ca

それの価値が変化することを指摘しchar *、我々は、文字列リテラル(読み取り専用メモリ内に存在している)を変更しようとしているので、値がセグメンテーションフォールトを与える
Divyanshu Maithani

10

どちらの場合も、文字列リテラルへのポインタがchar *またはとして宣言されているかどうかに関係なく、文字列リテラルを変更することはできませんconst char *

ただし、ポインタがそうである場合、ポイントconst char *された値を変更しようとするとコンパイラは診断を行う必要がありますが、ポインタがそうである場合は違いますchar *


1
「どちらの場合も、文字列リテラルを変更することはできません。... [it]がchar *またはconst char *として宣言されているかどうかにかかわらず」プログラマーが試してはならないことに同意しますが、すべてのCコンパイラは、プラットフォームはコードを拒否しますか、実行時にコードが失敗するように調整しますか?あるファイルには定義と初期化があり、別のファイルにはが含まれextern ... nameているかもしれません*name = 'X';。「適切なオペレーティングシステム」では失敗する可能性がありますが、組み込みシステムでは、プラットフォーム/コンパイラ固有の何かを実行することを期待しています。
gbulmer 2012年

@gbulmer:正しいCプログラムで文字列リテラルを変更することはできません。試行する不正なCプログラムがもたらす可能性のあるものはここにもありません。
ca

@gbulmer:1つの有用な定義は、C言語標準で指定された制約を破らないプログラムです。つまり、文字列リテラルを変更するプログラムは、nullポインターを逆参照するプログラムや0による除算を行うプログラムと同じように正しくありません。
ca

caf-私はそれがあなたの意味するところかもしれないと思った。その場合、「どちらの場合文字列リテラルを変更することはできません」と言っているようです。「どちらの場合でも、C言語標準で指定された制約が破られているかどうかにかかわらず...コンパイラまたはランタイムシステムがすべての場合に標準の違反を特定することは不可能です。」基準は効果が定義されていないという立場を取ると思いますか?
gbulmer 2012年

1
標準がどちらの方法でも何も主張できない場合、「未定義」であると動作を定義することは、正確な境界であり、役立つように思われます。「正しいCプログラム」「nullポインターを逆参照できない」関係を表明することは、停止の問題を証明することと同じように聞こえます。でも構わない。私はそれをせず、「スコットフリー」でそれを
回避

4

ケース1:

char *str = "Hello";
str[0] = 'M'  //Warning may be issued by compiler, and will cause segmentation fault upon running the programme

上記はstrをプログラムのバイナリイメージにハードコード化されたリテラル値「Hello」を指すように設定します。これはメモリ内で読み取り専用としてフラグが立てられ、この文字列リテラルの変更はすべて違法であり、セグメンテーション違反をスローします。

ケース2:

const char *str = "Hello";
str[0] = 'M'  //Compile time error

ケース3:

char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".

2

最初は必要に応じて実際に変更でき、2番目は変更できません。const正しさについて読んでください(違いについていくつかの素晴らしいガイドがあります)。char const * nameあなたがそれを再ポイントできない場所もあります。


正確に何が変わることができますか?
Antti Haapala 2017

2

問題は、違いは何ですか

char *name

定数文字列リテラルを指す

const char *cname

すなわち与えられた

char *name = "foo";

そして

const char *cname = "foo";

2つの間に大きな違いはなく、どちらも正しいと見なすことができます。Cコードの長いレガシーにより、文字列リテラルのタイプはchar[]でなくconst char[]であり、引数を変更しない場合でも、同様にのchar *代わりに受け入れる古いコードがたくさんありconst char *ます。

一般に、2の主な違いは、*cnameor cname[n]はタイプの左辺値に評価されるのconst charに対し、*nameor name[n]はタイプの左辺値に評価されchar変更可能な左辺値です。割り当てのターゲットが変更可能な左辺値でない場合、診断メッセージを生成するには、適合コンパイラが必要です。タイプの左辺値への割り当て時に警告を生成する必要はありませんchar

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message

どちらの場合も、コンパイラーはコンパイルを停止する必要はありません。への割り当てについて警告を出すだけで十分ですcname[0]。結果のプログラムは正しいプログラムではありません。コンストラクトの動作は未定義です。クラッシュする可能性があり、さらに悪いことに、クラッシュしない可能性があり、メモリ内の文字列リテラルを変更する可能性があります。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.