खोज…


परिचय

लूप स्टेटमेंट तब तक बार-बार स्टेटमेंट्स को निष्पादित करता है जब तक कि कोई शर्त पूरी नहीं हो जाती। C ++ में 3 प्रकार के आदिम लूप हैं: के लिए, जबकि, और ... करते समय।

वाक्य - विन्यास

  • जबकि ( स्थिति ) कथन ;
  • जबकि कथन ( अभिव्यक्ति );
  • for ( for-init-statement ; कंडीशन ; एक्सप्रेशन ) स्टेटमेंट ;
  • for ( for-range-घोषणापत्र : for-range-initializer ) कथन ;
  • टूटना ;
  • जारी रखें ;

टिप्पणियों

algorithm कॉल आमतौर पर हाथ से लिखे गए लूप के लिए बेहतर होते हैं।

यदि आप कुछ चाहते हैं जो एक एल्गोरिथ्म पहले से ही करता है (या कुछ समान है), एल्गोरिथ्म कॉल स्पष्ट है, अक्सर अधिक कुशल और कम त्रुटि प्रवण होता है।

यदि आपको एक लूप की आवश्यकता होती है जो कुछ सरल करता है (लेकिन यदि आप एक एल्गोरिथ्म का उपयोग कर रहे थे तो बाइंडर्स और एडेप्टर की एक उलझन वाली उलझन की आवश्यकता होगी), तो बस लूप लिखें।

रेंज-बेस्ड फॉर

सी ++ 11

एक सांख्यिक सूचकांक का उपयोग किए बिना या पुनरावृत्तियों को सीधे एक्सेस करने के for लूप्स का उपयोग इट्रेटर-आधारित श्रेणी के तत्वों पर पुनरावृति करने के लिए किया जा सकता है:

vector<float> v = {0.4f, 12.5f, 16.234f};

for(auto val: v)
{
    std::cout << val << " ";
}

std::cout << std::endl;

इस ओवर में हर तत्व पुनरावृति जाएगा v के साथ, val वर्तमान तत्व का मान रही है। निम्नलिखित कथन:

for (for-range-declaration : for-range-initializer ) statement

के बराबर है:

{
    auto&& __range = for-range-initializer;
    auto __begin = begin-expr, __end = end-expr;
    for (; __begin != __end; ++__begin) {
        for-range-declaration = *__begin;
        statement
    }
}
सी ++ 17
{
    auto&& __range = for-range-initializer;
    auto __begin = begin-expr;
    auto __end = end-expr; // end is allowed to be a different type than begin in C++17
    for (; __begin != __end; ++__begin) {
        for-range-declaration = *__begin;
        statement
    }
}

यह परिवर्तन C ++ 20 में रेंज टीएस के नियोजित समर्थन के लिए पेश किया गया था।

इस मामले में, हमारा लूप इसके बराबर है:

{
    auto&& __range = v;
    auto __begin = v.begin(), __end = v.end();
    for (; __begin != __end; ++__begin) {
        auto val = *__begin;
        std::cout << val << " ";
    }
}

ध्यान दें कि auto val एक मूल्य प्रकार की घोषणा करता है, जो रेंज में संग्रहीत मूल्य की एक प्रति होगी (हम इसे चलते समय इटरेटर से इसकी प्रतिलिपि बना रहे हैं)। यदि श्रेणी में संग्रहीत मान कॉपी करने के लिए महंगे हैं, तो आप const auto &val का उपयोग करना चाह सकते हैं। आपको auto का उपयोग करने की भी आवश्यकता नहीं है; आप एक उपयुक्त टाइपनेम का उपयोग कर सकते हैं, जब तक कि यह रेंज के मूल्य प्रकार से स्पष्ट रूप से परिवर्तनीय हो।

यदि आपको पुनरावृत्त तक पहुँच की आवश्यकता है, तो रेंज-आधारित आपकी मदद नहीं कर सकता (कुछ प्रयास के बिना नहीं, कम से कम)।

यदि आप इसे संदर्भित करना चाहते हैं, तो आप ऐसा कर सकते हैं:

vector<float> v = {0.4f, 12.5f, 16.234f};

for(float &val: v)
{
    std::cout << val << " ";
}

आप पर पुनरावृति सकता const यदि आपके पास संदर्भ const कंटेनर:

const vector<float> v = {0.4f, 12.5f, 16.234f};

for(const float &val: v)
{
    std::cout << val << " ";
}

जब अनुक्रम पुनरावृत्ति एक छद्म वस्तु लौटाता है और आपको उस वस्तु को गैर- const तरीके से संचालित करने की आवश्यकता होती है, तो अग्रेषण संदर्भों का उपयोग करेगा। नोट: यह आपके कोड के पाठकों को सबसे अधिक भ्रमित करेगा।

vector<bool> v(10);

for(auto&& val: v)
{
    val = true;
}

"श्रेणी" के लिए रेंज-आधारित के for प्रदान किया गया प्रकार निम्न में से एक हो सकता है:

  • भाषा सरणियाँ:

    float arr[] = {0.4f, 12.5f, 16.234f};
    
    for(auto val: arr)
    {
        std::cout << val << " ";
    }
    

    ध्यान दें कि डायनामिक ऐरे को आवंटित करने की गिनती नहीं है:

    float *arr = new float[3]{0.4f, 12.5f, 16.234f};
    
    for(auto val: arr) //Compile error.
    {
        std::cout << val << " ";
    }
    
  • किसी भी प्रकार के सदस्य कार्य begin() और end() , जो टाइप के तत्वों में पुनरावृत्तियों को लौटाते हैं। मानक पुस्तकालय कंटेनर योग्य होते हैं, लेकिन उपयोगकर्ता-परिभाषित प्रकारों का उपयोग किया जा सकता है:

    struct Rng
    {
        float arr[3];
    
        // pointers are iterators
        const float* begin() const {return &arr[0];}
        const float* end() const   {return &arr[3];}
        float* begin() {return &arr[0];}
        float* end()   {return &arr[3];}
    };
    
    int main()
    {
        Rng rng = {{0.4f, 12.5f, 16.234f}};
    
        for(auto val: rng)
        {
            std::cout << val << " ";
        }
    }
    
  • कोई भी प्रकार जिसमें गैर-सदस्य begin(type) और end(type) फ़ंक्शन जो type आधार पर तर्क निर्भर लुकअप के माध्यम से पाया जा सकता है। यह श्रेणी प्रकार को संशोधित किए बिना एक श्रेणी प्रकार बनाने के लिए उपयोगी है:

    namespace Mine
    {
        struct Rng {float arr[3];};
    
        // pointers are iterators
        const float* begin(const Rng &rng) {return &rng.arr[0];}
        const float* end(const Rng &rng) {return &rng.arr[3];}
        float* begin(Rng &rng) {return &rng.arr[0];}
        float* end(Rng &rng) {return &rng.arr[3];}
    }
    
    int main()
    {
        Mine::Rng rng = {{0.4f, 12.5f, 16.234f}};
    
        for(auto val: rng)
        {
            std::cout << val << " ";
        }
    }
    

पाश के लिए

एक for पाश में बयान निष्पादित करता है loop body है, जबकि पाश condition सच है। लूप initialization statement से पहले ठीक एक बार निष्पादित किया जाता है। प्रत्येक चक्र के बाद, iteration execution भाग निष्पादित किया जाता है।

लूप के for एक परिभाषित किया गया है:

for (/*initialization statement*/; /*condition*/; /*iteration execution*/)
{
    // body of the loop
}

प्लेसहोल्डर के बयानों की व्याख्या:

  • initialization statement : इस बयान की शुरुआत में केवल एक बार निष्पादित हो जाता है, for पाश। आप एक प्रकार के कई चरों की घोषणा कर सकते हैं, जैसे कि int i = 0, a = 2, b = 3 । ये चर केवल लूप के दायरे में मान्य हैं। लूप के निष्पादन के दौरान एक ही नाम के साथ लूप से पहले परिभाषित चर को छिपा दिया जाता है।
  • condition : यह कथन प्रत्येक लूप बॉडी निष्पादन के आगे मूल्यांकन किया जाता है, और यदि यह false मूल्यांकन करता है तो लूप को रोक देता है।
  • iteration execution : यह बयान, पाश शरीर के बाद मार डाला जाता है, अगले हालत मूल्यांकन के आगे जब तक for पाश शरीर में निरस्त किया गया है (द्वारा break , goto , return या एक अपवाद फेंका जा रहा है)। आप iteration execution भाग में कई कथन दर्ज कर सकते हैं, जैसे कि a++, b+=10, c=b+a

एक के किसी न किसी बराबर for पाश, एक के रूप में लिखा while पाश है:

/*initialization*/
while (/*condition*/)
{
    // body of the loop; using 'continue' will skip to increment part below
    /*iteration execution*/
}

एक का उपयोग कर सबसे सामान्य रूप में for पाश बयान बार की एक विशिष्ट संख्या निष्पादित करने के लिए है। उदाहरण के लिए, निम्नलिखित पर विचार करें:

for(int i = 0; i < 10; i++) {
    std::cout << i << std::endl;
}

एक मान्य लूप भी है:

for(int a = 0, b = 10, c = 20; (a+b+c < 100); c--, b++, a+=c) {
    std::cout << a << " " << b << " " << c << std::endl; 
}

लूप से पहले घोषित चर को छिपाने का एक उदाहरण है:

int i = 99; //i = 99
for(int i = 0; i < 10; i++) { //we declare a new variable i
    //some operations, the value of i ranges from 0 to 9 during loop execution
}
//after the loop is executed, we can access i with value of 99

लेकिन अगर आप पहले से घोषित चर का उपयोग करना चाहते हैं और इसे छिपाना नहीं चाहते हैं, तो घोषणा भाग को छोड़ दें:

int i = 99; //i = 99
for(i = 0; i < 10; i++) { //we are using already declared variable i
    //some operations, the value of i ranges from 0 to 9 during loop execution
}
//after the loop is executed, we can access i with value of 10

टिप्पणियाँ:

  • इनिशियलाइज़ेशन और इन्क्रीमेंट स्टेटमेंट्स, स्टेटमेंट स्टेटमेंट से असंबंधित ऑपरेशन कर सकते हैं, या कुछ भी नहीं - यदि आप ऐसा करना चाहते हैं। लेकिन पठनीयता कारणों के लिए, केवल लूप के लिए सीधे प्रासंगिक संचालन करना सबसे अच्छा अभ्यास है।
  • एक चर प्रारंभ बयान में घोषणा की केवल के दायरे के अंदर दिखाई दे रहा है for पाश और पाश की समाप्ति पर जारी किया गया है।
  • यह मत भूलो कि initialization statement में जो चर घोषित किया गया था, उसे लूप के दौरान संशोधित किया जा सकता है, साथ ही साथ चर को condition में जांचा जा सकता है।

एक लूप का उदाहरण जो 0 से 10 तक गिना जाता है:

for (int counter = 0; counter <= 10; ++counter)
{
    std::cout << counter << '\n';
}
// counter is not accessible here (had value 11 at the end)

कोड अंशों की व्याख्या:

  • int counter = 0 वैरिएबल counter को 0. से इनिशियलाइज़ करता है। (यह वेरिएबल केवल लूप के for इस्तेमाल किया जा सकता है।)
  • counter <= 10 एक बूलियन स्थिति है जो यह जांचती है कि क्या counter 10 से कम या बराबर है। यदि यह true , तो लूप निष्पादित होता है। यदि यह false , तो लूप समाप्त हो जाता है।
  • ++counter एक वेतन वृद्धि ऑपरेशन है जो अगली शर्त की जांच से पहले counter के मूल्य को 1 से बढ़ाता है।

सभी कथनों को खाली छोड़कर, आप एक अनंत लूप बना सकते हैं:

// infinite loop
for (;;)
    std::cout << "Never ending!\n";

while उपरोक्त लूप बराबर है:

// infinite loop
while (true)
    std::cout << "Never ending!\n";

हालांकि, स्टेटमेंट break , goto , या return का उपयोग करके या एक अपवाद फेंककर एक अनंत लूप को अभी भी छोड़ा जा सकता है।

<algorithm> हेडर का उपयोग किए बिना एसटीएल संग्रह (जैसे, एक vector ) से सभी तत्वों पर पुनरावृति का अगला आम उदाहरण है:

std::vector<std::string> names = {"Albert Einstein", "Stephen Hawking", "Michael Ellis"};
for(std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
    std::cout << *it << std::endl;
}

घुमाव के दौरान

एक while पाश कार्यान्वित बयान बार-बार करने के लिए दिया हालत मूल्यांकन करता है जब तक false । यह नियंत्रण कथन तब उपयोग किया जाता है जब यह ज्ञात नहीं होता है, अग्रिम में, कोड के एक ब्लॉक को कितनी बार निष्पादित किया जाना है।

उदाहरण के लिए, सभी नंबरों को 0 से 9 तक प्रिंट करने के लिए, निम्न कोड का उपयोग किया जा सकता है:

int i = 0;
while (i < 10)
{
    std::cout << i << " ";
    ++i; // Increment counter
}
std::cout << std::endl; // End of line; "0 1 2 3 4 5 6 7 8 9" is printed to the console
सी ++ 17

ध्यान दें कि C ++ 17 के बाद से, पहले 2 कथनों को जोड़ा जा सकता है

while (int i = 0; i < 10)
//... The rest is the same

एक अनंत लूप बनाने के लिए, निम्नलिखित निर्माण का उपयोग किया जा सकता है:

while (true)
{
    // Do something forever (however, you can exit the loop by calling 'break'
}

while छोरों का एक और प्रकार है, अर्थात् निर्माण do...while अधिक जानकारी के लिए करते समय लूप उदाहरण देखें।

स्थितियों में चर की घोषणा

के for और while छोरों की स्थिति में, इसे एक वस्तु घोषित करने की भी अनुमति है। लूप के अंत तक इस ऑब्जेक्ट को दायरे में माना जाएगा, और लूप के प्रत्येक पुनरावृत्ति के माध्यम से जारी रहेगा:

for (int i = 0; i < 5; ++i) {
    do_something(i);
}
// i is no longer in scope.

for (auto& a : some_container) {
    a.do_something();
}
// a is no longer in scope.

while(std::shared_ptr<Object> p = get_object()) {
   p->do_something();
}
// p is no longer in scope.

हालाँकि, इसे लूप के साथ करने की अनुमति नहीं do...while लूप; इसके बजाय, लूप से पहले वेरिएबल को घोषित करें, और (वैकल्पिक रूप से) वैरिएबल और लूप दोनों को एक स्थानीय स्कोप के साथ संलग्न करें यदि आप चाहते हैं कि लूप समाप्त होने के बाद वैरिएबल दायरे से बाहर हो जाए:

//This doesn't compile
do {
    s = do_something();
} while (short s > 0);

// Good
short s;
do {
    s = do_something();
} while (s > 0);

ऐसा इसलिए है क्योंकि एक do...while के स्टेटमेंट भाग do...while लूप (लूप की बॉडी) का मूल्यांकन एक्सप्रेशन भाग ( while ) तक पहुंचने से पहले किया जाता है, और इस प्रकार, एक्सप्रेशन का कोई भी ऐलान पहले पुनरावृति के दौरान दिखाई नहीं देगा पाश।

करते-करते पाश

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

निम्न कोड 0 प्रिंट करेगा, क्योंकि पहली पुनरावृत्ति के अंत में स्थिति false मूल्यांकन करेगी:

int i =0;
do
{
    std::cout << i;
    ++i; // Increment counter
}
while (i < 0);
std::cout << std::endl; // End of line; 0 is printed to the console

नोट: while(condition); के अंत में अर्धविराम को मत भूलना while(condition); , जो निर्माण के समय में आवश्यक है।

डू-टाइम लूप के विपरीत, निम्नलिखित कुछ भी प्रिंट नहीं करेगा, क्योंकि पहली पुनरावृत्तियों की शुरुआत में स्थिति false मूल्यांकन करती है:

int i =0;
while (i < 0)
{
    std::cout << i;
    ++i; // Increment counter
}    
std::cout << std::endl; // End of line; nothing is printed to the console

नोट: एक समय में एक break , goto , या return स्टेटमेंट का उपयोग करके लूप को शर्त के बिना बाहर निकाला जा सकता है।

int i = 0;
do
{
    std::cout << i;
    ++i; // Increment counter
    if (i > 5) 
    {
        break;
    }
}
while (true);
std::cout << std::endl; // End of line; 0 1 2 3 4 5 is printed to the console

एक तुच्छ काम करते समय लूप को कभी-कभी मैक्रोज़ लिखने के लिए भी उपयोग किया जाता है, जिसमें उनके स्वयं के दायरे की आवश्यकता होती है (जिस स्थिति में अनुगामी अर्धविराम को स्थूल परिभाषा से हटा दिया जाता है और उपयोगकर्ता द्वारा प्रदान किए जाने की आवश्यकता होती है):

#define BAD_MACRO(x) f1(x); f2(x); f3(x);

// Only the call to f1 is protected by the condition here
if (cond) BAD_MACRO(var);

#define GOOD_MACRO(x) do { f1(x); f2(x); f3(x); } while(0)

// All calls are protected here
if (cond) GOOD_MACRO(var);

लूप नियंत्रण कथन: विराम और जारी रखें

इसके सामान्य अनुक्रम से निष्पादन के प्रवाह को बदलने के लिए लूप नियंत्रण बयानों का उपयोग किया जाता है। जब निष्पादन एक गुंजाइश छोड़ देता है, तो उस दायरे में बनाए गए सभी स्वचालित ऑब्जेक्ट नष्ट हो जाते हैं। break और continue लूप नियंत्रण कथन हैं।

break कथन बिना किसी और विचार के एक लूप को समाप्त कर break

for (int i = 0; i < 10; i++)
{
    if (i == 4)
        break; // this will immediately exit our loop
    std::cout << i << '\n';
}

उपरोक्त कोड प्रिंट होगा:

1
2
3

continue बयान तुरंत लूप से बाहर नहीं निकलता है, बल्कि बाकी लूप शरीर को छोड़ देता है और लूप के शीर्ष पर जाता है (स्थिति की जांच सहित)।

for (int i = 0; i < 6; i++)
{
    if (i % 2 == 0) // evaluates to true if i is even
        continue; // this will immediately go back to the start of the loop
    /* the next line will only be reached if the above "continue" statement 
       does not execute  */
    std::cout << i << " is an odd number\n";
}

उपरोक्त कोड प्रिंट होगा:

1 is an odd number
3 is an odd number
5 is an odd number

क्योंकि इस तरह के नियंत्रण प्रवाह परिवर्तन कभी-कभी मनुष्यों को आसानी से समझने, break और continue लिए मुश्किल से उपयोग किए जाते हैं। अधिक सरल कार्यान्वयन आमतौर पर पढ़ने और समझने में आसान होते हैं। उदाहरण के लिए, ऊपर के break साथ लूप के for पहले for फिर से लिखा जा सकता है:

for (int i = 0; i < 4; i++)
{
    std::cout << i << '\n';
}

continue साथ दूसरा उदाहरण फिर से लिखा जा सकता है:

for (int i = 0; i < 6; i++)
{
    if (i % 2 != 0) {
        std::cout << i << " is an odd number\n";
    }
}

रेंज-के लिए एक उप-रेंज

रेंज-बेस लूप का उपयोग करते हुए, आप किसी दिए गए कंटेनर या अन्य श्रेणी के उप-भाग पर एक प्रॉक्सी ऑब्जेक्ट उत्पन्न करके लूप कर सकते हैं जो लूप के लिए रेंज-आधारित के लिए अर्हता प्राप्त करता है।

template<class Iterator, class Sentinel=Iterator>
struct range_t {
  Iterator b;
  Sentinel e;
  Iterator begin() const { return b; }
  Sentinel end() const { return e; }
  bool empty() const { return begin()==end(); }
  range_t without_front( std::size_t count=1 ) const {
    if (std::is_same< std::random_access_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category >{} ) {
      count = (std::min)(std::size_t(std::distance(b,e)), count);
    }
    return {std::next(b, count), e};
  }
  range_t without_back( std::size_t count=1 ) const {
    if (std::is_same< std::random_access_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category >{} ) {
      count = (std::min)(std::size_t(std::distance(b,e)), count);
    }
    return {b, std::prev(e, count)};
  }
};

template<class Iterator, class Sentinel>
range_t<Iterator, Sentinel> range( Iterator b, Sentinal e ) {
  return {b,e};
}
template<class Iterable>
auto range( Iterable& r ) {
  using std::begin; using std::end;
  return range(begin(r),end(r));
}

template<class C>
auto except_first( C& c ) {
  auto r = range(c);
  if (r.empty()) return r;
  return r.without_front();
}

अब हम कर सकते हैं:

std::vector<int> v = {1,2,3,4};

for (auto i : except_first(v))
  std::cout << i << '\n';

और प्रिंट आउट लें

2
3
4

ध्यान रखें कि लूप के for उत्पन्न मध्यवर्ती ऑब्जेक्ट for(:range_expression) भाग में लूप शुरू for के समय तक समाप्त हो जाएगा।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow