Làm thế nào để khởi tạo tất cả các thành viên của một mảng thành cùng một giá trị?


968

Tôi có một mảng lớn trong C (không phải C ++ nếu điều đó tạo ra sự khác biệt). Tôi muốn khởi tạo tất cả các thành viên có cùng giá trị.

Tôi có thể thề rằng tôi đã từng biết một cách đơn giản để làm điều này. Tôi có thể sử dụng memset()trong trường hợp của mình, nhưng không có cách nào để làm điều này được tích hợp ngay trong cú pháp C?


16
Không có câu trả lời nào cho đến nay đề cập đến ký hiệu khởi tạo được chỉ định là khả thi với C99 trở lên. Ví dụ: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. Nếu bạn loại bỏ dấu chấm lửng , các đoạn đó sẽ biên dịch theo C99 hoặc C11.
Jonathan Leffler

Trên thực tế, câu trả lời của abelenky đang sử dụng trình khởi tạo được chỉ định, nhưng không được hình thành mã khởi tạo hoàn chỉnh
Rob11311

memset () có thể giúp đỡ, nhưng phụ thuộc vào giá trị.
Nick

2
memset()thảo luận cụ thể: stackoverflow.com/questions/7202411/ Từ Tôi nghĩ rằng nó chỉ hoạt động với 0.
Ciro Santilli 冠状 病毒 审查 六四 事件

Câu trả lời:


1239

Trừ khi giá trị đó là 0 (trong trường hợp đó bạn có thể bỏ qua một phần của trình khởi tạo và các phần tử tương ứng sẽ được khởi tạo thành 0), không có cách nào dễ dàng.

Đừng bỏ qua giải pháp rõ ràng:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Các phần tử có giá trị bị thiếu sẽ được khởi tạo thành 0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

Vì vậy, điều này sẽ khởi tạo tất cả các yếu tố thành 0:

int myArray[10] = { 0 }; // all elements 0

Trong C ++, một danh sách khởi tạo trống cũng sẽ khởi tạo mọi phần tử thành 0. Điều này không được phép với C:

int myArray[10] = {}; // all elements 0 in C++

Hãy nhớ rằng các đối tượng có thời lượng lưu trữ tĩnh sẽ khởi tạo thành 0 nếu không có trình khởi tạo nào được chỉ định:

static int myArray[10]; // all elements 0

Và "0" không nhất thiết có nghĩa là "all-bits-zero", vì vậy sử dụng cách trên là tốt hơn và dễ mang theo hơn bộ nhớ (). (Giá trị điểm nổi sẽ được khởi tạo thành +0, con trỏ thành giá trị null, v.v.)


27
Đọc qua tiêu chuẩn C ++, bạn cũng có thể thực hiện int int [10] = {}; đến không khởi tạo. Tôi cũng không có tiêu chuẩn C để kiểm tra xem đây có phải là C hợp lệ không.
workmad3

54
Nhìn vào phần 6.7.8 Khởi tạo chuẩn C99, có vẻ như không cho phép một danh sách khởi tạo trống.
Jonathan Leffler

7
C99 có rất nhiều tính năng hay cho khởi tạo cấu trúc và mảng; một tính năng mà nó không có (nhưng Fortran IV, 1966, đã có) là một cách để lặp lại một trình khởi tạo cụ thể cho một mảng.
Jonathan Leffler

8
@CetinSert: Ý bạn là nó không hoạt động? Nó làm chính xác những gì câu trả lời này nói nó nên làm. Nó không làm những gì nhận xét trong mã của bạn nói, nhưng nhận xét đó là sai.
Benjamin Lindley

9
@CetinSert: Bạn là người duy nhất đã tuyên bố, trong nhận xét đó, tất cả các yếu tố sẽ được đặt thành -1. Câu trả lời này, đúng, rằng tất cả các yếu tố không xác định được đặt thành không. Kết quả mã của bạn phù hợp với yêu cầu này.
Benjamin Lindley

394

Nếu trình biên dịch của bạn là GCC, bạn có thể sử dụng cú pháp sau:

int array[1024] = {[0 ... 1023] = 5};

Kiểm tra mô tả chi tiết: http://gcc.gnu.org/onlinesocs/gcc-4.1.2/gcc/Designated-Inits.html


12
Và cú pháp đó gây ra sự gia tăng lớn trong kích thước tệp của các tệp nhị phân được biên dịch. Với N = 65536 (thay vì 1024), nhị phân của tôi tăng từ 15 KB lên 270 KB !!
Cetin Sert

50
Trình biên dịch @CetinSert phải thêm 65536 intgiây vào dữ liệu tĩnh, là 256 K - chính xác là tăng kích thước bạn đã quan sát.
qrdl

15
@CetinSert Tại sao tôi nên? Nó là một hành vi biên dịch chuẩn, không cụ thể cho các trình khởi tạo được chỉ định. Nếu bạn khởi tạo tĩnh 65536 intgiây, giống như int foo1 = 1, foo2 = 1, ..., foo65536 =1;bạn sẽ tăng kích thước tương tự.
qrdl

27
tốt hơn nữa: "int mảng [] = {[0 ... 1023] = 5}", kích thước của mảng sẽ tự động được đặt thành 1024, dễ dàng hơn và an toàn hơn để sửa đổi.
Francois

4
@Francois hoặc cho mảng 2d bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}, mặc dù tôi không chắc rằng nó dễ đọc hơn dạng đầy đủ.
g33kz0r

178

Để khởi tạo tĩnh một mảng lớn có cùng giá trị, không có nhiều bản sao-dán, bạn có thể sử dụng macro:

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };

Nếu bạn cần thay đổi giá trị, bạn phải thay thế tại một nơi duy nhất.

Chỉnh sửa: các tiện ích mở rộng hữu ích có thể

(lịch sự của Jonathan Leffler )

Bạn có thể dễ dàng khái quát hóa điều này với:

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */

Một biến thể có thể được tạo bằng cách sử dụng:

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 

mà làm việc với các cấu trúc hoặc mảng ghép.

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };

tên vĩ mô có thể thương lượng.


12
Tôi sẽ chỉ xem xét điều này trong các trường hợp cực đoan, chắc chắn một bộ nhớ là cách thanh lịch hơn để thể hiện nó.
u0b34a0f6ae

47
Nếu dữ liệu phải có khả năng ROM, bộ nhớ không thể được sử dụng.
Hợp đồng của giáo sư Falken vi phạm

9
Bộ tiền xử lý sẽ thực sự tạo mã từ #defines. Với kích thước mảng lớn hơn, kích thước thực thi sẽ tăng lên. Nhưng chắc chắn + cho ý tưởng;)
Leonid

7
@Alcott, trên các máy tính cũ và vẫn còn trên nhiều hệ thống nhúng, mã cuối cùng được đặt trong EPROM hoặc ROM . Khả năng ROM cũng có nghĩa là, trong các hệ thống nhúng, "code put in flash", bởi vì nó có cùng ý nghĩa, cụ thể là bộ nhớ không thể được ghi thời gian chạy. Tức là bộ nhớ hoặc bất kỳ hướng dẫn nào khác để cập nhật hoặc thay đổi bộ nhớ không thể được sử dụng. Các hằng số, mặc dù, có thể được thể hiện và flash hoặc ROM-ed trước khi chương trình bắt đầu.
Hợp đồng của giáo sư Falken vi phạm

4
@ u0b34a0f6ae: Hãy nhớ rằng bạn cũng có thể sử dụng phương pháp này nếu VAL_1Xkhông phải là một số nguyên duy nhất mà là một danh sách. Giống như các trạng thái Amigable, đây cũng là cách dành cho các hệ thống nhúng mà bạn muốn xác định các giá trị init của bộ nhớ EEPROM hoặc Flash. Trong cả hai trường hợp, bạn không thể sử dụng memset().
Martin Scharrer

63

Nếu bạn muốn đảm bảo rằng mọi thành viên của mảng được khởi tạo rõ ràng, chỉ cần bỏ qua thứ nguyên từ khai báo:

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Trình biên dịch sẽ suy ra kích thước từ danh sách khởi tạo. Thật không may, đối với các mảng nhiều chiều, chỉ có thể bỏ qua kích thước ngoài cùng:

int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

không sao, nhưng

int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

không phải.


điều này có đúng không int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV

10
Không. Bạn đang bỏ qua kích thước trong cùng, không được phép. Điều này sẽ đưa ra một lỗi biên dịch.
Frank Szczerba

4
Cả khởi tạo và suy luận chiều dài đã được giới thiệu trong C99.
Palec

3
@Palec: Suy luận không có độ dài đã có trong C kể từ thời C chuẩn trước (kể từ khi K & R 1st Edition được xuất bản, và có lẽ một thời gian trước đó). Công cụ khởi tạo được chỉ định là mới trong C99, nhưng điều này không sử dụng công cụ khởi tạo được chỉ định.
Jonathan Leffler

53

Tôi thấy một số mã sử dụng cú pháp này:

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   

Nơi nó trở nên đặc biệt hữu ích là nếu bạn tạo một mảng sử dụng enums làm chỉ mục:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   

Điều này giữ mọi thứ theo thứ tự, ngay cả khi bạn tình cờ viết một số giá trị enum ngoài trật tự.

Thông tin thêm về kỹ thuật này có thể được tìm thấy ở đâyở đây .


8
Đây là cú pháp khởi tạo C99, đã được bao phủ bởi một số câu trả lời khác. Bạn có thể đưa ra tuyên bố một cách hữu ích char const *array[] = { ... };hoặc thậm chí char const * const array[] = { ... };, phải không?
Jonathan Leffler

22
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Tôi nghĩ rằng điều này là tốt hơn

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...

kích thước của các thay đổi mảng.


12
Đối với hồ sơ, về cơ bản đó chỉ là một phiên bản chậm hơn, dài dòng hơn củamemset(myArray, VALUE, ARRAY_SIZE);
Benson

18
Làm thế nào bạn sẽ sử dụng bộ nhớ để khởi tạo một mảng int thành một giá trị lớn hơn 255? memset chỉ hoạt động nếu mảng có kích thước byte.
Matt

21
@Benson: Bạn không thể thay thế đoạn mã trên bằng bộ nhớ trên các nền tảng trong đó sizeof (int)> sizeof (char). Thử nó.
ChrisWue

13

Bạn có thể thực hiện toàn bộ điều khởi tạo tĩnh như chi tiết ở trên, nhưng nó có thể là một người lập dị thực sự khi kích thước mảng của bạn thay đổi (khi mảng của bạn khởi động, nếu bạn không thêm trình khởi tạo bổ sung thích hợp, bạn sẽ nhận được rác).

memset cung cấp cho bạn một lần truy cập thời gian chạy để thực hiện công việc, nhưng không có kích thước mã nào được thực hiện đúng là miễn dịch với thay đổi kích thước mảng. Tôi sẽ sử dụng giải pháp này trong gần như tất cả các trường hợp khi mảng lớn hơn, giả sử, vài chục phần tử.

Nếu điều thực sự quan trọng là mảng được khai báo tĩnh, tôi sẽ viết chương trình viết chương trình cho tôi và biến nó thành một phần của quá trình xây dựng.


Bạn có thể vui lòng thêm một số ví dụ về việc sử dụng memsetđể khởi tạo mảng không?
Sopalajo de Arrierez

8

Đây là một cách khác:

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};

Xem:

Phần mở rộng C

Chỉ định inits

Sau đó đặt câu hỏi: Khi nào người ta có thể sử dụng tiện ích mở rộng C?

Mẫu mã ở trên nằm trong một hệ thống nhúng và sẽ không bao giờ nhìn thấy ánh sáng từ trình biên dịch khác.


6

Để khởi tạo các kiểu dữ liệu 'bình thường' (như mảng int), bạn có thể sử dụng ký hiệu dấu ngoặc, nhưng nó sẽ bằng 0 các giá trị sau lần cuối nếu vẫn còn khoảng trống trong mảng:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};

5

Nếu mảng xảy ra là int hoặc bất cứ thứ gì có kích thước int hoặc kích thước mô hình mem của bạn khớp với thời gian chính xác vào một int (tức là tất cả các số 0 hoặc 0xA5A5A5A5), cách tốt nhất là sử dụng memset () .

Nếu không, hãy gọi memcpy () trong một vòng lặp di chuyển chỉ mục.


5

Một câu trả lời hơi khóe miệng; viết tuyên bố

array = initial_value

trong ngôn ngữ có khả năng mảng yêu thích của bạn (của tôi là Fortran, nhưng có nhiều ngôn ngữ khác) và liên kết nó với mã C của bạn. Bạn có thể muốn bọc nó thành một chức năng bên ngoài.


4

Có một cách nhanh chóng để khởi tạo mảng của bất kỳ loại nào với giá trị đã cho. Nó hoạt động rất tốt với các mảng lớn. Thuật toán như sau:

  • khởi tạo phần tử đầu tiên của mảng (cách thông thường)
  • phần sao chép đã được đặt thành phần chưa được đặt, nhân đôi kích thước với mỗi thao tác sao chép tiếp theo

Đối với mảng 1 000 000phần tử, intnó nhanh hơn 4 lần so với khởi tạo vòng lặp thông thường (i5, 2 lõi, 2,3 GHz, bộ nhớ 4GiB, 64 bit):

loop runtime 0.004248 [seconds]

memfill() runtime 0.001085 [seconds]


#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000

void memfill(void *dest, size_t destsize, size_t elemsize) {
   char   *nextdest = (char *) dest + elemsize;
   size_t movesize, donesize = elemsize;

   destsize -= elemsize;
   while (destsize) {
      movesize = (donesize < destsize) ? donesize : destsize;
      memcpy(nextdest, dest, movesize);
      nextdest += movesize; destsize -= movesize; donesize += movesize;
   }
}    
int main() {
    clock_t timeStart;
    double  runTime;
    int     i, a[ARR_SIZE];

    timeStart = clock();
    for (i = 0; i < ARR_SIZE; i++)
        a[i] = 9;    
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("loop runtime %f [seconds]\n",runTime);

    timeStart = clock();
    a[0] = 10;
    memfill(a, sizeof(a), sizeof(a[0]));
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("memfill() runtime %f [seconds]\n",runTime);
    return 0;
}

2
Xin lỗi, nhưng điều này không đúng. Có lẽ bạn đã quên bật tối ưu hóa biên dịch trong các thử nghiệm của mình (được thử nghiệm với chế độ gỡ lỗi?). Nếu tôi kiểm tra điều này, vòng lặp nhanh hơn gần 50% so với memfill ('luôn luôn' do một số jitter tải trên máy của tôi). Và sử dụng bộ nhớ (a, 0, sizeof (a)); thậm chí nhanh gấp đôi so với loopfill.
RS1980 17/03/2016

2
Như với bất kỳ mã điểm chuẩn nào, bạn cần phải cực kỳ cẩn thận. Thêm một vòng lặp để thực thi mã thời gian 10 lần (và nhân đôi kích thước của mảng thành 20M) - đối với tôi, chạy trên MacBook Pro với macOS Sierra 10.12.3 và sử dụng GCC 6.3.0 - lần đầu tiên, sử dụng vòng lặp mất khoảng 4600 Lời nói, trong khi memfill()mã mất khoảng 1200 bài. Tuy nhiên, ở các lần lặp lại tiếp theo, vòng lặp mất khoảng 900-1000 lượt trong khi memfill()mã mất 1000-1300 Lời. Lặp lại đầu tiên có thể bị ảnh hưởng bởi thời gian để điền vào bộ đệm. Đảo ngược các bài kiểm tra và memfill()lần đầu tiên chậm.
Jonathan Leffler

2

Không ai đã đề cập đến thứ tự chỉ mục để truy cập các phần tử của mảng khởi tạo. Mã ví dụ của tôi sẽ đưa ra một ví dụ minh họa cho nó.

#include <iostream>

void PrintArray(int a[3][3])
{
    std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
    std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
    std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
    std::cout << std::endl;
}

int wmain(int argc, wchar_t * argv[])
{
    int a1[3][3] =  {   11,     12,     13,     // The most
                        21,     22,     23,     // basic
                        31,     32,     33  };  // format.

    int a2[][3] =   {   11,     12,     13,     // The first (outer) dimension
                        21,     22,     23,     // may be omitted. The compiler
                        31,     32,     33  };  // will automatically deduce it.

    int a3[3][3] =  {   {11,    12,     13},    // The elements of each
                        {21,    22,     23},    // second (inner) dimension
                        {31,    32,     33} };  // can be grouped together.

    int a4[][3] =   {   {11,    12,     13},    // Again, the first dimension
                        {21,    22,     23},    // can be omitted when the 
                        {31,    32,     33} };  // inner elements are grouped.

    PrintArray(a1);
    PrintArray(a2);
    PrintArray(a3);
    PrintArray(a4);

    // This part shows in which order the elements are stored in the memory.
    int * b = (int *) a1;   // The output is the same for the all four arrays.
    for (int i=0; i<9; i++)
    {
        std::cout << b[i] << '\t';
    }

    return 0;
}

Đầu ra là:

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

11      12      13      21      22      23      31      32      33

4
<iostream>không hợp lệ Cstd::cout, std::cinv.v ... là một phần của std::namespaceCkhông hỗ trợ namespaces. Hãy thử sử dụng <stdio.h>để printf(...)thay thế.
Francis Cugler

2

Bỏ qua tất cả các cuộc trò chuyện, câu trả lời ngắn gọn là nếu bạn bật tối ưu hóa vào thời gian biên dịch, bạn sẽ không làm tốt hơn thế này:

int i,value=5,array[1000]; 
for(i=0;i<1000;i++) array[i]=value; 

Đã thêm tiền thưởng: mã thực sự dễ đọc :)


7
Câu hỏi đặc biệt yêu cầu khởi tạo. Đây rõ ràng không phải là khởi tạo, mà là sự phân công được thực hiện sau khi khởi tạo. Nó có thể được thực hiện ngay lập tức, nhưng nó vẫn chưa được khởi tạo.
Andy

Hoàn toàn không hữu ích cho một bảng tra cứu tĩnh lớn bên trong một hàm được gọi nhiều lần.
Martin Bonner hỗ trợ Monica

... không nhớ các bảng tra cứu tĩnh bên trong các hàm là một phần của câu hỏi ban đầu - giữ cho nó đơn giản. Điều đó nói rằng, @Community có thể đóng đinh nó.
JWDN

1
  1. Nếu mảng của bạn được khai báo là tĩnh hoặc là toàn cục, tất cả các phần tử trong mảng đã có giá trị mặc định 0.
  2. Một số trình biên dịch đặt mảng mặc định thành 0 trong chế độ gỡ lỗi.
  3. Thật dễ dàng để đặt mặc định thành 0: int mảng [10] = {0};
  4. Tuy nhiên, đối với các giá trị khác, bạn đã sử dụng vòng lặp memset () hoặc vòng lặp;

ví dụ: mảng int [10]; bộ nhớ (mảng, -1, 10 * sizeof (int));


0
#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
    a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
   return 0;
}

Nó sẽ cung cấp cho o / p 5 5 5 5 5 5 ...... cho đến khi kích thước của toàn bộ mảng


0

Tôi biết rằng người dùng đã Tarskitrả lời câu hỏi này theo cách tương tự, nhưng tôi đã thêm một vài chi tiết. Hãy tha thứ cho một số C của tôi vì tôi hơi khó chịu vì tôi có xu hướng muốn sử dụng C ++ hơn, nhưng rồi đây.


Nếu bạn biết kích thước của mảng trước thời hạn ...

#include <stdio.h>

typedef const unsigned int cUINT;
typedef unsigned int UINT;

cUINT size = 10;
cUINT initVal = 5;

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
void printArray( UINT* myArray ); 

int main() {        
    UINT myArray[size]; 
    /* Not initialized during declaration but can be
    initialized using a function for the appropriate TYPE*/
    arrayInitializer( myArray, size, initVal );

    printArray( myArray );

    return 0;
}

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
    for ( UINT n = 0; n < size; n++ ) {
        myArray[n] = initVal;
    }
}

void printArray( UINT* myArray ) {
    printf( "myArray = { " );
    for ( UINT n = 0; n < size; n++ ) {
        printf( "%u", myArray[n] );

        if ( n < size-1 )
            printf( ", " );
    }
    printf( " }\n" );
}

Có một vài cảnh báo ở trên; một là UINT myArray[size];không được khởi tạo trực tiếp khi khai báo, tuy nhiên khối mã hoặc lệnh gọi hàm tiếp theo sẽ khởi tạo từng phần tử của mảng thành cùng một giá trị bạn muốn. Nhắc nhở khác là, bạn sẽ phải viết một initializing functioncho mỗi typebạn sẽ hỗ trợ và bạn cũng sẽ phải sửa đổi printArray()chức năng để hỗ trợ các loại đó.


Bạn có thể thử mã này với một trình biên dịch trực tuyến được tìm thấy ở đây .


0

Đối với khởi tạo chậm (nghĩa là khởi tạo hàm tạo thành viên lớp), hãy xem xét:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;

0

Tôi biết câu hỏi ban đầu rõ ràng đề cập đến C và không phải C ++, nhưng nếu bạn (như tôi) đến đây để tìm giải pháp cho mảng C ++, thì đây là một mẹo nhỏ:

Nếu trình biên dịch của bạn hỗ trợ các biểu thức gấp , bạn có thể sử dụng ma thuật mẫu và std::index_sequenceđể tạo danh sách trình khởi tạo với giá trị mà bạn muốn. Và bạn thậm chí có thể làm constexprđiều đó và cảm thấy như một ông chủ:

#include <array>

/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
    return value;
}

/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
    return {identity_func<T, Indices>(value)...};
}

/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size> 
make_array_of(const T& value) {
    using Indices = std::make_index_sequence<Size>;
    return make_array_of_impl(value, Indices{});
}

// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds

Bạn có thể xem mã tại nơi làm việc (tại Wandbox)


-1

Tôi thấy không có yêu cầu nào trong câu hỏi, vì vậy giải pháp phải chung chung: khởi tạo một mảng đa chiều có thể không xác định được xây dựng từ các thành phần cấu trúc có thể không xác định với giá trị thành viên ban đầu:

#include <string.h> 

void array_init( void *start, size_t element_size, size_t elements, void *initval ){
  memcpy(        start,              initval, element_size              );
  memcpy( (char*)start+element_size, start,   element_size*(elements-1) );
}

// testing
#include <stdio.h> 

struct s {
  int a;
  char b;
} array[2][3], init;

int main(){
  init = (struct s){.a = 3, .b = 'x'};
  array_init( array, sizeof(array[0][0]), 2*3, &init );

  for( int i=0; i<2; i++ )
    for( int j=0; j<3; j++ )
      printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}

Kết quả:

array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'

EDIT: start+element_sizeđã đổi thành(char*)start+element_size


1
Tôi không rõ liệu đây có phải là một giải pháp hay không. Tôi không chắc liệu sizeof(void)thậm chí còn hợp lệ.
Chris Lutz

3
Nó không hoạt động. Chỉ có hai cái đầu tiên được khởi tạo, phần còn lại đều chưa được khởi tạo. Tôi đang sử dụng GCC 4.0 trên Mac OS X 10.4.
dreamlax

Điều này gọi hành vi không xác định bởi vì dữ liệu nguồn trong lần thứ hai memcpy()trùng lặp với không gian đích. Với việc triển khai ngây thơ memcpy(), nó có thể hoạt động nhưng không bắt buộc hệ thống phải làm cho nó hoạt động.
Jonathan Leffler

-1

Trước đây (và tôi không nói đó là một ý tưởng hay), chúng tôi đã thiết lập yếu tố đầu tiên và sau đó:

memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);

Thậm chí không chắc chắn nó sẽ hoạt động nữa (điều đó phụ thuộc vào việc triển khai memcpy) nhưng nó hoạt động bằng cách sao chép liên tục phần tử ban đầu sang phần tiếp theo - thậm chí hoạt động cho các mảng cấu trúc.


Điều đó sẽ không làm việc đáng tin cậy. IMHO, Tiêu chuẩn phải cung cấp các chức năng giống như memcpynhưng chỉ định thứ tự sao chép từ dưới lên hoặc từ trên xuống trong trường hợp chồng chéo, nhưng không được.
supercat

Như tôi đã nói, đó chỉ là một việc chúng tôi đã làm sẽ không hoạt động đáng tin cậy, nhưng sau đó, chúng tôi tập trung vào hiệu quả hơn là tránh các tính năng không có giấy tờ. Mặc dù sao chép bộ nhớ về phía trước sẽ hiệu quả hơn, nhưng không có gì trong đặc tả để nói rằng nó không thể sao chép ngược, theo thứ tự ngẫu nhiên hoặc chia nó thành nhiều luồng. memmove () cung cấp khả năng sao chép mà không bị xung đột.
Mike

Điều này tương đương với mã trong một câu trả lời khác - và thiếu sót. Sử dụng memmove()không làm cho nó hoạt động.
Jonathan Leffler

-2

Nếu bạn có nghĩa là song song, tôi nghĩ toán tử dấu phẩy khi được sử dụng cùng với một biểu thức có thể làm điều đó:

a[1]=1, a[2]=2, ..., a[indexSize]; 

hoặc nếu bạn có nghĩa là trong một cấu trúc đơn lẻ, bạn có thể làm điều đó trong một vòng lặp for:

for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
  array[index] = index;

// Lưu ý toán tử dấu phẩy trong danh sách đối số không phải là toán tử song song được mô tả ở trên;

Bạn có thể khởi tạo một bộ giải mã mảng:

array[] = {1, 2, 3, 4, 5};

Bạn có thể thực hiện cuộc gọi đến malloc / calloc / sbrk / alloca / etc để phân bổ một vùng lưu trữ cố định cho một đối tượng:

int *array = malloc(sizeof(int)*numberOfListElements/Indexes);

và truy cập các thành viên bằng cách:

*(array + index)

Vân vân.


Toán tử dấu phẩy đảm bảo đánh giá từ trái sang phải. Nếu không có tác dụng phụ trong các biểu thức, thì có thể song song hóa các hoạt động, nhưng sẽ là bất thường khi trình biên dịch làm như vậy.
Jonathan Leffler
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.