web-dev-qa-db-ja.com

C文字配列の初期化

初期化後の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]はランダムコンテンツになりますか?

89
lkkeepmoving

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

  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で初期化されます。これは、配列が関数内で宣言されている場合でも同様です。

188
ouah

編集:私がこの答えを提供した後のある時点でOP(または編集者)は静かに元の質問の中のいくつかの一重引用符を二重引用符に変更しました。

あなたのコードはコンパイラエラーになります。あなたの最初のコードの一部:

char buf[10] ; buf = ''

二重に違法です。まず、Cでは、空の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、つまり'\0'である10文字の配列を返します。配列が初期化指定子で宣言され定義されると、指定された初期値を持つものを過ぎた配列要素(もしあれば)は自動的に0で埋め込まれます。 「ランダムなコンテンツ」はありません。

次のように、配列を宣言して定義しても初期化しないとします。

char buf [10];

あなたはすべての要素にランダムな内容を持つでしょう。

20
verbose
  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};
    
18
Steven Penny

C11標準ドラフトn1570 6.7.9初期化の関連部分には、次のように記載されています。

14文字型の配列は、オプションで中括弧で囲まれた文字列リテラルまたはUTF-8文字列リテラルによって初期化できます。文字列リテラルの連続バイト(空きがある場合や配列のサイズが不明な場合は終端のヌル文字を含む)は、配列の要素を初期化します。

そして

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

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

最後に、

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

[-]

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

[-]

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

6
Antti Haapala

興味深いことに、配列がstructまたはunionのメンバーであれば、プログラム内でいつでも配列を初期化することができます。

プログラム例:

#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;
}
3
user3381726

確信はありませんが、私は一般的に ""に配列を初期化します。その場合、私は文字列の最後の空白について心配する必要はありません。

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'
}
0
Erric Rapsing