Khởi tạo mảng ký tự C


118

Tôi không chắc chắn những gì sẽ có trong mảng char sau khi khởi tạo theo các cách sau.

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

Đối với trường hợp 2, tôi nghĩ buf[0]nên có ' ', buf[1]nên có '\0', và từ buf[2]đến buf[9]sẽ là nội dung ngẫu nhiên. Đối với trường hợp 3, tôi nghĩ buf[0]nên là 'a', buf[1]nên là '\ 0', và từ buf[2]đến buf[9]sẽ là nội dung ngẫu nhiên.

Đúng không?

Và đối với trường hợp 1, những gì sẽ được trong buf? buf[0] == '\0'và từ buf[1]đến buf[9]sẽ là nội dung ngẫu nhiên?


2
Chà, trình biên dịch của tôi không chấp nhận mã (đã sửa) của bạn: "kiểu mảng 'char [10]' không thể gán được".
Martin R

@MartinR bây giờ nó sẽ hoạt động ...
lkkeepmoving

1
@lkkeepmoving: char buf[10]; buf = "a";không không biên dịch. - Vui lòng thử trước, sau đó sao chép / dán mã thực của bạn vào câu hỏi. Điều đó tiết kiệm rất nhiều công việc cho bạn và cho tất cả những người đọc câu hỏi của bạn.
Martin R

@MartinR Xin lỗi vì điều đó. Tôi nghĩ tôi có thể gán buf [] sau nhưng có vẻ như không. Bây giờ mã chạy.
lkkeepmoving

Câu trả lời:


222

Đây không phải là cách bạn khởi tạo một mảng, mà dành cho:

  1. Tuyên bố đầu tiên:

    char buf[10] = "";

    tương đương với

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. Tuyên bố thứ hai:

    char buf[10] = " ";

    tương đương với

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. Tuyên bố thứ ba:

    char buf[10] = "a";

    tương đương với

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

Như bạn có thể thấy, không có nội dung ngẫu nhiên: nếu có ít bộ khởi tạo hơn, phần còn lại của mảng sẽ được khởi tạo bằng 0. Trường hợp này xảy ra ngay cả khi mảng được khai báo bên trong một hàm.


45
Vì lợi ích của người đặt câu hỏi, cần chỉ ra rằng tiêu chuẩn C yêu cầu bất kỳ khởi tạo mảng hoàn chỉnh một phần nào phải được đệm bằng 0 cho các phần tử còn lại (bởi trình biên dịch). Điều này áp dụng cho tất cả các loại dữ liệu, không chỉ char.
paddy

4
@ouah tại sao không có '\ 0' ở cuối buf []?
lkkeepmoving

14
@lkkeepmoving 0'\0có cùng giá trị.
ouah

1
@lkkeepmoving Khởi tạo và gán là hai con thú khác nhau, do đó C cho phép bạn cung cấp một chuỗi làm bộ khởi tạo cho mảng char, nhưng cấm gán mảng (như ouah đã nói).
Lorenzo Donati - Codidact.com

3
@Pacerier char buff[3] = "abcdefghijkl";không hợp lệ. char p3[5] = "String";cũng không hợp lệ. char p[6] = "String";là hợp lệ và giống như char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};.
ouah

28

Chỉnh sửa: OP (hoặc một biên tập viên) đã âm thầm thay đổi một số dấu ngoặc kép trong câu hỏi ban đầu thành dấu ngoặc kép tại một số thời điểm sau khi tôi cung cấp câu trả lời này.

Mã của bạn sẽ dẫn đến lỗi trình biên dịch. Đoạn mã đầu tiên của bạn:

char buf[10] ; buf = ''

là bất hợp pháp gấp đôi. Đầu tiên, trong C, không có cái gọi là rỗng char. Bạn có thể sử dụng dấu ngoặc kép để chỉ định một chuỗi trống, như với:

char* buf = ""; 

Điều đó sẽ cung cấp cho bạn một con trỏ tới một NULchuỗi, tức là một chuỗi ký tự đơn chỉ có NULký tự trong đó. Nhưng bạn không thể sử dụng các dấu ngoặc kép đơn lẻ mà không có gì bên trong chúng - điều đó là không xác định. Nếu bạn cần chỉ định NULnhân vật, bạn phải chỉ định nó:

char buf = '\0';

Dấu gạch chéo ngược là cần thiết để phân biệt ký tự '0'.

char buf = 0;

hoàn thành điều tương tự, nhưng cái đầu tiên là ít mơ hồ hơn để đọc, tôi nghĩ.

Thứ hai, bạn không thể khởi tạo mảng sau khi chúng đã được xác định.

char buf[10];

khai báo và định nghĩa mảng. Định danh mảng bufbây giờ là một địa chỉ trong bộ nhớ và bạn không thể thay đổi vị trí bufđiểm thông qua phép gán. Vì thế

buf =     // anything on RHS

Là bất hợp pháp. Các đoạn mã thứ hai và thứ ba của bạn là bất hợp pháp vì lý do này.

Để khởi tạo một mảng, bạn phải thực hiện tại thời điểm định nghĩa:

char buf [10] = ' ';

sẽ cung cấp cho bạn một mảng 10 ký tự với ký tự đầu tiên là khoảng trắng '\040'và ký tự còn lại NULlà ký tự '\0'. Khi một mảng được khai báo và xác định bằng bộ khởi tạo, các phần tử của mảng (nếu có) nằm sau các phần tử có giá trị ban đầu được chỉ định sẽ tự động được thêm vào 0. Sẽ không có bất kỳ "nội dung ngẫu nhiên" nào.

Nếu bạn khai báo và xác định mảng nhưng không khởi tạo nó, như sau:

char buf [10];

bạn sẽ có nội dung ngẫu nhiên trong tất cả các phần tử.


"Để khởi tạo một mảng, bạn phải thực hiện nó tại thời điểm định nghĩa ..." Điều này và dòng sau làm cho điều này tốt hơn câu trả lời được chấp nhận.
Laurie Stearn

25
  1. Đây là tương đương

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  2. Đây là tương đương

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  3. Đây là tương đương

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

8

Phần có liên quan của bản khởi tạo chuẩn C11 n1570 6.7.9 cho biết:

14 Một mảng kiểu ký tự có thể được khởi tạo bằng một chuỗi ký tự theo nghĩa đen hoặc chuỗi UTF-8, tùy chọn được đặt trong dấu ngoặc nhọn. Các byte kế tiếp của chuỗi ký tự (bao gồm ký tự null kết thúc nếu còn chỗ hoặc nếu mảng có kích thước không xác định) khởi tạo các phần tử của mảng.

21 Nếu có ít bộ khởi tạo trong một danh sách được bao bởi dấu ngoặc nhọn hơn có các phần tử hoặc thành viên của một tổng thể hoặc ít ký tự hơn trong một chuỗi ký tự được sử dụng để khởi tạo một mảng có kích thước đã biết hơn là có các phần tử trong mảng, thì phần còn lại của tổng hợp sẽ được khởi tạo ngầm giống như các đối tượng có thời lượng lưu trữ tĩnh.

Do đó, '\ 0' được thêm vào, nếu có đủ khoảng trống và các ký tự còn lại được khởi tạo với giá trị mà a static char c;sẽ được khởi tạo trong một hàm.

Cuối cùng,

10 Nếu một đối tượng có thời lượng lưu trữ tự động không được khởi tạo rõ ràng, giá trị của nó là không xác định. Nếu một đối tượng có thời lượng lưu trữ tĩnh hoặc chuỗi không được khởi tạo rõ ràng, thì:

[-]

  • nếu nó có kiểu số học, nó được khởi tạo bằng 0 (dương hoặc không dấu);

[-]

Do đó, charlà một kiểu số học, phần còn lại của mảng cũng được đảm bảo khởi tạo bằng số 0.


3

Điều thú vị là có thể khởi tạo mảng theo bất kỳ cách nào vào bất kỳ lúc nào trong chương trình, miễn là chúng là thành viên của a structhoặc union.

Chương trình ví dụ:

#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

Tôi không chắc lắm nhưng tôi thường khởi tạo một mảng thành "" trong trường hợp đó, tôi không cần lo lắng về phần cuối của chuỗi rỗng.

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'
}

Bạn không thực sự nên sử dụng quy tắc int ngầm định. Bạn nên xác định một kiểu cho main()(và bạn cũng nên sử dụng void, tức là int main(void) { ... }. C99 đã thoát khỏi quy tắc này, do đó, mã này sẽ không biên dịch cho C99 và sau đó. Một điều khác cần lưu ý ở đây là bắt đầu với C99, nếu bạn bỏ qua returntrong main, có một hàm tự động return 0;được đặt / ngụ ý trước phần }cuối của main. Bạn đang sử dụng quy tắc int ngầm định chỉ hoạt động trước C99, nhưng bạn đang sử dụng hàm ngầm returnchỉ hoạt động với C99 trở lên ; hai điều này rõ ràng là mâu thuẫn .
RastaJedi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.