Khởi tạo toàn bộ mảng 2D với một giá trị


81

Với khai báo sau

int array[ROW][COLUMN]={0};

Tôi nhận được mảng với tất cả các số 0 nhưng với mảng sau

int array[ROW][COLUMN]={1};

Tôi không nhận được mảng có tất cả một giá trị. Giá trị mặc định vẫn là 0.

Tại sao lại có hành vi này và làm cách nào để khởi tạo với tất cả 1?

CHỈNH SỬA: Tôi vừa hiểu rằng việc sử dụng memsetvới giá trị là 1, sẽ đặt mỗi byte là 1 và do đó giá trị thực tế của mỗi ô mảng sẽ không bằng 1 nhưng 16843009. Làm cách nào để đặt nó thành 1?


1
@ckruse: Câu hỏi không phải là Làm thế nào , mà là Tại sao .
masoud

@MM. câu trả lời được đưa ra trong chủ đề tôi đã liên kết.
ckruse

Vấn đề thực sự là why and howcả hai. :)
Kraken

@Kraken Câu hỏi trong bản chỉnh sửa của bạn có lẽ nên được đăng dưới dạng một câu hỏi riêng biệt với câu hỏi này.
Lundin

1
@Kraken Thực ra tôi đã tìm thấy câu hỏi đó ở đây . Tôi khuyên bạn nên làm như được đề xuất trong câu trả lời của mình (tất nhiên!) Và không dựa vào tiện ích mở rộng GCC.
Lundin

Câu trả lời:


123

Bạn nhận được hành vi này, vì int array [ROW][COLUMN] = {1};làm không có nghĩa là "đặt tất cả các mục vào một". Hãy để tôi cố gắng giải thích cách hoạt động của điều này từng bước.

Cách rõ ràng, quá rõ ràng để khởi tạo mảng của bạn sẽ như sau:

#define ROW 2
#define COLUMN 2

int array [ROW][COLUMN] =
{
  {0, 0},
  {0, 0}
};

Tuy nhiên, C cho phép bạn loại bỏ một số mục trong một mảng (hoặc struct / union). Ví dụ, bạn có thể viết:

int array [ROW][COLUMN] =
{
  {1, 2}
};

Điều này có nghĩa là, khởi tạo các phần tử đầu tiên thành 1 và 2, và các phần tử còn lại "như thể chúng có thời lượng lưu trữ tĩnh". Có một quy tắc trong C nói rằng tất cả các đối tượng có thời lượng lưu trữ tĩnh, không được khởi tạo rõ ràng bởi lập trình viên, phải được đặt bằng 0.

Vì vậy, trong ví dụ trên, hàng đầu tiên được đặt thành 1,2 và hàng tiếp theo là 0,0 vì chúng tôi không cung cấp cho chúng bất kỳ giá trị rõ ràng nào.

Tiếp theo, có một quy tắc trong C cho phép kiểu dấu ngoặc nhọn. Ví dụ đầu tiên cũng có thể được viết như

int array [ROW][COLUMN] = {0, 0, 0, 0};

mặc dù tất nhiên đây là văn phong nghèo nàn, khó đọc và khó hiểu hơn. Nhưng quy tắc này rất tiện lợi, vì nó cho phép chúng tôi viết

int array [ROW][COLUMN] = {0};

có nghĩa là: "khởi tạo cột đầu tiên trong hàng đầu tiên thành 0 và tất cả các mục khác như thể chúng có thời lượng lưu trữ tĩnh, tức là đặt chúng thành 0."

do đó, nếu bạn cố gắng

int array [ROW][COLUMN] = {1};

nó có nghĩa là "khởi tạo cột đầu tiên trong hàng đầu tiên thành 1 và đặt tất cả các mục khác thành 0".


2
Cảm ơn vì điều đó, tôi có thể làm bất cứ điều gì để tăng cường toàn bộ mảng bằng 1? xem xét các hàng và cột của tôi có kích thước hàng trăm?
Kraken

1
@Kraken Với các thủ thuật macro. Xem này .
Lundin

Có phải chỉ tôi không hay bạn cần bộ dấu ngoặc thứ hai:int array [ROW][COLUMN] = {{0}};
user1794469

@ user1794469 Không, bạn không.
Lundin

1
@ user1794469 Có, và điều đó là tốt, bởi vì trong hầu hết các trường hợp, bỏ qua niềng răng là hành vi xấu. Nhưng trình biên dịch không để cung cấp cho một chẩn đoán. Về thực hành tốt / xấu cho trường hợp này, hãy xem câu trả lời của tôi cho câu hỏi này .
Lundin

40

Nếu bạn muốn khởi tạo mảng -1thì bạn có thể sử dụng như sau:

memset(array, -1, sizeof(array[0][0]) * row * count)

Nhưng điều này sẽ hoạt động 0-1chỉ


14
Sẽ dễ dàng hơn khi sử dụng "sizeof (array)" thay vì "sizeof (array [0] [0]) * row * count".
Vladyslav Savchenko

Nó hoạt động cho bất kỳ byte liên tục mặc dù nó không rõ ràng với tôi những gì sẽ có ích ngoài 00001111
user1794469

4
cần phải bao gồm <cstring>trong c ++
MTK

Nhưng tại sao điều này chỉ hoạt động cho 0 và -1?
user9989615

12
int array[ROW][COLUMN]={1};

Điều này chỉ khởi tạo phần tử đầu tiên thành 1. Mọi thứ khác đều nhận 0.

Trong trường hợp đầu tiên, bạn đang làm tương tự - khởi tạo phần tử đầu tiên thành 0 và phần tử còn lại mặc định là 0.

Lý do rất đơn giản: đối với một mảng, trình biên dịch sẽ khởi tạo mọi giá trị mà bạn không chỉ định bằng 0.

Với một charmảng, bạn có thể sử dụng memsetđể đặt từng byte, nhưng điều này thường không hoạt động với một intmảng (mặc dù nó tốt cho 0).

Một forvòng lặp chung sẽ thực hiện điều này một cách nhanh chóng:

for (int i = 0; i < ROW; i++)
  for (int j = 0; j < COLUMN; j++)
    array[i][j] = 1;

Hoặc có thể nhanh hơn (tùy thuộc vào trình biên dịch)

for (int i = 0; i < ROW*COLUMN; i++)
  *((int*)a + i) = 1;

1
@Kraken - Nó không - cũng 0chỉ khởi tạo giá trị đầu tiên. Sau đó, nó khởi tạo tất cả phần còn lại 0theo mặc định.
teppic

@EricPostpischil vì vậy, nó đặt tất cả các byte bằng 1, do đó nếu tôi coi là số nguyên 32 bit, thì nếu valuetrường của tôi memsetlà 1 thì giá trị thực trong ma trận sẽ không bằng 1 nhưng 2^0 + 2^8 + 2^16 + 2^24?
Kraken

@Kraken: Về cơ bản, có. memsetđặt mỗi byte trong đích của nó thành giá trị mà nó được đưa ra, điều này sẽ không hoạt động để đặt thành int1. memsetKhông thể được sử dụng để đặt giá trị của các đối tượng nhiều byte trừ khi bạn muốn mỗi byte của đối tượng được đặt thành cùng một giá trị.
Eric Postpischil,

@EricPostpischil Vì vậy, không có cách nào để làm điều đó ngoài việc khởi tạo thủ công từng cái? Xem xét các Hàng và Cột của tôi thậm chí chỉ bằng vài nghìn?
Kraken

@Kraken Tôi đã đăng giải thích tại sao {1} không hoạt động. Và quả thực không có cách nào khác ngoài việc khởi tạo thủ công. Mặc dù vậy, bạn không cần phải gõ hàng nghìn con số, vẫn có những thủ thuật vĩ mô, nhưng đó có lẽ là một chủ đề cho một câu hỏi khác.
Lundin

8

Lưu ý rằng GCC có một phần mở rộng cho ký hiệu bộ khởi tạo được chỉ định rất hữu ích cho ngữ cảnh. Nó cũng được cho phép clangmà không cần bình luận (một phần vì nó cố gắng tương thích với GCC).

Ký hiệu mở rộng cho phép bạn sử dụng ...để chỉ định một loạt các phần tử sẽ được khởi tạo với giá trị sau. Ví dụ:

#include <stdio.h>

enum { ROW = 5, COLUMN = 10 };

int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = 1 } };

int main(void)
{
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COLUMN; j++)
            printf("%2d", array[i][j]);
        putchar('\n');
    }
    return 0;
}

Đầu ra, không có gì đáng ngạc nhiên:

 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1

Lưu ý rằng Fortran 66 (Fortran IV) có số lần lặp lại cho bộ khởi tạo cho mảng; Tôi luôn thấy kỳ lạ rằng C không nhận được chúng khi các bộ khởi tạo được chỉ định được thêm vào ngôn ngữ. Và Pascal sử dụng 0..9ký hiệu để chỉ định phạm vi từ 0 đến 9 bao gồm, nhưng C không sử dụng.. làm mã thông báo, vì vậy không có gì ngạc nhiên khi nó không được sử dụng.

Lưu ý rằng các khoảng trắng xung quanh ...ký hiệu về cơ bản là bắt buộc; nếu chúng được gắn với số, thì số được hiểu là số dấu phẩy động. Ví dụ, 0...9sẽ được tokenized như 0., ., .9, và số dấu chấm động không được phép như subscript mảng. Với các hằng số được đặt tên, ...ROW-1sẽ không gây rắc rối, nhưng tốt hơn là bạn nên có thói quen an toàn.


Addenda:

Tôi lưu ý khi thông qua rằng GCC 7.3.0 từ chối:

int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = { 1 } } };

nơi có thêm một bộ dấu ngoặc nhọn xung quanh bộ khởi tạo vô hướng 1( error: braces around scalar initializer [-Werror]). Tôi không chắc điều đó chính xác vì bạn có thể chỉ định niềng răng xung quanh vô hướng int a = { 1 };, điều này được tiêu chuẩn cho phép một cách rõ ràng. Tôi cũng không chắc là nó không chính xác.

Tôi cũng tự hỏi nếu ký hiệu tốt hơn sẽ là [0]...[9]- rõ ràng, không thể nhầm lẫn với bất kỳ cú pháp hợp lệ nào khác và tránh nhầm lẫn với số dấu phẩy động.

int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };

Có thể ủy ban tiêu chuẩn sẽ xem xét điều đó?


5

Để khởi tạo mảng 2d bằng 0, hãy sử dụng phương pháp dưới đây: int arr[n][m] = {};

LƯU Ý : Phương thức trên sẽ chỉ hoạt động để khởi tạo với 0;


3

Sử dụng mảng vectơ thay thế:

vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));

3
Có thể, nhưng OP chưa đề cập đến C ++.
Sangeet

0
char grid[row][col];
memset(grid, ' ', sizeof(grid));

Đó là để khởi tạo các phần tử mảng char thành các ký tự khoảng trắng.

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.