การเริ่มต้นขององค์ประกอบทั้งหมดของอาร์เรย์ให้เป็นค่าเริ่มต้นหนึ่งใน C ++?


248

หมายเหตุ C ++: การเริ่มต้นอาร์เรย์มีรายการที่ดีเกี่ยวกับการเริ่มต้นของอาร์เรย์ ฉันมี

int array[100] = {-1};

คาดหวังว่ามันจะเต็มไปด้วย -1 แต่ไม่ใช่เพียงค่าแรกคือและส่วนที่เหลือเป็น 0 ผสมกับค่าสุ่ม

รหัส

int array[100] = {0};

ทำงานได้ดีและตั้งค่าแต่ละองค์ประกอบเป็น 0

ฉันจะพลาดอะไรที่นี่ .. ไม่สามารถเริ่มต้นได้หากค่าไม่เป็นศูนย์?

และ 2: การเริ่มต้นเริ่มต้น (ดังกล่าว) เร็วกว่าการวนซ้ำทั่วทั้งอาร์เรย์และกำหนดค่าหรือทำสิ่งเดียวกันหรือไม่?


1
พฤติกรรมใน C และ C ++ แตกต่างกัน ใน C {0} เป็นกรณีพิเศษสำหรับ struct initializer อย่างไรก็ตาม AFAIK ไม่ใช่สำหรับอาร์เรย์ int array [100] = {0} ควรเหมือนกับ array [100] = {[0] = 0} ซึ่งผลข้างเคียงจะเป็นศูนย์องค์ประกอบอื่น ๆ ทั้งหมด AC คอมไพเลอร์ไม่ควรทำงานตามที่คุณอธิบายข้างต้นแทน int array [100] = {- 1} ควรตั้งค่าองค์ประกอบแรกเป็น -1 และส่วนที่เหลือเป็น 0 (ไม่มีเสียงรบกวน) ใน C หากคุณมี struct x array [100] การใช้ = {0} เนื่องจาก initializer ไม่ถูกต้อง คุณสามารถใช้ {{0}} ซึ่งจะเริ่มต้นองค์ประกอบแรกและเป็นศูนย์อื่น ๆ ทั้งหมดในกรณีส่วนใหญ่จะเป็นสิ่งเดียวกัน
Fredrik Widlund

1
@FredrikWidlund มันเหมือนกันทั้งสองภาษา {0}ไม่ใช่กรณีพิเศษสำหรับ structs หรืออาร์เรย์ กฎคือองค์ประกอบที่ไม่มี initializer รับการเริ่มต้นราวกับว่าพวกเขามี0สำหรับ initializer หากมีการรวมที่ซ้อนกัน (เช่นstruct x array[100]) การเริ่มต้นจะถูกนำไปใช้กับการไม่รวมในลำดับ "แถวหลัก" วงเล็บอาจเลือกที่จะละเว้นการทำเช่นนี้ struct x array[100] = { 0 }ถูกต้องใน C; และใช้ได้ใน C ++ ตราบใดที่สมาชิกรายแรกstruct Xยอมรับ0ว่าเป็น initializer
MM

1
{ 0 }ไม่ได้เป็นพิเศษใน C แต่มันยากมากที่จะกำหนดชนิดของข้อมูลที่ไม่สามารถเริ่มต้นกับมันเนื่องจากไม่มีการก่อสร้างและทำให้วิธีการที่จะไม่หยุด0จากการแปลงโดยปริยายและมอบหมายให้บางสิ่งบางอย่าง
Leushenko

3
โหวตให้เปิดใหม่อีกครั้งเนื่องจากคำถามอื่น ๆ เกี่ยวกับ C. มีหลายวิธีในการเริ่มต้นอาร์เรย์ที่ไม่ถูกต้องใน C.
xskxzr

1
โหวตให้เปิดใหม่อีกครั้ง - C และ C ++ เป็นภาษาที่แตกต่าง
Pete

คำตอบ:


350

ใช้ไวยากรณ์ที่คุณใช้

int array[100] = {-1};

กล่าวว่า "ตั้งองค์ประกอบแรกไป-1และส่วนที่เหลือจะ0" 0ตั้งแต่องค์ประกอบละเว้นทั้งหมดมีการกำหนดให้

ใน C ++ หากต้องการตั้งค่าทั้งหมดเป็น-1คุณสามารถใช้สิ่งที่ชอบstd::fill_n(จาก<algorithm>):

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

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


14
ที่ตอบคำถามทางอ้อมเกี่ยวกับวิธีการกรอกข้อมูลในอาร์เรย์ด้วยค่าเริ่มต้น "ง่าย" ขอบคุณ.
มิลาน

7
@chessofnerd: ไม่ถูกต้อง#include <algorithm>เป็นส่วนหัวขวา<vector>อาจหรือไม่รวมไว้ทางอ้อมที่จะขึ้นอยู่กับการใช้งานของคุณ
Evan Teran

2
คุณไม่จำเป็นต้องเริ่มต้นอาร์เรย์ระหว่างรันไทม์ หากคุณต้องการให้การเริ่มต้นเกิดขึ้นแบบสแตติกคุณสามารถใช้เทมเพลต Variadic และลำดับ Variadic เพื่อสร้างลำดับints ที่ต้องการและขยายลงใน initializer ของอาเรย์
void-pointer

2
@ เกี่ยวกับไม่มีวิธีที่ไม่ถูกต้องในการใช้การเรียกครั้งเดียวfill_nเพื่อเติมอาร์เรย์ 2D ทั้งหมด คุณต้องวนซ้ำข้ามมิติหนึ่งในขณะที่เติมในอีกมิติหนึ่ง
Evan Teran

7
นี่คือคำตอบสำหรับคำถามอื่น std::fill_nไม่ได้เริ่มต้น
Ben Voigt

133

มีส่วนขยายสำหรับคอมไพเลอร์ gcc ซึ่งอนุญาตให้ใช้ไวยากรณ์:

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

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

สิ่งนี้เรียกว่า "Initialized Initialated" ดูที่นี่สำหรับข้อมูลเพิ่มเติม

หมายเหตุสิ่งนี้ไม่ได้ถูกนำไปใช้กับคอมไพเลอร์ gcc c ++


2
น่ากลัว ดูเหมือนว่าไวยากรณ์นี้จะทำงานเป็นเสียงดังกราว (สามารถใช้กับ iOS / Mac OS X)
JosephH

31

หน้าที่คุณเชื่อมโยงไปถึงได้ให้คำตอบในส่วนแรกแล้ว:

หากระบุขนาดอาเรย์ที่ชัดเจน แต่มีการระบุรายการเริ่มต้นที่สั้นกว่าองค์ประกอบที่ไม่ระบุจะถูกตั้งค่าเป็นศูนย์

ไม่มีวิธีที่มีอยู่แล้วภายในเพื่อเริ่มต้นอาร์เรย์ทั้งหมดเป็นค่าที่ไม่เป็นศูนย์

กฎที่ใช้กันทั่วไปคือ: "วิธีการที่ให้คอมไพเลอร์มีอิสระมากที่สุดน่าจะเร็วกว่า"

int array[100] = {0};

เพียงแค่บอกคอมไพเลอร์ "ตั้ง 100 ints เป็นศูนย์" ซึ่งคอมไพเลอร์สามารถเพิ่มประสิทธิภาพได้อย่างอิสระ

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

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

สุดท้ายหากคุณต้องการตั้งค่าอาร์เรย์ให้เป็นค่าที่ไม่ใช่ศูนย์คุณควรใช้ (ใน C ++, อย่างน้อย) เพื่อstd::fill:

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

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


5
คำตอบที่ดี. โปรดทราบว่าใน C ++ (ไม่ใช่ใน C) คุณสามารถทำ int array [100] = {}; และให้คอมไพเลอร์เสรีภาพมากที่สุด :)
โยฮันเน Schaub - litb

1
เห็นด้วยคำตอบที่ยอดเยี่ยม แต่สำหรับอาร์เรย์ที่มีขนาดคงที่มันจะใช้ std :: fill_n :-P
Evan Teran


9

ด้วย {} คุณกำหนดองค์ประกอบตามที่ประกาศไว้; ส่วนที่เหลือจะเริ่มต้นด้วย 0

หากไม่มีการ= {}ทำให้มีชีวิตชีวาเนื้อหาจะไม่ได้กำหนด


8

หน้าเว็บที่คุณเชื่อมโยงรัฐ

หากระบุขนาดอาเรย์ที่ชัดเจน แต่มีการระบุรายการเริ่มต้นที่สั้นกว่าองค์ประกอบที่ไม่ระบุจะถูกตั้งค่าเป็นศูนย์

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


2
memcpy ไม่ใช่ความคิดที่ดีมากเนื่องจากมันจะเปรียบได้กับการตั้งค่าความเร็วที่ฉลาดโดยตรง
Evan Teran

1
ฉันไม่เห็นความจำเป็นในการคัดลอกและอาร์เรย์อาร์เรย์: ทำไมไม่สร้างอาร์เรย์ที่แก้ไขได้ตั้งแต่แรกด้วยค่าที่เติมไว้ล่วงหน้า
Johannes Schaub - litb

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

รายการ initializer เสร็จสิ้นในเวลาคอมไพล์และโหลดที่รันไทม์ ไม่จำเป็นต้องคัดลอกสิ่งต่าง ๆ รอบตัว
Martin York

@litb, @Evan: ตัวอย่างเช่น gcc สร้างการกำหนดค่าเริ่มต้นแบบไดนามิก (MOV จำนวนมาก) แม้จะเปิดใช้งานการปรับให้เหมาะสม สำหรับอาร์เรย์ขนาดใหญ่และข้อกำหนดด้านประสิทธิภาพที่ จำกัด คุณต้องการดำเนินการ init ในเวลารวบรวม memcpy น่าจะเหมาะสำหรับสำเนาขนาดใหญ่ดีกว่า movs ธรรมดาจำนวนมากเพียงอย่างเดียว
laalto

4

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

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

การเริ่มต้นอาร์เรย์ให้เป็นค่าทั่วไปสามารถทำได้อย่างง่ายดาย:

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

หมายเหตุ: DUPx ถูกนำมาใช้เพื่อเปิดใช้งานการทดแทนแมโครในพารามิเตอร์ของ DUP


3

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

มีตัวอย่างที่เป็นที่นี่


3

ใช้std::arrayเราสามารถทำสิ่งนี้ได้อย่างตรงไปตรงมาใน C ++ 14 เป็นไปได้ที่จะทำใน C ++ 11 เท่านั้น แต่ซับซ้อนกว่าเล็กน้อย

อินเทอร์เฟซของเรามีขนาดเวลารวบรวมและค่าเริ่มต้น

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

ฟังก์ชั่นที่สามนั้นมีไว้เพื่อความสะดวกสบายเป็นหลักดังนั้นผู้ใช้จึงไม่จำเป็นต้องสร้างstd::integral_constant<std::size_t, size>มันขึ้นมาเองเพราะมันเป็นการก่อสร้างที่ค่อนข้างคำ การทำงานจริงทำได้โดยหนึ่งในสองฟังก์ชั่นแรก

โอเวอร์โหลดแรกค่อนข้างตรงไปตรงมา: มันสร้างstd::arrayขนาด 0 โดยไม่จำเป็นต้องคัดลอกเราเพิ่งสร้างมันขึ้นมา

การโอเวอร์โหลดครั้งที่สองนั้นยุ่งยากเล็กน้อย มันจะส่งต่อไปตามค่าที่ได้เป็นแหล่งที่มาและมันยังสร้างอินสแตนซ์ของmake_index_sequenceและเพียงแค่เรียกใช้ฟังก์ชั่นการใช้งานอื่น ๆ ฟังก์ชั่นนั้นมีลักษณะอย่างไร

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

สิ่งนี้สร้างขนาดแรก - 1 ข้อโต้แย้งโดยการคัดลอกค่าที่เราส่งผ่านที่นี่เราใช้ดัชนีชุดตัวแปร variadic ของเราเป็นสิ่งที่จะขยาย มีขนาด - 1 รายการในแพ็คนั้น (ตามที่เราระบุในการสร้างmake_index_sequence) และมีค่า 0, 1, 2, 3, ... , ขนาด - 2 อย่างไรก็ตามเราไม่สนใจค่า ( ดังนั้นเราจึงโยนมันให้เป็นโมฆะเพื่อปิดเสียงคำเตือนของคอมไพเลอร์) การขยายแพ็คของพารามิเตอร์จะขยายโค้ดของเราออกมาเป็นแบบนี้ (สมมุติว่าขนาด == 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) };

เราใช้วงเล็บเหล่านั้นเพื่อให้แน่ใจว่าการขยายแพ็ค Variadic ...จะขยายสิ่งที่เราต้องการและเพื่อให้แน่ใจว่าเรากำลังใช้โอเปอเรเตอร์คอมม่า หากไม่มีวงเล็บมันจะดูเหมือนว่าเรากำลังผ่านการโต้แย้งไปยังการเริ่มต้นอาร์เรย์ของเรา แต่จริงๆแล้วเรากำลังประเมินดัชนีชี้ขาดมันเป็นโมฆะโดยไม่สนใจผลลัพธ์ที่เป็นโมฆะและส่งคืนค่าซึ่งถูกคัดลอกลงในอาร์เรย์ .

อาร์กิวเมนต์สุดท้ายคือสิ่งที่เราเรียกว่าstd::forwardเป็นการเพิ่มประสิทธิภาพเล็กน้อย หากใครบางคนผ่าน std :: string ชั่วคราวและบอกว่า "ทำอาร์เรย์จำนวน 5 ของสิ่งเหล่านี้" เราต้องการสำเนา 4 เล่มและย้าย 1 ครั้งแทนที่จะเป็น 5 สำเนา std::forwardมั่นใจได้ว่าเราทำเช่นนี้

รหัสเต็มรวมถึงส่วนหัวและการทดสอบหน่วย:

#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_copyableชนิดเป็นจริง copyable operator=โดยวิธีการของ
เฮิรตซ์

ฉันคิดว่าnon_copy_constructibleจะเป็นชื่อที่ถูกต้องมากขึ้นสำหรับวัตถุ อย่างไรก็ตามไม่มีการกำหนดใด ๆ ในรหัสนี้ดังนั้นจึงไม่สำคัญสำหรับตัวอย่างนี้
David Stone

1

1) เมื่อคุณใช้ initializer สำหรับ struct หรืออาเรย์เช่นนั้นค่าที่ไม่ระบุจะถูกสร้างเป็นค่าเริ่มต้น ในกรณีที่เป็นชนิดดั้งเดิมเช่น ints ซึ่งหมายความว่าพวกเขาจะเป็นศูนย์ โปรดทราบว่าสิ่งนี้ใช้ซ้ำ: คุณสามารถมีอาร์เรย์ของ structs ที่มีอาร์เรย์และถ้าคุณระบุเพียงแค่สนามแรกของโครงสร้างแรกจากนั้นส่วนที่เหลือทั้งหมดจะเริ่มต้นได้ด้วยศูนย์และตัวสร้างเริ่มต้น

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


1) การตั้งค่าเริ่มต้นเบื้องต้นของ POD ไม่ได้เกิดขึ้นที่นี่ การใช้รายการคอมไพเลอร์จะสร้างค่าในเวลารวบรวมและวางไว้ในส่วนพิเศษของชุดประกอบที่เพิ่งโหลดเป็นส่วนหนึ่งของการเริ่มต้นโปรแกรม (เช่นรหัส) ดังนั้นราคาจึงเป็นศูนย์ที่รันไทม์
Martin York

1
ฉันไม่เห็นว่าเขาผิดตรงไหนเหรอ? int a [100] = {} แน่นอนว่าจะเริ่มต้นได้กับ 0 ทั้งหมดโดยไม่คำนึงถึงตำแหน่งที่ปรากฏและ struct {int a; } b [100] = {}; ก็เช่นกัน "เป็นค่าเริ่มต้นที่สร้างเป็นหลัก" => "สร้างค่าแล้ว", สรรพสินค้า แต่สิ่งนี้ไม่สำคัญในกรณีของ ints, PODS หรือประเภทที่มีผู้ใช้ประกาศ มันเป็นเรื่องสำคัญสำหรับผู้ที่ไม่ได้ใช้ Pod โดยไม่ต้องแจ้งให้ผู้ใช้ทราบถึงสิ่งที่ฉันรู้ แต่ฉันจะไม่ลงคะแนน (!) เพราะสิ่งนี้ อย่างไรก็ตาม +1 สำหรับคุณที่จะทำให้มันเป็น 0 อีกครั้ง :)
344902 Johannes Schaub - litb

@Evan: ฉันผ่านการรับรองด้วย "เมื่อคุณใช้ initializer ... " ฉันไม่ได้อ้างถึงค่าเริ่มต้น @Martin: นั่นอาจใช้ได้กับข้อมูลคงที่, คงที่, หรือข้อมูลทั่วโลก แต่ฉันไม่เห็นว่ามันจะทำงานอย่างไรกับ: การทดสอบ int () {int i [10] = {0}; int v = i [0]; ฉัน [0] = 5; กลับ v; } คอมไพเลอร์ควรเริ่มต้น i [] เป็นศูนย์ทุกครั้งที่คุณเรียกใช้ test ()
Boojum

มันอาจจะวางข้อมูลลงในส่วนของข้อมูลแบบคงที่และทำให้ "ฉัน" เรียกมัน :)
โยฮันเน Schaub - litb

จริง - ในทางเทคนิคในกรณีนี้มันสามารถลบ "i" ทั้งหมดและส่งคืนค่า 0 แต่การใช้เซ็กเมนต์ข้อมูลแบบคงที่สำหรับข้อมูลที่ไม่แน่นอนจะเป็นอันตรายในสภาพแวดล้อมแบบมัลติเธรด ประเด็นที่ฉันพยายามตอบมาร์ตินก็คือคุณไม่สามารถกำจัดค่าใช้จ่ายในการเริ่มต้นได้อย่างสมบูรณ์ คัดลอกก้อนที่สร้างไว้ล่วงหน้าจากส่วนข้อมูลคงที่แน่นอน แต่มันยังไม่ว่าง
Boojum


0

ในภาษาโปรแกรม C ++ V4, Stroustrup แนะนำให้ใช้เวกเตอร์หรือวาลเลย์ย์เหนืออาร์เรย์ในตัว ด้วย valarrary's เมื่อคุณสร้างพวกเขาคุณสามารถเริ่มพวกเขาเป็นค่าเฉพาะเช่น:

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

ในการเริ่มต้นสมาชิกอาเรย์ 7 ที่ยาวด้วย "7777777"

นี่เป็นวิธีการ C ++ ในการนำคำตอบไปใช้โดยใช้โครงสร้างข้อมูล C ++ แทนอาร์เรย์ "plain old C"

ฉันเปลี่ยนมาใช้ valarray เป็นความพยายามในรหัสของฉันเพื่อพยายามใช้ C ++ 'isms v. C'isms ....


นี่คือตัวอย่างที่เลวร้ายที่สุดที่สองของวิธีการใช้ชนิดที่ฉันเคยเห็น ...
Steazy

-3

ควรเป็นคุณสมบัติมาตรฐาน แต่ด้วยเหตุผลบางอย่างมันไม่รวมอยู่ในมาตรฐาน C หรือ 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 คุณสามารถทำได้:

program main
    implicit none

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

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

แต่มันไม่มีตัวเลขที่ไม่ได้ลงนาม ...

เหตุใด C / C ++ ไม่สามารถใช้งานได้ มันยากจริงๆเหรอ? มันช่างโง่เหลือเกินที่จะต้องเขียนมันเองเพื่อให้ได้ผลลัพธ์เดียวกัน ...

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

เกิดอะไรขึ้นถ้ามันเป็นอาร์เรย์ 1,000,00 ไบต์? ฉันจะต้องเขียนสคริปต์เพื่อเขียนให้ฉันหรือใช้วิธีแฮ็กกับแอสเซมบลี / etc นี่เป็นเรื่องไร้สาระ

พกพาได้อย่างสมบูรณ์แบบไม่มีเหตุผลที่จะไม่ใช้ภาษา

เพียงแฮ็คมันเหมือน:

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

วิธีหนึ่งในการแฮ็คมันคือผ่านการประมวลผลล่วงหน้า ... (รหัสด้านล่างไม่ครอบคลุมถึงกรณีขอบ แต่เขียนเพื่อแสดงให้เห็นถึงสิ่งที่สามารถทำได้อย่างรวดเร็ว)

#!/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);

คุณกำลังพิมพ์ในวงทำไมคุณไม่สามารถกำหนดในวง?
Abhinav Gauniyal

1
การกำหนดภายในลูปเกิดค่าใช้จ่ายรันไทม์; ในขณะที่ hardcoding บัฟเฟอร์นั้นว่างเพราะบัฟเฟอร์ถูกฝังเข้าไปในไบนารี่แล้วดังนั้นจึงไม่ต้องเสียเวลาในการสร้างอาเรย์ตั้งแต่เริ่มต้นในแต่ละครั้งที่โปรแกรมทำงาน คุณคิดถูกว่าการพิมพ์ในลูปไม่ใช่ความคิดที่ดีโดยรวมแม้ว่าจะเป็นการดีกว่าที่จะผนวกไว้ในลูปแล้วจึงพิมพ์อีกครั้งเนื่องจากการเรียกใช้ printf แต่ละครั้งต้องใช้การเรียกระบบในขณะที่การต่อสตริง เนื่องจากขนาดในโปรแกรมประเภทนี้ไม่ใช่ของแท้จึงควรสร้างอาร์เรย์นี้ในเวลารวบรวมไม่ใช่เวลาทำงาน
Dmitry

"การกำหนดภายในลูปเกิดค่าใช้จ่ายรันไทม์" - คุณประเมินเครื่องมือเพิ่มประสิทธิภาพต่ำเกินไป
Asu

ขึ้นอยู่กับขนาดของอาร์เรย์นั้น gcc และเสียงดังกังวานจะ "hardcode" หรือหลอกค่าในและมีอาร์เรย์ขนาดใหญ่โดยตรงเพียงแค่memsetมันแม้จะมีอาร์เรย์ "hardcoded"
Asu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.