C文字配列の初期化


118

次の方法で初期化した後、char配列に何が入るかわかりません。

1. char buf[10] = "";
2. char buf[10] = " ";
3。char buf[10] = "a";

ケース2の場合は、私が考えるbuf[0]べきである' 'buf[1]あるべき'\0'、とからbuf[2]buf[9]ランダムな内容になります。ケース3の場合、私は考えるbuf[0]べきである'a'buf[1]「\ 0」でなければなりません、そしてからbuf[2]buf[9]ランダムな内容になります。

あれは正しいですか?

そして、ケース1の場合、何が入りますbufか?buf[0] == '\0'以下とからbuf[1]buf[9]ランダムな内容でしょうか?


2
ええと、私のコンパイラはあなたの(修正された)コードを受け入れません:「配列型 'char [10]'は割り当て可能ではありません」。
マーティンR

@MartinRが動作するようになりました...
lkkeepmoving

1
@lkkeepmoving:コンパイルchar buf[10]; buf = "a";しませ。-まず試してから、実際のコードをコピーして質問に貼り付けてください。それはあなたとあなたの質問のすべての読者のために多くの仕事を節約します。
Martin R

@MartinR申し訳ありません。後者のbuf []を割り当てられると思いましたが、そうではありません。これでコードが実行されます。
lkkeepmoving 2013

回答:


222

これは配列を初期化する方法ではありませんが、

  1. 最初の宣言:

    char buf[10] = "";

    に相当

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. 2番目の宣言:

    char buf[10] = " ";

    に相当

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. 3番目の宣言:

    char buf[10] = "a";

    に相当

    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

ご覧のとおり、ランダムなコンテンツはありません。初期化子の数が少ない場合、配列の残りはで初期化され0ます。これは、配列が関数内で宣言されている場合でも同様です。


45
質問をする人のために、C規格では、部分的に完全な配列の初期化を、残りの要素に対して(コンパイラーによって)ゼロで埋める必要があることを指摘する価値があります。これは、だけでなく、すべてのデータ型に当てはまりcharます。
水田

4
@ouah buf []の最後に '\ 0'がないのはなぜですか?
lkkeepmoving 2013

14
@lkkeepmoving 0'\0同じ値です。
ouah 2013

1
@lkkeepmoving初期化と割り当ては2つの異なる野獣であるため、Cでは文字配列をchar配列の初期化子として指定できますが、配列の割り当ては禁止されています(そうだそうです)。
Lorenzo Donati-Codidact.com

3
@Pacerier char buff[3] = "abcdefghijkl";は無効です。char p3[5] = "String";も無効です。char p[6] = "String";は有効で、と同じchar p[6] = {'S', 't', 'r', 'i', 'n', 'g'};です。
ouah

28

編集:OP(またはエディター)が、元の質問の単一引用符のいくつかを、この回答を提供した後のある時点で、二重引用符に黙って変更しました。

コードによってコンパイラエラーが発生します。最初のコードフラグメント:

char buf[10] ; buf = ''

二重に違法です。まず、Cでは、emptyのようなものはありませんchar。次のように、二重引用符を使用して空の文字列を指定できます。

char* buf = ""; 

これにより、NUL文字列へのポインタ、つまり、文字のみが含まれる単一文字の文字列が得られますNUL。ただし、内部に何もない単一引用符は使用できません。これは未定義です。NUL文字を指定する必要がある場合は、指定する必要があります。

char buf = '\0';

バックスラッシュは、文字と区別するために必要'0'です。

char buf = 0;

同じことを達成しますが、前者は少し曖昧さを少なくしていると思います。

次に、定義された配列は初期化できません。

char buf[10];

配列を宣言して定義します。配列識別子bufはメモリ内のアドレスになりbufました。割り当てを通じてポイントを変更することはできません。そう

buf =     // anything on RHS

違法です。このため、2番目と3番目のコードフラグメントは違法です。

配列を初期化するには、定義時にそれを行う必要があります。

char buf [10] = ' ';

最初の文字がスペース'\040'で残りがNULである10文字の配列が得られます'\0'。初期化子を使用して配列が宣言および定義されると、指定された初期値を持つ配列要素(ある場合)を過ぎた配列要素には、自動的にが埋め込まれ0ます。「ランダムなコンテンツ」はありません。

次のように、配列を宣言して定義しても初期化しない場合:

char buf [10];

すべての要素にランダムなコンテンツが含まれます。


「配列を初期化するには、定義時にそれを行う必要があります...」これと、次の行は、これを受け入れられた回答よりも優れています。
Laurie Stearn 2016

25
  1. これらは同等です

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. これらは同等です

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. これらは同等です

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

8

C11標準ドラフトn1570 6.7.9初期化の関連部分は次のように述べています。

14 文字タイプの配列は、文字列リテラルまたはUTF-8文字列リテラルで初期化できます。オプションで中括弧で囲むこともできます。文字列リテラルの連続するバイト(スペースがある場合、または配列のサイズが不明の場合は、終端のnull文字を含む)は、配列の要素を初期化します。

そして

21 が存在する場合、集約の要素またはメンバーが存在するよりも、中括弧で囲まれたリスト内のより少ない初期化子、またはより少ない文字が文字列リテラルでは、配列の要素が存在するよりも、既知のサイズのアレイを初期化するために、集合体の残りの部分を使用しました静的な保存期間を持つオブジェクトと同じように暗黙的に初期化されます

したがって、十分なスペースがある場合は「\ 0」が追加され、残りの文字はstatic char c;関数内で初期化される値で初期化されます。

最後に、

10 自動保存期間を持つオブジェクトが明示的に初期化されていない場合、その値は不確定です。静的またはスレッドのストレージ期間を持つオブジェクトが明示的に初期化されていない場合は、次のようになります。

[-]

  • 算術型の場合、(正または符号なし)ゼロに初期化されます。

[-]

したがって、char算術型であるため、配列の残りの部分もゼロで初期化されることが保証されます。


3

興味深いことに、彼らがメンバーで提供される、プログラム中の任意の時点でどのような方法で配列を初期化することが可能ですstructunion

プログラム例:

#include <stdio.h>

struct ccont
{
  char array[32];
};

struct icont
{
  int array[32];
};

int main()
{
  int  cnt;
  char carray[32] = { 'A', 66, 6*11+1 };    // 'A', 'B', 'C', '\0', '\0', ...
  int  iarray[32] = { 67, 42, 25 };

  struct ccont cc = { 0 };
  struct icont ic = { 0 };

  /*  these don't work
  carray = { [0]=1 };           // expected expression before '{' token
  carray = { [0 ... 31]=1 };    // (likewise)
  carray = (char[32]){ [0]=3 }; // incompatible types when assigning to type 'char[32]' from type 'char *'
  iarray = (int[32]){ 1 };      // (likewise, but s/char/int/g)
  */

  // but these perfectly work...
  cc = (struct ccont){ .array='a' };        // 'a', '\0', '\0', '\0', ...
  // the following is a gcc extension, 
  cc = (struct ccont){ .array={ [0 ... 2]='a' } };  // 'a', 'a', 'a', '\0', '\0', ...
  ic = (struct icont){ .array={ 42,67 } };      // 42, 67, 0, 0, 0, ...
  // index ranges can overlap, the latter override the former
  // (no compiler warning with -Wall -Wextra)
  ic = (struct icont){ .array={ [0 ... 1]=42, [1 ... 2]=67 } }; // 42, 67, 67, 0, 0, ...

  for (cnt=0; cnt<5; cnt++)
    printf("%2d %c %2d %c\n",iarray[cnt], carray[cnt],ic.array[cnt],cc.array[cnt]);

  return 0;
}

1

よくわかりませんが、通常は配列を ""に初期化します。この場合、文字列のnullの終わりについて心配する必要はありません。

main() {
    void something(char[]);
    char s[100] = "";

    something(s);
    printf("%s", s);
}

void something(char s[]) {
    // ... do something, pass the output to s
    // no need to add s[i] = '\0'; because all unused slot is already set to '\0'
}

暗黙のintルールを実際に使用するべきではありません。あなたがのためのタイプを指定する必要がありますmain()(そして、あなたも使用する必要がありvoid、すなわち、int main(void) { ... }このコードはC99用にコンパイルし、後でないようにします。C99は、この規則を処分した。ここで注意すべき他の事があることである起動を省略した場合、C99とreturnでmain、メインの終わりのreturn 0;前に自動配置/暗黙指定があります。C99以前}でのみ機能する暗黙のintルールを使用していますがreturn、C99 以降でのみ機能する暗黙を使用しています。これら2つは明らかに矛盾しています。
RastaJedi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.