Tại sao tôi không cần 3 cấp độ niềng răng để khởi tạo 3 cấp độ của mảng?


8

Tôi đã đi qua ví dụ này

struct sct
{
    int t[2];
};

struct str
{
    sct t[2];
};

int main()
{
    str t[2] = { {0, 2, 4, 6}, {1, 3, 5, 7} }; //Who does this work?

    cout << t[1].t[0].t[1] << t[0].t[1].t[0];     

    return 0;
}

Điều này biên dịch và chạy tốt. Nó cho đầu ra34

Tôi dự kiến ​​cú pháp khởi tạo sẽ là:

str t[2] = {  { {0, 2},{4, 6} }, { {1, 3},{5, 7} }   };

Thay vì

 { {0, 2, 4, 6}, {1, 3, 5, 7} };

Nhưng điều này đã cho:

In function 'int main()':
error: too many initializers for 'str'

Ai đó có thể giải thích tại sao?

Đây là một hình ảnh để minh họa cách tôi nhìn thấy điều này: nhập mô tả hình ảnh ở đây

Tôi nên nghĩ như thế nào khi bắt đầu khởi tạo các cấu trúc lồng nhau?


3
Khi đặt câu hỏi liên quan đến lỗi xây dựng, vui lòng luôn bao gồm các lỗi thực tế bạn gặp phải, dán sao chép dưới dạng văn bản đầy đủ và hoàn chỉnh.
Một số lập trình viên anh chàng

Câu trả lời:


7

Điều này trông giống như một lỗi đánh máy đơn giản nhưng tình hình đủ phức tạp để giải quyết từng bước một.

Đầu tiên hãy để tôi chỉ ra giải pháp có vẻ hiệu quả:

int main()
{
    str t[2] = { { { {0, 2}, {4, 6} } }, { { {1, 3}, {5, 7} } } };
    cout << t[1].t[0].t[1] << t[0].t[1].t[0] << endl;

    return 0;
}

Vì vậy, chúng tôi có một mảng strchứa một mảng sct.

Hãy bắt đầu với cái sau. Bạn khởi tạo một mảng sctvới một cái gì đó như thế này:

sct x[2] = { {0, 1}, {2, 3} };

Bây giờ cho một ví dụ duy nhất của strbạn có thể đi với

str y = { { {0, 2}, {4, 6} } };

Những gì còn lại str t[2]là sắp xếp hai bản sao của strbiểu thức khởi tạo trong dấu ngoặc nhọn:

str t[2] = { { { {0, 2}, {4, 6} } }, { { {1, 3}, {5, 7} } } };

Chỉnh sửa: Trong lần đọc đầu tiên tôi đã hiểu nhầm câu hỏi. Sau khi bài đăng được cập nhật, rõ ràng câu hỏi đặt ra là tại sao có thể loại bỏ hai cặp niềng răng nhưng chỉ cần một cặp kết quả là bị lỗi cú pháp.

Để hiểu cách trình phân tích cú pháp diễn giải mã, bạn có thể muốn nhìn vào cây phân tích cú pháp. Bạn có thể tạo gcc dump cây ở một số giai đoạn của trình phân tích cú pháp với -fdump-tree-...các tùy chọn. Ở đây -fdump-tree-originalcó thể hữu ích.

Để tránh nhầm lẫn thêm, hãy đảm bảo các thành phần của cấu trúc có các tên khác nhau:

struct sct
{
    int a[2];
};

struct str
{
    sct b[2];
};

Đây là đầu ra tôi nhận được với GCC 7.5 từ

>>>> CODE:
str t[2] = { { 0, 2, 4, 6 }, { 1, 3, 5, 7 } };
>>>> tree enabled by -tree-original
struct str t[2] = {{.b={{.a={0, 2}}, {.a={4, 6}}}}, {.b={{.a={1, 3}}, {.a={5, 7}}}}};

Bạn có thể thấy rằng trình biên dịch thêm các dấu ngoặc ẩn xung quanh các biểu thức khởi tạo cho từng cấu trúc và xung quanh các biểu thức khởi tạo cho từng trường được đặt tên.

Bây giờ hãy xem xét biểu thức không biên dịch:

str t[2] = {  { {0, 2},{4, 6} }, { {1, 3},{5, 7} }   };

Cây ở cấp trên biểu thức này sẽ là

/*Step 1: */ struct str t[2] = { {.b={0, 2}, {4, 6} }, {.b={1, 3}, {5, 7} } };

Nhưng vì b là một mảng sct, chúng tôi cố gắng khởi tạo nó bằng {0,2}cách nhận

sct b[2] = {0, 2};

Điều này mở rộng đến

struct sct b[2] = {{.a={0, 2} }};

Đây là C ++ hợp lệ do phần tử đầu tiên của mảng được khởi tạo một cách rõ ràng và phần tử thứ hai được khởi tạo ngầm với các số không.

Với kiến ​​thức này, chúng ta có được cây sau

/*Step 2: */ struct str t[2] = { {.b={{.a={0, 2} }}, {4, 6} }, {.b={{.a={1, 3} }}, {5, 7} } };

Bây giờ chúng tôi còn lại với những điều sau đây:

 struct str z = { { { {0,2} }, { {0,0} } }, {4, 6} };

Và trình biên dịch phàn nàn đúng:

 error: too many initializers for str

Như một kiểm tra cuối cùng xem xét khai báo sau

 struct sxc
 {
     sct b[2];
     int c[2];
 }

 struct sxc z = { {0,2} , {4, 6} };

Điều này biên dịch và kết quả trong cấu trúc sau:

 { .b = { { .a={0,2} }, { .a={0,0} } }, .c={4, 6} }

Ok, nhưng làm thế nào mà bạn được phép liệt kê đơn giản bằng dấu phẩy các giá trị như str t[2] = { {0, 2, 4, 6}, {1, 3, 5, 7} }. Tôi thấy rằng trình biên dịch giả định chúng theo thứ tự. Từ dòng cuối cùng của bạn trả lời, bạn sẽ sửa đổi như thế nào để đến cái này { {0, 2, 4, 6}, {1, 3, 5, 7} }?
Cătălina Sîrbu

Ý tôi là đó sẽ là lý do bạn có thể thoát khỏi một số dấu ngoặc nhọn?
Cătălina Sîrbu

1
Bạn có thể hiểu sai ý định của câu hỏi @Dimitri. Mã này biên dịch và chạy tốt. Tôi nghĩ cô ấy hỏi "không cần một bộ niềng răng ( { }) à?"
miền Bắc

1
@ CătălinaSîrbu Thật vậy tôi nhận ra rằng tôi đã bỏ lỡ ý định của bài viết gốc của bạn, cảm ơn bạn đã làm rõ. Tôi đã cập nhật câu trả lời với nỗ lực tái cấu trúc logic của trình biên dịch.
Dmitri Chubarov

1
@ CătălinaSîrbu Ký hiệu dấu chấm được trình biên dịch sử dụng để chú thích cây phân tích cú pháp. Để làm cho mọi việc dễ dàng hơn để đọc tôi đổi tên sct.tstr.tđể sct.astr.btương ứng. Đó là nơi .a.bđến từ.
Dmitri Chubarov
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.