किसी सरणी के सभी तत्वों का प्रारंभिक मान C ++ में एक डिफ़ॉल्ट मान?


248

C ++ नोट्स: ऐरे इनिशियलाइज़ेशन में सरणियों के प्रारंभ पर एक अच्छी सूची है। मेरे पास एक

int array[100] = {-1};

यह -1 के साथ पूर्ण होने की उम्मीद है, लेकिन इसका पहला मूल्य नहीं है, और बाकी 0 यादृच्छिक मूल्यों के साथ मिश्रित हैं।

कोड

int array[100] = {0};

बस ठीक काम करता है और प्रत्येक तत्व को 0 पर सेट करता है।

मैं यहाँ क्या याद कर रहा हूँ .. अगर मूल्य शून्य नहीं है तो क्या कोई इसे शुरू नहीं कर सकता है?

और 2: क्या डिफॉल्ट इनिशियलाइज़ेशन (ऊपर के रूप में) पूरे ऐरो के माध्यम से सामान्य लूप की तुलना में अधिक तेज़ है और एक वैल्यू असाइन करता है या क्या यह वही काम करता है?


1
C और C ++ में व्यवहार भिन्न है। C {0} में एक स्ट्रक्चर इनिशियलाइज़र के लिए एक विशेष मामला है, हालाँकि AFAIK सरणियों के लिए नहीं। int array [100] = {0} समान होना चाहिए array [100] = {[0] = 0}, जो कि साइड-इफेक्ट के रूप में अन्य सभी तत्वों को शून्य कर देगा। एसी कंपाइलर को आपके द्वारा ऊपर वर्णित के अनुसार व्यवहार नहीं करना चाहिए, इसके बजाय इंट सरणी [100] = {- 1} को पहला तत्व -1 और बाकी को 0 (शोर के बिना) सेट करना चाहिए। C में यदि आपके पास एक संरचित x सरणी है [100], तो एक initializer के रूप में = {0} का उपयोग करना मान्य नहीं है। आप {{0}} का उपयोग कर सकते हैं जो पहले तत्व को इनिशियलाइज़ करेगा और अन्य सभी को शून्य करेगा, ज्यादातर मामलों में यही बात होगी।
फ्रेड्रिक विडालंड

1
@FredrikWidlund यह दोनों भाषाओं में समान है। {0}संरचना या सरणियों के लिए एक विशेष मामला नहीं है। नियम यह है कि बिना आरम्भिक वाले तत्व आरम्भिकृत हो जाते हैं जैसे कि वे 0एक आरम्भक के लिए थे। यदि नेस्टेड समुच्चय हैं (उदाहरण के लिए struct x array[100]) तो शुरुआती को "पंक्ति-प्रमुख" क्रम में गैर-समुच्चय पर लागू किया जाता है; ब्रेसिज़ वैकल्पिक रूप से ऐसा करने से छोड़ा जा सकता है। struct x array[100] = { 0 }सी में मान्य है; और C ++ में मान्य है जब तक कि शुरुआती के रूप में struct Xस्वीकार 0करता है।
MM

1
{ 0 }C में विशेष नहीं है, लेकिन एक डेटा प्रकार को परिभाषित करना बहुत कठिन है, क्योंकि इसे इसके साथ आरंभ नहीं किया जा सकता है क्योंकि कोई निर्माता नहीं हैं और इस प्रकार किसी भी तरह से 0परिवर्तित होने और कुछ को सौंपा जाने से रोकने का कोई तरीका नहीं है
Leushenko

3
फिर से खोलने की कोशिश की क्योंकि अन्य प्रश्न सी के बारे में है। एक सरणी को आरम्भ करने के कई सी ++ तरीके हैं जो सी में मान्य नहीं हैं
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);

पोर्टेबल सी में, आपको अपना लूप रोल करना होगा। संकलक-विस्तार हैं या आप एक शॉर्टकट के रूप में कार्यान्वयन-परिभाषित व्यवहार पर निर्भर कर सकते हैं यदि यह स्वीकार्य है।


14
यह भी एक अप्रत्यक्ष प्रश्न का उत्तर देता है कि ऐरे को डिफ़ॉल्ट मानों के साथ कैसे भरें "आसानी से"। धन्यवाद।
मिलन

7
@chessofnerd: ठीक नहीं, #include <algorithm>सही हेडर है, <vector>इसे अप्रत्यक्ष रूप से शामिल कर सकते हैं या नहीं, यह आपके कार्यान्वयन पर निर्भर करेगा।
इवान टेरान

2
आपको रनटाइम के दौरान सरणी को इनिशियलाइज़ करने का सहारा नहीं लेना है। यदि आपको वास्तव में वैधानिक रूप से होने के लिए आरंभीकरण की आवश्यकता है, तो एस के वांछित अनुक्रम को उत्पन्न करने intऔर इसे सरणी के आरंभीक में विस्तारित करने के लिए वैरेडिक टेम्प्लेट और वैरेडिक अनुक्रम का उपयोग करना संभव है ।
शून्य-सूचक

2
@ontherocks, fill_nसंपूर्ण 2 डी सरणी को भरने के लिए किसी एकल कॉल का उपयोग करने का कोई सही तरीका नहीं है । दूसरे में भरते समय आपको एक आयाम में लूप करने की आवश्यकता होती है।
इवान टेरान

7
यह किसी अन्य प्रश्न का उत्तर है। std::fill_nआरंभीकरण नहीं है।
बेन वोइगट

133

Gcc कंपाइलर के लिए एक एक्सटेंशन है जो सिंटैक्स की अनुमति देता है:

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

यह सभी तत्वों को -1 पर सेट करेगा।

इसे "नामित प्रारंभिक" के रूप में जाना जाता है जो आगे की जानकारी के लिए यहां देखें।

ध्यान दें कि यह gcc c ++ कंपाइलर के लिए लागू नहीं किया गया है।


2
बहुत बढ़िया। यह वाक्य रचना भी क्लैंग में काम करने लगती है (इसलिए इसे आईओएस / मैक ओएस एक्स पर इस्तेमाल किया जा सकता है)।
जोसेफ

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] = {} कर सकते हैं; और संकलक सबसे स्वतंत्रता :) देना
litb - Johannes Schaub

1
सहमत, उत्कृष्ट जवाब। लेकिन एक निश्चित आकार के सरणी के लिए, यह std :: fill_n :-P का उपयोग करेगा।
इवान टेरन


9

{} के साथ आप तत्वों को घोषित करते हैं जैसे वे घोषित होते हैं; बाकी को 0 से शुरू किया गया है।

यदि कोई = {}वशीकरण नहीं है, तो सामग्री अपरिभाषित है।


8

आपके द्वारा लिंक किया गया पृष्ठ

यदि एक स्पष्ट सरणी आकार निर्दिष्ट किया गया है, लेकिन एक छोटी इनिटिलिजेशन सूची निर्दिष्ट है, तो अनिर्दिष्ट तत्व शून्य पर सेट हैं।

स्पीड इश्यू: इस छोटे से एरेज़ के लिए कोई भी अंतर नगण्य होगा। यदि आप बड़े सरणियों के साथ काम करते हैं और गति आकार की तुलना में बहुत अधिक महत्वपूर्ण है, तो आपके पास डिफ़ॉल्ट मानों का एक संक्षिप्त सरणी (संकलित समय पर आरंभ) हो सकता है और फिर memcpyउन्हें परिवर्तनीय सरणी में लाया जा सकता है।


2
मेमसीपी बहुत अच्छा विचार नहीं है, क्योंकि यह केवल सीधे गति बुद्धिमान मूल्यों को स्थापित करने के लिए तुलनीय होगा।
इवान टेरान

1
मुझे कॉपी और कास्ट एरे की आवश्यकता नहीं दिखती: पहले से भरे हुए मानों के साथ पहली जगह में परिवर्तनीय एरे क्यों नहीं बनाए जाते?
जोहान्स शाउब -

गति स्पष्टीकरण के लिए धन्यवाद और अगर यह करना है तो गति एक बड़े सरणी आकार (जो मेरे मामले में है) के साथ एक मुद्दा है
मिलान

प्रारंभिक सूची संकलन समय पर की जाती है और रनटाइम पर लोड की जाती है। आसपास चीजों की नकल करने की जरूरत नहीं है।
मार्टिन

@litb, @ इवान: उदाहरण के लिए, gcc सक्रियकरण के साथ गतिशील इनिशियलाइज़ेशन (बहुत सारे मूव) भी उत्पन्न करता है। के लिए बड़े सरणियों और तंग प्रदर्शन की आवश्यकताओं, आप संकलन समय पर init करना चाहते हैं। मेमकीपी शायद बड़ी प्रतियों के लिए अनुकूलित है, जो कि बहुत सारे सादे मोमो की तुलना में बेहतर है ।
लालाटो

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

एकल-बाइट तत्वों की एक सरणी के मामले के लिए, आप सभी तत्वों को समान मूल्य पर सेट करने के लिए मेमसेट का उपयोग कर सकते हैं।

यहाँ एक उदाहरण है


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 तर्क। यहां, हम अपने वैरिएड पैरामीटर पैक इंडेक्स का उपयोग उसी तरह करते हैं जैसे कुछ विस्तार करने के लिए। उस पैक में आकार - 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) };

हम उन कोष्ठकों का उपयोग यह सुनिश्चित करने के लिए करते हैं कि वैरिएड पैक विस्तार ...हम क्या चाहते हैं, और यह भी सुनिश्चित करें कि हम अल्पविराम ऑपरेटर का उपयोग कर रहे हैं। कोष्ठक के बिना, ऐसा लगेगा कि हम अपने सरणी आरंभीकरण के लिए तर्कों का एक समूह पारित कर रहे हैं, लेकिन वास्तव में, हम सूचकांक का मूल्यांकन कर रहे हैं, इसे शून्य करने के लिए कास्टिंग कर रहे हैं, उस शून्य परिणाम को अनदेखा कर रहे हैं, और फिर वापसी का मान, जो कि सरणी में कॉपी किया गया है ।

अंतिम तर्क, जिसे हम कहते हैं std::forward, वह एक मामूली अनुकूलन है। यदि कोई अस्थायी std :: string में पास होता है और कहता है कि "इनमें से 5 की एक सरणी बनाएं", तो हम चाहते हैं कि 5 प्रतियों के बजाय 4 प्रतियां और 1 चाल चलें। यह 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प्रकार वास्तव में के माध्यम से प्रतिलिपि योग्य है operator=
हर्ट्ज

मुझे लगता है non_copy_constructibleकि वस्तु के लिए एक अधिक सटीक नाम होगा। हालाँकि, इस कोड में कहीं भी असाइनमेंट नहीं है, इसलिए यह इस उदाहरण के लिए मायने नहीं रखता है।
डेविड स्टोन

1

1) जब आप एक आरंभिक का उपयोग करते हैं, तो एक संरचना या उस तरह के एक सरणी के लिए, अनिर्दिष्ट मान अनिवार्य रूप से डिफ़ॉल्ट रूप से निर्मित होते हैं। किलों की तरह एक आदिम प्रकार के मामले में, इसका मतलब है कि वे शून्य हो जाएंगे। ध्यान दें कि यह पुनरावर्ती रूप से लागू होता है: आपके पास सरणियों वाली एक सरणी हो सकती है और यदि आप केवल पहली संरचना के पहले क्षेत्र को निर्दिष्ट करते हैं, तो सभी शेष शून्य और डिफ़ॉल्ट निर्माणकर्ताओं के साथ आरंभ किए जाएंगे।

2) कंपाइलर शायद इनिशियल कोड उत्पन्न करेगा जो कम से कम उतना अच्छा हो जितना आप हाथ से कर सकते हैं। जब भी संभव हो मैं कंपाइलर को इनिशियलाइज़ेशन करने देना पसंद करता हूं।


1) POD की डिफ़ॉल्ट आरंभीकरण यहां नहीं हो रहा है। सूची का उपयोग करते हुए संकलक समय पर मान उत्पन्न करेगा और उन्हें एक विशेष खंड में इकट्ठा करेगा जो केवल प्रोग्राम इनिशियलाइज़ेशन (कोड की तरह) के हिस्से के रूप में लोड किया गया है। इसलिए रनटाइम पर लागत शून्य है।
मार्टिन यॉर्क

1
मैं नहीं देखता कि वह कहां गलत है? int [100] = {} निश्चित रूप से सभी 0 से आरंभीकृत होता है, जहां यह प्रकट होता है, और संरचना {int a; } b [100] = {}; बहुत है। "अनिवार्य रूप से डिफ़ॉल्ट रूप से निर्मित" => "मूल्य निर्मित", थो। लेकिन यह ints, PODS या उपयोगकर्ता द्वारा घोषित ctors के साथ प्रकार के मामले में कोई फर्क नहीं पड़ता। यह केवल उपयोगकर्ता के बिना एनओएन-पॉड्स के लिए मायने रखता है, जो मुझे पता है कि ctors की घोषणा की। लेकिन मैं इस वजह से नीचे (!) वोट नहीं डालूंगा। वैसे भी, +1 आपके लिए इसे फिर से बनाने के लिए :)
जोहान्स स्काउब -

@ इवान: मैंने "जब आप एक इनिशलाइज़र का उपयोग करते हैं ..." के साथ मेरे बयान को योग्य किया था तो मैं अनइंस्टॉल किए गए मूल्यों का उल्लेख नहीं कर रहा था। @ मर्टिन: यह स्थिर, स्थिर या वैश्विक डेटा के लिए काम कर सकता है। लेकिन मैं यह नहीं देखता कि यह कैसे काम करेगा जैसे: int test () {int i [10] = {0}; int v = i [0]; मैं [0] = 5; वापसी v; } कंपाइलर बेहतर था कि मैं [[] को हर बार जब आप टेस्ट () कहते हैं, ज़ीरो करें।
बोजूम

यह डेटा को स्टैटिक डेटा सेगमेंट में रख सकता है, और "i" को इसके लिए संदर्भित करता है :)
जोहान्स स्काउब -

सच है - तकनीकी रूप से, इस मामले में यह "i" को पूरी तरह से खत्म कर सकता है और सिर्फ 0. लौटा सकता है। लेकिन स्थूल डेटा के लिए स्थैतिक डेटा खंड का उपयोग करना बहु-थ्रेडेड वातावरण में खतरनाक होगा। मार्टिन के जवाब में मैं जो बात करना चाह रहा था, वह यह थी कि आप इनिशियलाइज़ेशन की लागत को पूरी तरह से खत्म नहीं कर सकते। स्थैतिक डेटा खंड से एक पूर्व-निर्मित चंक को कॉपी करें, सुनिश्चित करें, लेकिन यह अभी भी मुफ़्त नहीं है।
21

1

C ++ में, मेटा प्रोग्रामिंग और वैरेडिक टेम्प्लेट का उपयोग करना भी संभव है। निम्न पोस्ट यह दिखाती है कि यह कैसे करना है: C ++ में संकलित समय पर प्रोग्रामेटिक रूप से स्थिर सरणियाँ बनाएं


0

C ++ प्रोग्रामिंग लैंग्वेज V4 में, Stroustrup ने बिल्डिन एरेज़ पर वैक्टर या वैलेरेज़ का उपयोग करने की सलाह दी। वैलेरी के साथ, जब आप उन्हें बनाते हैं, तो आप उन्हें एक विशिष्ट मूल्य के लिए भेज सकते हैं जैसे:

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

एक सरणी 7 सदस्यों को "7777777" के साथ लंबा करने के लिए।

यह "सादे पुराने सी" सरणी के बजाय C ++ डेटा संरचना का उपयोग करके उत्तर को लागू करने का एक C ++ तरीका है।

मैंने अपने कोड में C ++ 'isms v। C'ismism का उपयोग करने के प्रयास के रूप में वैलेरे का उपयोग करने के लिए स्विच किया।'


यह मेरे द्वारा देखे गए एक प्रकार का उपयोग करने का दूसरा सबसे बुरा उदाहरण है ...
स्टीज़ी

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

फोरट्रान में आप कर सकते हैं:

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 बाइट्स की एक सरणी थी? मुझे इसे लिखने के लिए स्क्रिप्ट लिखनी होगी, या असेंबली / आदि से हैक करने का सहारा लेना होगा। यह बकवास है।

यह पूरी तरह से पोर्टेबल है, इसका कोई कारण नहीं है कि यह भाषा में न हो।

बस इसे इस तरह से हैक करें:

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

आप लूप में प्रिंट कर रहे हैं, आप लूप में क्यों नहीं लिख सकते?
अभिनव गौण्याल १३'१hin को ६:२०

1
एक लूप के अंदर असाइन करना रनवे ओवरहेड को बढ़ाता है; बफर को हार्डकोड करने के लिए स्वतंत्र है क्योंकि बफर पहले से ही बाइनरी में एम्बेडेड है, इसलिए यह हर बार प्रोग्राम को चलाने से खरोंच से सरणी का निर्माण करने में समय बर्बाद नहीं करता है। आप सही कह रहे हैं कि लूप में मुद्रण एक अच्छा विचार नहीं है, हालांकि, लूप के अंदर जोड़ना बेहतर है और फिर एक बार प्रिंट करें, क्योंकि प्रत्येक प्रिंटफ कॉल के लिए सिस्टम कॉल की आवश्यकता होती है, जबकि एप्लिकेशन के ढेर / स्टैक का उपयोग करते हुए स्ट्रिंग समवर्ती नहीं करता है। चूंकि इस तरह के कार्यक्रम में आकार एक गैर-कारण है, इसलिए संकलन समय पर इस सरणी का निर्माण करना सबसे अच्छा है, रनटाइम नहीं।
दिमित्री

"लूप इनकमिंग रनटाइम ओवरहेड के अंदर असाइन करना" - आप ऑप्टिमाइज़र को गंभीर रूप से कम आंकते हैं।
Asu

सरणी के आकार के आधार पर, जीसीसी और क्लैंग "हार्डकोड" या मूल्य को ट्रिक करेगा, और बड़े सरणियों के साथ, सीधे सीधे memsetइसे, यहां तक ​​कि "हार्डकोड" सरणी के साथ।
आशु
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.