Khởi tạo tất cả các phần tử của một mảng thành một giá trị mặc định trong C ++?


248

Ghi chú C ++: Khởi tạo mảng có một danh sách đẹp về khởi tạo mảng. tôi có một

int array[100] = {-1};

hy vọng nó sẽ đầy với -1 nhưng không, chỉ có giá trị đầu tiên và phần còn lại là 0 với các giá trị ngẫu nhiên.

Mật mã

int array[100] = {0};

chỉ hoạt động tốt và đặt từng phần tử thành 0.

Tôi đang thiếu gì ở đây .. Không ai có thể khởi tạo nó nếu giá trị bằng 0?

Và 2: Việc khởi tạo mặc định (như trên) có nhanh hơn vòng lặp thông thường trong toàn bộ mảng và gán một giá trị hay nó có làm điều tương tự không?


1
Hành vi trong C và C ++ là khác nhau. Trong C {0} là trường hợp đặc biệt cho trình khởi tạo cấu trúc, tuy nhiên AFAIK không dành cho mảng. int mảng [100] = {0} phải giống như mảng [100] = {[0] = 0}, vì hiệu ứng phụ sẽ bằng không tất cả các yếu tố khác. Trình biên dịch AC KHÔNG nên hoạt động như bạn mô tả ở trên, thay vào đó int int [100] = {- 1} nên đặt phần tử đầu tiên thành -1 và phần còn lại thành 0 (không có nhiễu). Trong C nếu bạn có mảng struct x [100], sử dụng = {0} làm công cụ khởi tạo là KHÔNG hợp lệ. Bạn có thể sử dụng {{0}} sẽ khởi tạo phần tử đầu tiên và không cho tất cả các phần tử khác, trong hầu hết các trường hợp sẽ là điều tương tự.
Fredrik Widlund

1
@FredrikWidlund Nó giống nhau ở cả hai ngôn ngữ. {0}không phải là trường hợp đặc biệt cho cấu trúc cũng như mảng. Quy tắc là các phần tử không có trình khởi tạo được khởi tạo như thể chúng có 0cho trình khởi tạo. Nếu có các tập hợp lồng nhau (ví dụ struct x array[100]) thì bộ khởi tạo được áp dụng cho các tập hợp không theo thứ tự "hàng chính"; niềng răng tùy ý có thể được bỏ qua làm điều này. struct x array[100] = { 0 }có giá trị bằng C; và hợp lệ trong C ++ miễn là thành viên đầu tiên struct Xchấp nhận 0làm trình khởi tạo.
MM

1
{ 0 }không đặc biệt ở C, nhưng việc xác định kiểu dữ liệu không thể khởi tạo với nó khó hơn nhiều vì không có hàm tạo và do đó không có cách nào để không 0bị chuyển đổi và gán cho một thứ gì đó .
Leushenko

3
Được bình chọn để mở lại vì câu hỏi khác là về C. Có nhiều cách C ++ để khởi tạo một mảng không hợp lệ trong C.
xskxzr

1
Cũng được bình chọn để mở lại - C và C ++ là các ngôn ngữ khác nhau
Pete

Câu trả lời:


350

Sử dụng cú pháp mà bạn đã sử dụng,

int array[100] = {-1};

nói "đặt phần tử đầu tiên thành -1và phần còn lại thành 0" vì tất cả các phần tử bị bỏ qua được đặt thành 0.

Trong C ++, để đặt tất cả chúng thành -1, bạn có thể sử dụng cái gì đó như std::fill_n(từ <algorithm>):

std::fill_n(array, 100, -1);

Trong C di động, bạn phải cuộn vòng lặp của riêng bạn. Có các phần mở rộng trình biên dịch hoặc bạn có thể phụ thuộc vào hành vi được xác định thực hiện như một lối tắt nếu điều đó được chấp nhận.


14
Điều đó cũng trả lời một câu hỏi gián tiếp về cách điền vào mảng với các giá trị mặc định "một cách dễ dàng". Cảm ơn bạn.
Milan

7
@chessofnerd: không chính xác, #include <algorithm> là tiêu đề đúng, <vector>có thể hoặc không bao gồm nó một cách gián tiếp, điều đó phụ thuộc vào việc triển khai của bạn.
Evan Teran

2
Bạn không phải dùng đến việc khởi tạo mảng trong thời gian chạy. Nếu bạn thực sự cần khởi tạo để xảy ra một cách tĩnh, có thể sử dụng các mẫu và các chuỗi biến đổi để tạo ra chuỗi ints mong muốn và mở rộng nó thành trình khởi tạo của mảng.
void-con trỏ

2
@ontherocks, không có cách chính xác nào để sử dụng một lệnh gọi fill_nđể điền vào toàn bộ mảng 2D. Bạn cần lặp qua một chiều, trong khi điền vào chiều khác.
Evan Teran

7
Đây là một câu trả lời cho một số câu hỏi khác. std::fill_nkhông phải là khởi tạo.
Ben Voigt

133

Có một phần mở rộng cho trình biên dịch gcc cho phép cú pháp:

int array[100] = { [0 ... 99] = -1 };

Điều này sẽ đặt tất cả các yếu tố thành -1.

Điều này được gọi là "Khởi tạo được chỉ định" xem tại đây để biết thêm thông tin.

Lưu ý điều này không được thực hiện cho trình biên dịch gcc c ++.


2
Tuyệt vời. Cú pháp này dường như cũng hoạt động trong tiếng kêu (vì vậy có thể được sử dụng trên iOS / Mac OS X).
JosephH

31

Trang bạn đã liên kết đến đã đưa ra câu trả lời cho phần đầu tiên:

Nếu kích thước mảng rõ ràng được chỉ định, nhưng danh sách khởi tạo ngắn hơn được chỉ định, các phần tử không xác định được đặt thành không.

Không có cách tích hợp nào để khởi tạo toàn bộ mảng thành một số giá trị khác không.

Đối với cái nào nhanh hơn, quy tắc thông thường được áp dụng: "Phương pháp mang lại cho trình biên dịch sự tự do nhất có lẽ là nhanh hơn".

int array[100] = {0};

chỉ cần nói với trình biên dịch "đặt 100 ints này thành 0", trình biên dịch có thể tối ưu hóa tự do.

for (int i = 0; i < 100; ++i){
  array[i] = 0;
}

cụ thể hơn rất nhiều. Nó báo cho trình biên dịch tạo một biến lặp i, nó báo cho nó thứ tự các phần tử sẽ được khởi tạo, v.v. Tất nhiên, trình biên dịch có khả năng tối ưu hóa điều đó, nhưng vấn đề là ở đây bạn đang xác định quá mức vấn đề, buộc trình biên dịch phải làm việc chăm chỉ hơn để có được kết quả tương tự.

Cuối cùng, nếu bạn muốn đặt mảng thành giá trị khác không, ít nhất bạn nên (trong C ++, ít nhất) sử dụng std::fill:

std::fill(array, array+100, 42); // sets every value in the array to 42

Một lần nữa, bạn có thể làm tương tự với một mảng, nhưng điều này ngắn gọn hơn và giúp trình biên dịch tự do hơn. Bạn chỉ nói rằng bạn muốn toàn bộ mảng chứa đầy giá trị 42. Bạn không nói bất cứ điều gì về thứ tự nên được thực hiện, hoặc bất cứ điều gì khác.


5
Câu trả lời tốt. Lưu ý rằng trong C ++ (không phải trong C), bạn có thể thực hiện int int [100] = {}; và cung cấp cho trình biên dịch sự tự do nhất :)
Johannes Schaub - litb

1
đồng ý, trả lời xuất sắc. Nhưng đối với một mảng có kích thước cố định, nó sẽ sử dụng std :: fill_n :-P.
Evan Teran

12

C ++ 11 có một tùy chọn (không hoàn hảo) khác:

std::array<int, 100> a;
a.fill(-1);

hoặcstd::fill(begin(a), end(a), -1)
Doctorlai

9

Với {} bạn chỉ định các phần tử khi chúng được khai báo; phần còn lại được khởi tạo bằng 0.

Nếu không có = {}initalize, nội dung không được xác định.


8

Trang bạn liên kết trạng thái

Nếu kích thước mảng rõ ràng được chỉ định, nhưng danh sách khởi tạo ngắn hơn được chỉ định, các phần tử không xác định được đặt thành không.

Vấn đề tốc độ: Bất kỳ sự khác biệt sẽ không đáng kể cho mảng nhỏ này. Nếu bạn làm việc với các mảng lớn và tốc độ quan trọng hơn nhiều so với kích thước, bạn có thể có một mảng const của các giá trị mặc định (được khởi tạo tại thời gian biên dịch) và sau đó memcpychúng đến mảng có thể sửa đổi.


2
memcpy không phải là một ý tưởng hay, vì điều đó sẽ tương đương với việc chỉ đặt các giá trị trực tiếp tăng tốc một cách khôn ngoan.
Evan Teran

1
Tôi không thấy sự cần thiết của bản sao và mảng const: Tại sao không tạo mảng có thể sửa đổi ở vị trí đầu tiên với các giá trị được điền sẵn?
Julian Schaub - litb

Cảm ơn đã giải thích về tốc độ và cách thực hiện nếu tốc độ là vấn đề với kích thước mảng lớn (trong trường hợp của tôi)
Milan

Danh sách khởi tạo được thực hiện tại thời gian biên dịch và được tải khi chạy. Không cần phải đi sao chép những thứ xung quanh.
Martin York

@litb, @Evan: Ví dụ gcc tạo khởi tạo động (rất nhiều Mov) ngay cả khi tối ưu hóa được bật. Đối với mảng lớn và yêu cầu hiệu năng chặt chẽ, bạn muốn thực hiện init tại thời gian biên dịch. memcpy có lẽ được tối ưu hóa tốt hơn cho các bản sao lớn hơn rất nhiều Mov đơn thuần.
laalto

4

Một cách khác để khởi tạo mảng thành một giá trị chung, sẽ thực sự tạo ra danh sách các phần tử trong một chuỗi các định nghĩa:

#define DUP1( X ) ( X )
#define DUP2( X ) DUP1( X ), ( X )
#define DUP3( X ) DUP2( X ), ( X )
#define DUP4( X ) DUP3( X ), ( X )
#define DUP5( X ) DUP4( X ), ( X )
.
.
#define DUP100( X ) DUP99( X ), ( X )

#define DUPx( X, N ) DUP##N( X )
#define DUP( X, N ) DUPx( X, N )

Khởi tạo một mảng thành một giá trị chung có thể dễ dàng được thực hiện:

#define LIST_MAX 6
static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) };

Lưu ý: DUPx được giới thiệu để cho phép thay thế macro trong các tham số cho DUP


3

Đối với trường hợp một mảng các phần tử byte đơn, bạn có thể sử dụng bộ nhớ để đặt tất cả các phần tử thành cùng một giá trị.

Có một ví dụ ở đây .


3

Sử dụng std::array, chúng ta có thể làm điều này theo cách khá đơn giản trong C ++ 14. Chỉ có thể thực hiện trong C ++ 11, nhưng phức tạp hơn một chút.

Giao diện của chúng tôi là kích thước thời gian biên dịch và giá trị mặc định.

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}


template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}

Chức năng thứ ba chủ yếu là để thuận tiện, vì vậy người dùng không phải xây dựng std::integral_constant<std::size_t, size> , vì đó là một công trình khá dài. Công việc thực sự được thực hiện bởi một trong hai chức năng đầu tiên.

Quá tải đầu tiên khá đơn giản: Nó xây dựng một std::arraykích thước 0. Không cần sao chép, chúng tôi chỉ xây dựng nó.

Quá tải thứ hai là một chút phức tạp hơn. Nó chuyển tiếp theo giá trị mà nó nhận được dưới dạng nguồn và nó cũng xây dựng một thể hiện make_index_sequencevà chỉ gọi một số hàm thực hiện khác. Chức năng đó trông như thế nào?

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

Điều này xây dựng kích thước đầu tiên - 1 đối số bằng cách sao chép giá trị chúng tôi đã truyền vào. Ở đây, chúng tôi sử dụng các chỉ mục gói tham số matrixdic của chúng tôi giống như một cái gì đó để mở rộng. Có kích thước - 1 mục trong gói đó (như chúng tôi đã chỉ định khi xây dựng make_index_sequence) và chúng có các giá trị 0, 1, 2, 3, ..., kích thước - 2. Tuy nhiên, chúng tôi không quan tâm đến các giá trị ( vì vậy chúng tôi bỏ nó vào chỗ trống, để tắt bất kỳ cảnh báo nào của trình biên dịch). Mở rộng gói tham số mở rộng mã của chúng tôi thành một cái gì đó như thế này (giả sử kích thước == 4):

return std::array<std::decay_t<T>, 4>{ (static_cast<void>(0), value), (static_cast<void>(1), value), (static_cast<void>(2), value), std::forward<T>(value) };

Chúng tôi sử dụng các dấu ngoặc đơn này để đảm bảo rằng việc mở rộng gói biến đổi mở ...rộng những gì chúng tôi muốn và cũng để đảm bảo chúng tôi đang sử dụng toán tử dấu phẩy. Nếu không có dấu ngoặc đơn, có vẻ như chúng ta đang chuyển một loạt các đối số cho việc khởi tạo mảng của mình, nhưng thực sự, chúng ta đang đánh giá chỉ mục, bỏ nó thành void, bỏ qua kết quả void đó và sau đó trả về giá trị, được sao chép vào mảng .

Đối số cuối cùng, đối số chúng ta gọi std::forwardlà một tối ưu hóa nhỏ. Nếu ai đó chuyển qua chuỗi std :: tạm thời và nói "tạo một mảng gồm 5 trong số này", chúng tôi muốn có 4 bản sao và 1 di chuyển, thay vì 5 bản sao. Việc std::forwardđảm bảo rằng chúng tôi làm điều này.

Mã đầy đủ, bao gồm các tiêu đề và một số bài kiểm tra đơn vị:

#include <array>
#include <type_traits>
#include <utility>

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}

template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}



struct non_copyable {
    constexpr non_copyable() = default;
    constexpr non_copyable(non_copyable const &) = delete;
    constexpr non_copyable(non_copyable &&) = default;
};

int main() {
    constexpr auto array_n = make_array_n<6>(5);
    static_assert(std::is_same<std::decay_t<decltype(array_n)>::value_type, int>::value, "Incorrect type from make_array_n.");
    static_assert(array_n.size() == 6, "Incorrect size from make_array_n.");
    static_assert(array_n[3] == 5, "Incorrect values from make_array_n.");

    constexpr auto array_non_copyable = make_array_n<1>(non_copyable{});
    static_assert(array_non_copyable.size() == 1, "Incorrect array size of 1 for move-only types.");

    constexpr auto array_empty = make_array_n<0>(2);
    static_assert(array_empty.empty(), "Incorrect array size for empty array.");

    constexpr auto array_non_copyable_empty = make_array_n<0>(non_copyable{});
    static_assert(array_non_copyable_empty.empty(), "Incorrect array size for empty array of move-only.");
}

non_copyableLoại của bạn thực sự có thể sao chép bằng phương tiện operator=.
Hertz

Tôi cho rằng non_copy_constructiblesẽ là một tên chính xác hơn cho đối tượng. Tuy nhiên, không có sự phân công ở bất cứ đâu trong mã này, vì vậy nó không quan trọng đối với ví dụ này.
David Stone

1

1) Khi bạn sử dụng một trình khởi tạo, đối với một cấu trúc hoặc một mảng như thế, các giá trị không xác định về cơ bản được xây dựng mặc định. Trong trường hợp của một kiểu nguyên thủy như ints, điều đó có nghĩa là chúng sẽ bằng không. Lưu ý rằng điều này áp dụng đệ quy: bạn có thể có một mảng các cấu trúc chứa các mảng và nếu bạn chỉ định trường đầu tiên của cấu trúc đầu tiên, thì tất cả phần còn lại sẽ được khởi tạo với các số 0 và các hàm tạo mặc định.

2) Trình biên dịch có thể sẽ tạo mã khởi tạo ít nhất là tốt như bạn có thể làm bằng tay. Tôi có xu hướng thích để trình biên dịch thực hiện việc khởi tạo cho tôi, khi có thể.


1) Khởi tạo mặc định của POD không xảy ra ở đây. Sử dụng danh sách, trình biên dịch sẽ tạo ra các giá trị tại thời gian biên dịch và đặt chúng vào một phần đặc biệt của tập hợp vừa được tải như một phần của khởi tạo chương trình (như mã). Vì vậy, chi phí bằng không khi chạy.
Martin York

1
Tôi không thấy anh ấy sai ở đâu? int a [100] = {} chắc chắn được khởi tạo cho tất cả 0, không quan tâm đến nơi nó xuất hiện và struct {int a; } b [100] = {}; cũng vậy "về cơ bản mặc định được xây dựng" => "giá trị được xây dựng", tho. Nhưng điều này không quan trọng trong trường hợp ints, PODS hoặc các loại với người dùng khai báo. Nó chỉ quan trọng đối với NON-Pod mà không có người dùng khai báo, theo những gì tôi biết. Nhưng tôi sẽ không bỏ phiếu (!) Vì điều này. dù sao đi nữa, +1 để bạn biến nó thành 0 lần nữa :)
Johannes Schaub - litb

@Evan: Tôi đã đủ điều kiện tuyên bố của mình với "Khi bạn sử dụng trình khởi tạo ..." Tôi không đề cập đến các giá trị chưa được khởi tạo. @Martin: Điều đó có thể hoạt động đối với dữ liệu không đổi, tĩnh hoặc toàn cầu. Nhưng tôi không thấy nó sẽ hoạt động như thế nào với một cái gì đó như: int test () {int i [10] = {0}; int v = i [0]; i [0] = 5; trả lại v; } Trình biên dịch tốt hơn nên khởi tạo i [] thành số không mỗi khi bạn gọi test ().
Boojum

nó có thể đặt dữ liệu vào phân đoạn dữ liệu tĩnh và làm cho "i" tham chiếu đến nó :)
Johannes Schaub - litb

Đúng - về mặt kỹ thuật, trong trường hợp này, nó cũng có thể hoàn toàn bỏ qua "i" và chỉ trả về 0. Nhưng sử dụng phân đoạn dữ liệu tĩnh cho dữ liệu có thể thay đổi sẽ nguy hiểm trong môi trường đa luồng. Điểm mà tôi đang cố gắng đưa ra để trả lời Martin chỉ đơn giản là bạn không thể loại bỏ hoàn toàn chi phí khởi tạo. Chắc chắn, sao chép một đoạn được tạo sẵn từ phân đoạn dữ liệu tĩnh, nhưng nó vẫn không miễn phí.
Boojum


0

Trong ngôn ngữ lập trình C ++ V4, Stroustrup khuyên bạn nên sử dụng các vectơ hoặc giá trị trên các mảng dựng sẵn. Với valarrary's, khi bạn tạo chúng, bạn có thể khởi tạo chúng thành một giá trị cụ thể như:

valarray <int>seven7s=(7777777,7);

Để khởi tạo một mảng dài 7 thành viên với "7777777".

Đây là một cách C ++ để thực hiện câu trả lời bằng cách sử dụng cấu trúc dữ liệu C ++ thay vì mảng "C cũ đơn giản".

Tôi đã chuyển sang sử dụng valarray như một nỗ lực trong mã của mình để cố gắng sử dụng C ++ 'isms v. C'ism ....


Đây là ví dụ tồi tệ thứ hai về cách sử dụng loại mà tôi từng thấy ...
Steazy

-3

Nên là một tính năng tiêu chuẩn nhưng vì một số lý do, nó không được bao gồm trong tiêu chuẩn C hay C ++ ...

#include <stdio.h>

 __asm__
 (
"    .global _arr;      "
"    .section .data;    "
"_arr: .fill 100, 1, 2; "
 );

extern char arr[];

int main() 
{
    int i;

    for(i = 0; i < 100; ++i) {
        printf("arr[%u] = %u.\n", i, arr[i]);
    }
}

Ở Fortran bạn có thể làm:

program main
    implicit none

    byte a(100)
    data a /100*2/
    integer i

    do i = 0, 100
        print *, a(i)
    end do
end

nhưng nó không có số không dấu ...

Tại sao C / C ++ không thể thực hiện nó. Có thực sự khó khăn như vậy? Thật ngớ ngẩn khi phải viết thủ công để đạt được kết quả tương tự ...

#include <stdio.h>
#include <stdint.h>

/* did I count it correctly? I'm not quite sure. */
uint8_t arr = {
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};    

int main() 
{
    int i;

    for(i = 0; i < 100; ++i) {
        printf("arr[%u] = %u.\n", i, arr[i]);
    }
}

Điều gì nếu nó là một mảng 1.000,00 byte? Tôi cần phải viết một kịch bản để viết nó cho tôi, hoặc dùng đến các bản hack với lắp ráp / v.v. Thật vô nghĩa.

Nó hoàn toàn di động, không có lý do gì để nó không có trong ngôn ngữ.

Chỉ cần hack nó như:

#include <stdio.h>
#include <stdint.h>

/* a byte array of 100 twos declared at compile time. */
uint8_t twos[] = {100:2};

int main()
{
    uint_fast32_t i;
    for (i = 0; i < 100; ++i) {
        printf("twos[%u] = %u.\n", i, twos[i]);
    }

    return 0;
}

Một cách để hack nó là thông qua tiền xử lý ... (Mã bên dưới không bao gồm các trường hợp cạnh, nhưng được viết để nhanh chóng chứng minh những gì có thể được thực hiện.)

#!/usr/bin/perl
use warnings;
use strict;

open my $inf, "<main.c";
open my $ouf, ">out.c";

my @lines = <$inf>;

foreach my $line (@lines) {
    if ($line =~ m/({(\d+):(\d+)})/) {
        printf ("$1, $2, $3");        
        my $lnew = "{" . "$3, "x($2 - 1) . $3 . "}";
        $line =~ s/{(\d+:\d+)}/$lnew/;
        printf $ouf $line;
    } else {
        printf $ouf $line;
    }
}

close($ouf);
close($inf);

bạn đang in trong một vòng lặp, tại sao bạn không thể chỉ định trong một vòng lặp?
Abhinav Gauniyal

1
gán bên trong một vòng lặp phát sinh chi phí thời gian chạy; trong khi mã hóa bộ đệm là miễn phí vì bộ đệm đã được nhúng vào nhị phân, do đó, nó không lãng phí thời gian để xây dựng mảng từ đầu mỗi khi chương trình chạy. Mặc dù vậy, bạn đúng rằng việc in trong một vòng lặp không phải là một ý tưởng hay, tốt hơn là nên nối vào bên trong vòng lặp và sau đó in một lần, vì mỗi lệnh gọi printf yêu cầu một cuộc gọi hệ thống, trong khi đó việc ghép chuỗi bằng heap / stack của ứng dụng thì không. Vì kích thước trong loại chương trình này là không phát hành, tốt nhất nên xây dựng mảng này vào thời gian biên dịch, không phải thời gian chạy.
Dmitry

"gán bên trong một vòng lặp phát sinh chi phí thời gian chạy" - Bạn thực sự đánh giá thấp trình tối ưu hóa.
Asu

Tùy thuộc vào kích thước của mảng, gcc và clang sẽ "mã hóa cứng" hoặc đánh lừa giá trị trong và với các mảng lớn hơn, chỉ trực tiếp với memsetnó, ngay cả với mảng "mã hóa cứng".
Asu
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.