C char array inisialisasi

119

Saya tidak yakin apa yang akan ada di array karakter setelah inisialisasi dengan cara berikut.

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

Untuk kasus 2, saya pikir buf[0]harus ' ', buf[1]harus '\0', dan dari buf[2]ke buf[9]akan menjadi konten acak. Untuk kasus 3, menurut saya buf[0]seharusnya 'a', buf[1]harus '\ 0', dan dari buf[2]hingga buf[9]akan menjadi konten acak.

Apakah itu benar?

Dan untuk kasus 1, apa yang akan ada di buf? buf[0] == '\0'dan dari buf[1]sampai buf[9]akan menjadi konten acak?

lkkeepmoving
sumber
2
Nah, kompilator saya tidak menerima kode (dikoreksi) Anda: "tipe array 'char [10]' tidak dapat dialihkan".
Martin R
@MartinR sekarang akan berhasil ...
lkkeepmoving
1
@ lkkeepmoving: char buf[10]; buf = "a";tidak dapat dikompilasi. - Silakan coba dulu, lalu salin / tempel kode Anda yang sebenarnya ke dalam pertanyaan. Itu menghemat banyak pekerjaan untuk Anda dan untuk semua pembaca pertanyaan Anda.
Martin R
@MartinR Maaf untuk itu. Saya pikir saya dapat menetapkan buf [] yang terakhir tetapi tampaknya tidak. Sekarang kodenya berjalan.
lkkeepmoving

Jawaban:

222

Ini bukan cara Anda menginisialisasi array, tetapi untuk:

  1. Deklarasi pertama:

    char buf[10] = "";

    setara dengan

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Deklarasi kedua:

    char buf[10] = " ";

    setara dengan

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Deklarasi ketiga:

    char buf[10] = "a";

    setara dengan

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

Seperti yang Anda lihat, tidak ada konten acak: jika ada lebih sedikit penginisialisasi, sisa larik diinisialisasi dengan 0. Ini terjadi bahkan jika array dideklarasikan di dalam suatu fungsi.

ouah
sumber
46
Demi orang yang mengajukan pertanyaan, ada baiknya menunjukkan bahwa standar C mengharuskan inisialisasi array yang sebagian lengkap diisi dengan nol untuk elemen yang tersisa (oleh kompilator). Ini berlaku untuk semua tipe data, tidak hanya char.
paddy
4
@ouah kenapa tidak ada '\ 0' di akhir buf []?
lkkeepmoving
14
@lkkeepmoving 0dan '\0memiliki nilai yang sama.
ouah
1
@lkkeepmoving Inisialisasi dan penugasan adalah dua beast yang berbeda, sehingga C memungkinkan Anda menyediakan string sebagai penginisialisasi untuk larik karakter, tetapi melarang penugasan larik (seperti yang Anda katakan).
Lorenzo Donati - Codidact.com
3
@Pacerier char buff[3] = "abcdefghijkl";tidak valid. char p3[5] = "String";juga tidak valid. char p[6] = "String";valid dan sama dengan char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah
28

Sunting: OP (atau editor) diam-diam mengubah beberapa tanda kutip tunggal dalam pertanyaan awal menjadi tanda kutip ganda di beberapa titik setelah saya memberikan jawaban ini.

Kode Anda akan menghasilkan kesalahan kompiler. Fragmen kode pertama Anda:

char buf[10] ; buf = ''

adalah ilegal ganda. Pertama, di C, tidak ada yang namanya kosong char. Anda dapat menggunakan tanda kutip ganda untuk menunjukkan string kosong, seperti:

char* buf = ""; 

Itu akan memberi Anda penunjuk ke NULstring, yaitu, string satu karakter dengan hanya NULkarakter di dalamnya. Tetapi Anda tidak dapat menggunakan tanda kutip tunggal dengan tidak ada isinya - itu tidak ditentukan. Jika Anda perlu menentukan NULkarakter, Anda harus menentukannya:

char buf = '\0';

Garis miring terbalik diperlukan untuk membedakan karakter '0'.

char buf = 0;

menyelesaikan hal yang sama, tetapi yang pertama agak kurang ambigu untuk dibaca, saya kira.

Kedua, Anda tidak dapat menginisialisasi array setelah didefinisikan.

char buf[10];

mendeklarasikan dan mendefinisikan array. Pengenal array bufsekarang menjadi alamat di memori, dan Anda tidak dapat mengubah di mana buftitik melalui tugas. Begitu

buf =     // anything on RHS

ilegal. Fragmen kode kedua dan ketiga Anda ilegal karena alasan ini.

Untuk menginisialisasi sebuah array, Anda harus melakukannya pada saat mendefinisikan:

char buf [10] = ' ';

akan memberi Anda array 10 karakter dengan karakter pertama adalah spasi '\040'dan karakter lainnya NUL, yaitu '\0'. Ketika sebuah array dideklarasikan dan didefinisikan dengan penginisialisasi, elemen array (jika ada) melewati yang dengan nilai awal yang ditentukan secara otomatis diisi 0. Tidak akan ada "konten acak".

Jika Anda mendeklarasikan dan mendefinisikan array tetapi tidak menginisialisasinya, seperti berikut ini:

char buf [10];

Anda akan memiliki konten acak di semua elemen.

bertele-tele
sumber
"Untuk menginisialisasi larik, Anda harus melakukannya pada saat mendefinisikan ..." Ini, dan baris berikut membuat ini lebih baik daripada jawaban yang diterima.
Laurie Stearn
26
  1. Ini setara

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Ini setara

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Ini setara

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};
Steven Penny
sumber
8

Bagian yang relevan dari draft standar C11 n1570 6.7.9 inisialisasi mengatakan:

14 Sebuah array tipe karakter dapat diinisialisasi dengan karakter string literal atau UTF-8 string literal, secara opsional diapit oleh tanda kurung. Byte berturut-turut dari string literal (termasuk karakter null penghentian jika ada ruang atau jika ukuran array tidak diketahui) menginisialisasi elemen array.

dan

21 Jika ada lebih sedikit penginisialisasi dalam daftar yang diapit tanda kurung kurawal daripada ada elemen atau anggota agregat, atau lebih sedikit karakter dalam string literal yang digunakan untuk menginisialisasi larik dengan ukuran yang diketahui daripada jumlah elemen dalam larik, sisa agregat harus diinisialisasi secara implisit sama dengan objek yang memiliki durasi penyimpanan statis.

Jadi, '\ 0' ditambahkan, jika ada cukup ruang , dan karakter yang tersisa diinisialisasi dengan nilai yang static char c;akan diinisialisasi dalam suatu fungsi.

Akhirnya,

10 Jika sebuah objek yang memiliki durasi penyimpanan otomatis tidak diinisialisasi secara eksplisit, nilainya tidak pasti. Jika sebuah objek yang memiliki durasi penyimpanan statis atau thread tidak diinisialisasi secara eksplisit, maka:

[-]

  • jika memiliki tipe aritmatika, ia diinisialisasi ke nol (positif atau tidak bertanda tangan);

[-]

Jadi, charsebagai tipe aritmatika, sisa dari array juga dijamin akan diinisialisasi dengan nol.

Antti Haapala
sumber
3

Yang cukup menarik, adalah mungkin untuk menginisialisasi array dengan cara apapun dan kapanpun dalam program, asalkan mereka adalah anggota dari structatau union.

Contoh program:

#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;
}
pengguna3381726
sumber
1

Saya tidak yakin tetapi saya biasanya menginisialisasi sebuah array ke "" dalam hal ini saya tidak perlu khawatir tentang akhir null dari string.

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'
}
Erric Rapsing
sumber
Anda seharusnya tidak benar-benar menggunakan aturan int implisit . Anda harus menentukan jenis untuk main()(dan Anda juga harus menggunakan void, yaitu, int main(void) { ... }. C99 menyingkirkan aturan ini, sehingga kode ini tidak dapat dikompilasi untuk C99 dan kemudian. Hal lain yang perlu diperhatikan di sini adalah bahwa mulai dengan C99, jika Anda menghilangkan returndi main, ada otomatis return 0;ditempatkan / tersirat sebelum }di ujung utama. Anda menggunakan aturan int implisit yang hanya bekerja sebelum C99, namun Anda menggunakan implisit returnyang hanya bekerja dengan C99 dan yang lebih baru ; keduanya jelas kontradiktif .
RastaJedi