วิธีการเริ่มต้นสมาชิกทั้งหมดของอาร์เรย์ให้เป็นค่าเดียวกันได้อย่างไร


968

ฉันมีอาร์เรย์ขนาดใหญ่ในC (ไม่ใช่C ++หากสร้างความแตกต่าง) ฉันต้องการเริ่มต้นสมาชิกทั้งหมดที่มีค่าเดียวกัน

ฉันสาบานได้ว่าฉันเคยรู้วิธีง่ายๆในการทำเช่นนี้ ฉันสามารถใช้memset()ในกรณีของฉัน แต่ไม่มีวิธีการทำสิ่งนี้ที่สร้างไว้ในไวยากรณ์ C หรือไม่?


16
ไม่มีคำตอบใด ๆ ที่กล่าวถึงสัญกรณ์เริ่มต้นที่กำหนดซึ่งเป็นไปได้กับ C99 และสูงกว่า ตัวอย่างเช่น: และ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" }, … };หากคุณลบจุดไข่ปลาชิ้นส่วนเหล่านั้นจะรวบรวมภายใต้ C99 หรือ C11
Jonathan Leffler

คำตอบที่แท้จริงของ abelenky คือการใช้ initializer ที่กำหนด แต่ไม่ได้เกิดขึ้นอย่างสมบูรณ์รหัสเริ่มต้น
Rob11311

memset () สามารถช่วย แต่ขึ้นอยู่กับค่า
นิค

2
memset()อภิปรายเฉพาะ: stackoverflow.com/questions/7202411/…ฉันคิดว่ามันใช้งานได้เฉพาะสำหรับ 0
Ciro Santilli 冠状病毒审查审查六四事件

คำตอบ:


1239

ถ้าค่านั้นเป็น 0 (ซึ่งในกรณีนี้คุณสามารถตัดบางส่วนของ initializer และองค์ประกอบที่เกี่ยวข้องจะถูกกำหนดค่าเริ่มต้นเป็น 0) ไม่มีวิธีที่ง่าย

อย่ามองข้ามโซลูชันที่ชัดเจนแม้ว่า:

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

องค์ประกอบที่มีค่าที่หายไปจะเริ่มต้นเป็น 0:

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

ดังนั้นสิ่งนี้จะเริ่มต้นองค์ประกอบทั้งหมดเป็น 0:

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

ใน C ++ รายการเริ่มต้นที่ว่างเปล่าจะเริ่มต้นทุกองค์ประกอบเป็น 0 ซึ่งไม่ได้รับอนุญาตด้วย C:

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

โปรดจำไว้ว่าวัตถุที่มีระยะเวลาการจัดเก็บแบบคงที่จะเริ่มต้นเป็น 0 หากไม่มีการระบุตัวเริ่มต้น:

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

และ "0" ไม่ได้แปลว่า "all-bits-zero" ดังนั้นการใช้ด้านบนนั้นดีกว่าและพกพาได้ดีกว่า memset () (ค่าทศนิยมจะถูกกำหนดค่าเริ่มต้นเป็น +0, ตัวชี้ไปยังค่า Null ฯลฯ )


27
การอ่านผ่านมาตรฐาน C ++ คุณยังสามารถทำ int array [10] = {}; ถึงค่าเริ่มต้นเป็นศูนย์ ฉันไม่มีมาตรฐาน C เพื่อตรวจสอบว่านี่เป็น C ที่ถูกต้องเช่นกัน
workmad3

54
ดูที่หัวข้อ 6.7.8 การกำหนดค่าเริ่มต้นของมาตรฐาน C99 ไม่ปรากฏว่าอนุญาตให้ใช้รายการตัวเริ่มต้นว่างเปล่า
Jonathan Leffler

7
C99 มีคุณสมบัติที่ดีมากมายสำหรับการเริ่มต้นโครงสร้างและอาร์เรย์ ฟีเจอร์เดียวที่มันไม่มี (แต่ Fortran IV, 1966, มี) เป็นวิธีการทำซ้ำ initializer เฉพาะสำหรับอาร์เรย์
Jonathan Leffler

8
@CetinSert: คุณหมายถึงอะไรมันใช้งานไม่ได้? มันทำในสิ่งที่คำตอบนี้บอกว่าควรทำ มันไม่ได้ทำสิ่งที่ความคิดเห็นในรหัสของคุณพูด แต่ความคิดเห็นนั้นไม่ถูกต้อง
Benjamin Lindley

9
@CetinSert: คุณเป็นคนเดียวที่อ้างว่าในความคิดเห็นนั้นองค์ประกอบทั้งหมดจะถูกตั้งค่าเป็น -1 คำตอบนี้อ้างว่าถูกต้องว่าองค์ประกอบที่ไม่ระบุทั้งหมดได้รับการตั้งค่าเป็นศูนย์ ผลลัพธ์ของรหัสของคุณสอดคล้องกับการเรียกร้องนี้
Benjamin Lindley

394

หากคอมไพเลอร์ของคุณคือ GCC คุณสามารถใช้ไวยากรณ์ต่อไปนี้:

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

ลองดูคำอธิบายโดยละเอียด: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html


12
และไวยากรณ์นั้นทำให้ขนาดไฟล์ไบนารีของคอมไพล์เพิ่มขึ้นอย่างมาก สำหรับ N = 65536 (แทน 1024) ไบนารีของฉันกระโดดจากขนาด 15 KB ถึง 270 KB !!
Cetin Sert

50
@CetinSert Compiler ต้องเพิ่ม 65536 intวินาทีลงในข้อมูลสแตติกซึ่งเป็น 256 K - เพิ่มขนาดที่คุณสังเกตเห็น
qrdl

15
@CetinSert ทำไมต้องฉัน มันเป็นพฤติกรรมการรวบรวมมาตรฐานไม่เฉพาะสำหรับผู้เริ่มต้นที่กำหนด หากคุณเริ่มต้น 65536 intวินาทีแบบคงที่เช่นint foo1 = 1, foo2 = 1, ..., foo65536 =1;คุณจะได้รับการเพิ่มขนาดเดียวกัน
qrdl

27
ดีกว่า: "int array [] = {[0 ... 1023] = 5}" ขนาดของอาร์เรย์จะถูกตั้งค่าเป็น 1024 โดยอัตโนมัติง่ายขึ้นและปลอดภัยกว่าในการปรับเปลี่ยน
Francois

4
@ Francois หรืออาเรย์ 2d bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}แต่ฉันไม่แน่ใจว่าสามารถอ่านได้มากกว่าแบบเต็ม
g33kz0r

178

สำหรับการเริ่มต้นอาร์เรย์ขนาดใหญ่แบบคงที่ด้วยค่าเดียวกันโดยไม่ต้องคัดลอกหลายครั้งคุณสามารถใช้มาโครได้:

#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 };

หากคุณต้องการเปลี่ยนค่าคุณต้องทำการแทนที่ในที่เดียวเท่านั้น

แก้ไข: ส่วนขยายที่มีประโยชน์ที่เป็นไปได้

(ได้รับความอนุเคราะห์จากJonathan Leffler )

คุณสามารถพูดคุยเรื่องนี้กับ:

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

สามารถสร้างชุดตัวเลือกได้โดยใช้:

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

ที่ทำงานกับโครงสร้างหรืออาร์เรย์แบบผสม

#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) };

ชื่อมาโครสามารถต่อรองได้


12
ฉันจะพิจารณาเรื่องนี้เฉพาะในกรณีที่รุนแรงมากเท่านั้น
u0b34a0f6ae

47
หากข้อมูลนั้นต้องใช้ ROM ได้จะไม่สามารถใช้ memset ได้
ศ. Falken ผิดสัญญา

9
ตัวประมวลผลล่วงหน้าจะสร้างรหัสจาก #defines ด้วยขนาดอาร์เรย์ที่ใหญ่ขึ้นขนาดที่สามารถใช้งานได้จะเพิ่มขึ้น แต่แน่นอนสำหรับความคิด +)
Leonid

7
@Alcott บนคอมพิวเตอร์เก่าและยังคงอยู่ในระบบฝังตัวหลายรหัสจะถูกวางไว้ในท้ายที่สุดEPROMหรือรอม ROM-สามารถแปลได้ว่าในระบบฝังตัว "รหัสใส่แฟลช" เพราะมันมีความหมายเหมือนกันนั่นคือหน่วยความจำไม่สามารถเขียนรันไทม์ได้ เช่น memset หรือคำสั่งอื่น ๆ เพื่อปรับปรุงหรือเปลี่ยนหน่วยความจำไม่สามารถใช้งานได้ อย่างไรก็ตามค่าคงที่สามารถแสดงและประกายหรือ ROM-ed ก่อนที่โปรแกรมจะเริ่ม
ศ. Falken ผิดสัญญา

4
@ u0b34a0f6ae: โปรดจำไว้ว่าคุณสามารถใช้วิธีนี้ได้เช่นกันหากVAL_1Xไม่ใช่จำนวนเต็มเดียว แต่เป็นรายการ เช่นเดียวกับสถานะ Amigable นี่เป็นวิธีที่จะใช้สำหรับระบบฝังตัวที่คุณต้องการกำหนดค่าเริ่มต้นของ EEPROM หรือหน่วยความจำแฟลช ในทั้งสองกรณีคุณไม่สามารถใช้งานmemset()ได้
Martin Scharrer

63

หากคุณต้องการให้แน่ใจว่าสมาชิกทุกคนในอาร์เรย์ได้รับการกำหนดค่าเริ่มต้นอย่างชัดเจนเพียงละเว้นมิติจากการประกาศ:

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

คอมไพเลอร์จะอนุมานมิติจากรายการ initializer น่าเสียดายสำหรับอาร์เรย์หลายมิติอาจมีการละเว้นมิติภายนอกสุดเท่านั้น:

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

ก็โอเค แต่

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

ไม่ใช่.


ถูกต้องหรือไม่ int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV

10
ไม่คุณไม่ได้ใช้มิติด้านในสุดซึ่งไม่ได้รับอนุญาต สิ่งนี้จะทำให้เกิดข้อผิดพลาดของคอมไพเลอร์
Frank Szczerba

4
ทั้งการเริ่มต้นและการอนุมานความยาวถูกนำมาใช้ใน C99
Palec

3
@Palec: ไม่มี - การอนุมานความยาวได้อยู่ใน C ตั้งแต่วันก่อนมาตรฐาน C (ตั้งแต่ K&R 1st Edition ได้รับการเผยแพร่และอาจจะอยู่พักหนึ่งก่อนหน้านั้น) initializers ที่กำหนดนั้นเป็นของใหม่ใน C99 แต่นี่ไม่ได้ใช้ initializers ที่กำหนด
Jonathan Leffler

53

ฉันเห็นรหัสที่ใช้ไวยากรณ์นี้:

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

ที่ซึ่งมีประโยชน์อย่างยิ่งคือถ้าคุณสร้างอาร์เรย์ที่ใช้ enums เป็นดัชนี:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

สิ่งนี้จะช่วยให้สิ่งต่าง ๆ เป็นไปตามปกติแม้ว่าคุณจะเขียนค่า enum บางตัวที่ไม่เป็นระเบียบก็ตาม

เพิ่มเติมเกี่ยวกับเทคนิคนี้สามารถพบได้ที่นี่และที่นี่


8
นี่คือไวยากรณ์เริ่มต้นของ C99 ซึ่งครอบคลุมโดยคำตอบอื่น ๆ อยู่แล้ว คุณสามารถประกาศอย่างเป็นประโยชน์ได้char const *array[] = { ... };หรือchar const * const array[] = { ... };ไม่ใช่มั้ย
Jonathan Leffler

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

ฉันคิดว่ามันดีกว่า

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

กรณีขนาดของการเปลี่ยนแปลงอาร์เรย์


12
สำหรับบันทึกนั้นเป็นเพียงรุ่นที่ช้ากว่าและละเอียดมากขึ้นmemset(myArray, VALUE, ARRAY_SIZE);
เบ็นสัน

18
คุณจะใช้ memset เพื่อเริ่มต้นอาร์เรย์ int กับค่าที่มากกว่า 255 ได้อย่างไร memset ใช้งานได้ถ้าอาร์เรย์มีขนาดไบต์เท่านั้น
Matt

21
@Benson: คุณไม่สามารถแทนที่โค้ดด้านบนด้วย memset บนแพลตฟอร์มที่ sizeof (int)> sizeof (char) ลองมัน.
ChrisWue

13

คุณสามารถทำสิ่งเริ่มต้นคงที่ทั้งหมดตามรายละเอียดข้างต้น แต่มันอาจจะเป็นคนเกียจคร้านจริง ๆ เมื่อขนาดอาร์เรย์ของคุณเปลี่ยนไป (เมื่ออาร์เรย์ของคุณรวมตัวกันถ้าคุณไม่เพิ่มตัวกำหนดค่าเริ่มต้นพิเศษที่เหมาะสม

memset ช่วยให้คุณได้รับผลกระทบ runtime สำหรับการทำงาน แต่ไม่มีการตีขนาดโค้ดที่ถูกต้องจะไม่ส่งผลต่อการเปลี่ยนแปลงขนาดของอาร์เรย์ ฉันจะใช้วิธีแก้ปัญหานี้ในเกือบทุกกรณีเมื่ออาร์เรย์มีขนาดใหญ่กว่าพูดองค์ประกอบไม่กี่โหล

ถ้ามันสำคัญมากที่อาร์เรย์ถูกประกาศแบบคงที่ฉันจะเขียนโปรแกรมเพื่อเขียนโปรแกรมสำหรับฉันและทำให้มันเป็นส่วนหนึ่งของกระบวนการสร้าง


คุณช่วยเพิ่มตัวอย่างในการใช้งานmemsetเพื่อเริ่มต้นอาร์เรย์ได้ไหม?
Sopalajo de Arrierez

8

นี่เป็นอีกวิธีหนึ่ง:

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},
};

ดู:

C-ส่วนขยาย

inits กำหนด

จากนั้นถามคำถาม: เมื่อหนึ่งสามารถใช้ส่วนขยาย C?

ตัวอย่างโค้ดข้างต้นอยู่ในระบบฝังตัวและจะไม่เห็นแสงจากคอมไพเลอร์อื่น


6

สำหรับการเริ่มต้นชนิดข้อมูล 'ปกติ' (เช่น int arrays) คุณสามารถใช้เครื่องหมายวงเล็บ แต่จะเป็นศูนย์ค่าหลังจากที่ผ่านมาหากยังมีพื้นที่ในอาร์เรย์:

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

5

หากอาร์เรย์เกิดขึ้นเป็น int หรืออะไรกับขนาดของ int ของคุณหรือข่าวรูปแบบของขนาดพอดีกับเวลาที่แน่นอนให้เป็น int (คือเลขศูนย์หรือ 0xA5A5A5A5) วิธีที่ดีที่สุดคือการใช้memset ()

มิฉะนั้นเรียก memcpy () ในวงย้ายดัชนี


5

คำตอบเล็กน้อยในแก้ม เขียนคำสั่ง

array = initial_value

ในภาษาที่สามารถใช้กับอาเรย์ที่คุณโปรดปราน (ของฉันคือฟอร์แทรน แต่มีหลายภาษา) และเชื่อมโยงกับรหัส C คุณอาจต้องการห่อมันให้เป็นฟังก์ชั่นภายนอก


4

มีวิธีที่รวดเร็วในการเริ่มต้นอาร์เรย์ทุกประเภทด้วยค่าที่กำหนด มันทำงานได้ดีมากกับอาร์เรย์ขนาดใหญ่ อัลกอริทึมเป็นดังนี้:

  • เริ่มต้นองค์ประกอบแรกของอาร์เรย์ (วิธีปกติ)
  • คัดลอกส่วนที่ได้รับการตั้งค่าเป็นส่วนที่ไม่ได้ตั้งค่าการเพิ่มขนาดของการทำสำเนาในแต่ละครั้ง

สำหรับ1 000 000องค์ประกอบintอาร์เรย์มันเร็วกว่าการเริ่มต้นลูปปกติ 4 เท่า (i5, 2 คอร์, 2.3 GHz, หน่วยความจำ 4GiB, 64 บิต):

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
ขออภัย แต่นี่ไม่เป็นความจริง คุณอาจลืมเปิดการคอมไพล์การเพิ่มประสิทธิภาพระหว่างการทดสอบ (ทดสอบด้วยโหมดแก้ไขข้อบกพร่องหรือไม่) หากฉันทดสอบสิ่งนี้ลูปจะเร็วกว่า memfill เกือบ 50% เสมอ ('เสมอ' เนื่องจากมีการกระตุกของโหลดบนเครื่องของฉัน) และใช้ memset (a, 0, sizeof (a)); เร็วกว่า loopfill ถึงสองเท่า
RS1980

2
เช่นเดียวกับรหัสการเปรียบเทียบคุณต้องระวังอย่างมาก การเพิ่มลูปเพื่อเรียกใช้งานไทม์โค้ด 10 ครั้ง (และเพิ่มขนาดของอาเรย์เป็น 20M) แสดงขึ้น - สำหรับฉันใช้บน MacBook Pro กับ macOS Sierra 10.12.3 และใช้ GCC 6.3.0 - เป็นครั้งแรกที่ใช้ การวนซ้ำใช้เวลาประมาณ 4600 whiles ในขณะที่memfill()รหัสใช้เวลาประมาณ 1200 .s อย่างไรก็ตามในการวนซ้ำตามมาวงจะใช้เวลาประมาณmemfill()900-1,000 whiles ในขณะที่รหัสใช้ 1,000-1300 µs การวนซ้ำครั้งแรกอาจได้รับผลกระทบจากเวลาในการเติมแคช กลับการทดสอบและmemfill()ช้าในครั้งแรก
Jonathan Leffler

2

ไม่มีใครได้กล่าวถึงคำสั่งดัชนีเพื่อเข้าถึงองค์ประกอบของอาร์เรย์ที่เริ่มต้น รหัสตัวอย่างของฉันจะให้ตัวอย่างเป็นตัวอย่าง

#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;
}

ผลลัพธ์คือ:

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>ไม่ถูกต้องCตามที่std::cout, std::cinฯลฯ เป็นส่วนหนึ่งของstd::namespaceและไม่สนับสนุนC namespacesลองใช้<stdio.h>สำหรับprintf(...)แทน
ฟรานซิส Cugler

2

คำตอบสั้น ๆ คือถ้าคุณเปิดการปรับให้เหมาะสมในเวลารวบรวมคุณจะไม่ทำได้ดีไปกว่านี้:

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

โบนัสเพิ่มเติม: รหัสนั้นชัดเจนจริง ๆ :)


7
คำถามที่ถามโดยเฉพาะสำหรับการเริ่มต้น นี่ไม่ใช่การเริ่มต้นอย่างชัดเจน แต่การมอบหมายให้ทำหลังจากการเริ่มต้น มันอาจจะทำทันที แต่ก็ยังไม่เริ่มต้น
แอนดี้

ไม่เป็นประโยชน์สำหรับตารางการค้นหาแบบสแตติกขนาดใหญ่ภายในฟังก์ชันที่เรียกว่าหลายครั้ง
Martin Bonner สนับสนุนโมนิก้า

... อย่าจำตารางการค้นหาแบบคงที่ภายในฟังก์ชั่นซึ่งเป็นส่วนหนึ่งของคำถามเดิม - ทำให้มันง่าย ที่กล่าวว่า @ ชุมชนอาจจะจับมัน
JWDN

1
  1. ถ้าอาร์เรย์ของคุณถูกประกาศว่าเป็นแบบคงที่หรือเป็นสากลองค์ประกอบทั้งหมดในอาร์เรย์นั้นมีค่าเริ่มต้นเป็น 0
  2. คอมไพเลอร์บางตัวตั้งค่าเริ่มต้นเป็น 0 ในโหมดดีบัก
  3. ง่ายต่อการตั้งค่าเริ่มต้นเป็น 0: int array [10] = {0};
  4. อย่างไรก็ตามสำหรับค่าอื่นคุณใช้ memset () หรือ loop;

ตัวอย่าง: int array [10]; memset (อาร์เรย์, -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;
}

มันจะให้ o / p 5 5 5 5 5 5 ...... จนถึงขนาดของอาร์เรย์ทั้งหมด


0

ฉันรู้ว่าผู้ใช้Tarskiตอบคำถามนี้ในลักษณะที่คล้ายกัน แต่ฉันเพิ่มรายละเอียดอีกเล็กน้อย ยกโทษให้ C บางส่วนสำหรับฉันฉันเป็นสนิมเล็กน้อยเนื่องจากฉันมีแนวโน้มที่จะต้องการใช้ C ++ มากขึ้น แต่ที่นี่จะไป


ถ้าคุณรู้ขนาดของอาร์เรย์ล่วงหน้า ...

#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" );
}

มีข้อแม้อยู่สองสามข้อด้านบน หนึ่งคือUINT myArray[size];ไม่ได้เริ่มต้นโดยตรงกับการประกาศอย่างไรก็ตามการบล็อกรหัสหรือการเรียกฟังก์ชั่นต่อไปมากจะเริ่มต้นแต่ละองค์ประกอบของอาร์เรย์เป็นค่าเดียวกันกับที่คุณต้องการ ข้อแม้อื่น ๆ คือคุณจะต้องเขียนinitializing functionสำหรับแต่ละtypeสิ่งที่คุณจะสนับสนุนและคุณจะต้องแก้ไขprintArray()ฟังก์ชันเพื่อรองรับประเภทเหล่านั้น


คุณสามารถลองรหัสนี้ด้วยการเรียบเรียงออนไลน์พบที่นี่


0

สำหรับการเริ่มต้นล่าช้า (เช่นการเริ่มต้นสมาชิกคลาสของตัวสร้าง) ให้พิจารณา:

int a[4];

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

0

ฉันรู้ว่าคำถามเดิมกล่าวถึง C อย่างชัดเจนและไม่ใช่ C ++ แต่ถ้าคุณ (เช่นฉัน) มาที่นี่เพื่อค้นหาวิธีแก้ปัญหาสำหรับอาร์เรย์ C ++ นี่เป็นเคล็ดลับที่เรียบร้อย:

หากคอมไพเลอร์ของคุณรองรับนิพจน์แบบพับคุณสามารถใช้เทมเพลตเวทย์มนตร์และstd::index_sequenceสร้างรายการตัวเริ่มต้นพร้อมค่าที่คุณต้องการ และคุณสามารถทำได้แม้กระทั่งconstexprรู้สึกเหมือนเป็นเจ้านาย:

#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

คุณสามารถดูรหัสที่ทำงาน (ที่ Wandbox)


-1

ฉันไม่เห็นข้อกำหนดในคำถามดังนั้นวิธีแก้ปัญหาต้องเป็นแบบทั่วไป: การกำหนดค่าเริ่มต้นของอาเรย์หลายมิติที่ไม่ระบุอาจสร้างขึ้นจากองค์ประกอบโครงสร้างอาจไม่ได้ระบุด้วยค่าสมาชิกเริ่มต้น:

#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);
}

ผลลัพธ์:

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'

แก้ไข: start+element_sizeเปลี่ยนเป็น(char*)start+element_size


1
ฉันสงสัยว่านี่เป็นวิธีแก้ปัญหาหรือไม่ ฉันไม่แน่ใจว่าsizeof(void)ถูกต้องหรือไม่
คริสลัทซ์

3
มันไม่ทำงาน มีเพียงสองคนแรกเท่านั้นที่เริ่มต้นได้ส่วนที่เหลือจะไม่ได้กำหนดค่าเริ่มต้น ฉันใช้ GCC 4.0 บน Mac OS X 10.4
dreamlax

สิ่งนี้เรียกใช้ลักษณะการทำงานที่ไม่ได้กำหนดเนื่องจากข้อมูลต้นฉบับในการmemcpy()ทับซ้อนครั้งที่สองกับพื้นที่ปลายทาง ด้วยการใช้งานที่ไร้เดียงสาของmemcpy()มันอาจทำงานได้ แต่ไม่จำเป็นว่าระบบจะใช้งานได้
Jonathan Leffler

-1

ย้อนกลับไปในวัน (และฉันไม่ได้บอกว่ามันเป็นความคิดที่ดี) เราจะกำหนดองค์ประกอบแรกแล้ว:

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

ไม่แน่ใจว่ามันจะทำงานได้อีกต่อไป (ซึ่งจะขึ้นอยู่กับการใช้งานของ memcpy) แต่มันทำงานได้โดยการคัดลอกองค์ประกอบเริ่มต้นไปยังองค์ประกอบต่อไปซ้ำ ๆ - แม้จะใช้งานได้กับอาร์เรย์ของโครงสร้าง


นั่นจะไม่ทำงานอย่างน่าเชื่อถือ IMHO มาตรฐานควรมีฟังก์ชั่นที่เหมือนmemcpyแต่ระบุลำดับการคัดลอกจากล่างขึ้นบนหรือบนลงล่างในกรณีที่ทับซ้อนกัน แต่ไม่ได้ทำ
supercat

อย่างที่ฉันพูดมันเป็นเพียงสิ่งที่เราทำที่จะไม่สามารถทำงานได้อย่างน่าเชื่อถือ แต่หลังจากนั้นเรามุ่งเน้นไปที่ประสิทธิภาพมากกว่าการหลีกเลี่ยงคุณลักษณะที่ไม่มีเอกสาร แม้ว่าจะมีประสิทธิภาพมากกว่าในการคัดลอกหน่วยความจำไปข้างหน้า แต่ก็ไม่มีอะไรในสเปคที่จะบอกว่าไม่สามารถคัดลอกไปข้างหลังได้ในลำดับแบบสุ่มหรือแยกออกเป็นหลายเธรด memmove () ให้ความสามารถในการคัดลอกโดยไม่มีการปะทะกัน
Mike

นี่เทียบเท่ากับรหัสในคำตอบอื่น- และมีข้อบกพร่อง การใช้งานmemmove()ไม่ได้ผล
Jonathan Leffler

-2

หากคุณหมายถึงแบบขนานฉันคิดว่าตัวดำเนินการเครื่องหมายจุลภาคเมื่อใช้ร่วมกับนิพจน์สามารถทำได้ดังนี้:

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

หรือถ้าคุณหมายถึงในโครงสร้างเดียวคุณสามารถทำในห่วงสำหรับ:

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

// หมายเหตุตัวดำเนินการเครื่องหมายจุลภาคในรายการอาร์กิวเมนต์ไม่ใช่ตัวดำเนินการขนานที่อธิบายไว้ข้างต้น

คุณสามารถเริ่มต้นอาร์เรย์ decleration:

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

คุณสามารถโทรไปที่ malloc / calloc / sbrk / alloca / etc เพื่อจัดสรรพื้นที่เก็บข้อมูลถาวรให้กับวัตถุ:

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

และเข้าถึงสมาชิกโดย:

*(array + index)

เป็นต้น


ตัวดำเนินการเครื่องหมายจุลภาครับประกันการประเมินผลจากซ้ายไปขวาในนาม หากไม่มีผลข้างเคียงในการแสดงออกก็อาจเป็นไปได้ที่จะขนานการดำเนินงาน แต่มันจะเป็นเรื่องผิดปกติสำหรับคอมไพเลอร์ที่จะทำเช่นนั้น
Jonathan Leffler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.