किसी सरणी को सीमा से बाहर पहुँचाना कोई त्रुटि नहीं है, क्यों?


177

मैं सी + + प्रोग्राम में मूल्यों को इस तरह से सीमा से बाहर कर रहा हूं:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    return 0;
}

कार्यक्रम प्रिंट 3और 4। यह संभव नहीं होना चाहिए। मैं g ++ 4.3.3 का उपयोग कर रहा हूं

यहाँ संकलन और रन कमांड है

$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4

केवल असाइन करते समय array[3000]=3000यह मुझे एक विभाजन दोष देता है।

अगर gcc सरणी सीमाओं की जाँच नहीं करता है, तो मुझे कैसे यकीन हो सकता है कि मेरा कार्यक्रम सही है, क्योंकि यह बाद में कुछ गंभीर मुद्दों को जन्म दे सकता है?

मैंने उपरोक्त कोड को बदल दिया है

vector<int> vint(2);
vint[0] = 0;
vint[1] = 1;
vint[2] = 2;
vint[5] = 5;
cout << vint[2] << endl;
cout << vint[5] << endl;

और यह भी कोई त्रुटि नहीं पैदा करता है।


3
संबंधित प्रश्न: stackoverflow.com/questions/671703/…
TSomKes

16
कोड निश्चित रूप से छोटी गाड़ी है, लेकिन यह अपरिभाषित व्यवहार उत्पन्न करता है। अनिर्धारित का मतलब है कि यह पूरा होने के लिए दौड़ सकता है या नहीं। दुर्घटना की कोई गारंटी नहीं है।
dmckee --- पूर्व-संचालक बिल्ली का बच्चा

4
आप सुनिश्चित कर सकते हैं कि आपका प्रोग्राम कच्ची सरणियों के साथ खराब न होकर सही है। सी ++ प्रोग्रामर को एम्बेडेड / ओएस प्रोग्रामिंग को छोड़कर, कंटेनर कक्षाओं का उपयोग करना चाहिए। उपयोगकर्ता कंटेनरों के कारणों के लिए इसे पढ़ें। parashift.com/c++-faq-lite/containers.html
jkeys

8
यह ध्यान रखें कि वैक्टर जरूरी नहीं है [] का उपयोग करके जाँच करें। .At () का उपयोग करना [] के समान कार्य करता है, लेकिन रेंज-चेक करता है।
डेविड थॉर्नले

4
ए -आउट-ऑफ-बाउंड्स तत्वों तक पहुँचने पर ऑटो-आकार vector नहीं देता है ! यह सिर्फ यूबी है!
पावेल मिनेव

जवाबों:


364

हर C / C ++ प्रोग्रामर के सबसे अच्छे दोस्त का स्वागत: अपरिभाषित व्यवहार

कई कारणों से बहुत कुछ ऐसा है जो भाषा मानक द्वारा निर्दिष्ट नहीं है। यह उनमें से एक है।

सामान्य तौर पर, जब भी आपका अपरिभाषित व्यवहार होता है, तो कुछ भी हो सकता है। एप्लिकेशन क्रैश हो सकता है, यह जम सकता है, यह आपकी सीडी-रॉम ड्राइव को बाहर कर सकता है या राक्षसों को आपकी नाक से बाहर निकाल सकता है। यह आपकी हार्डड्राइव को प्रारूपित कर सकता है या आपकी सभी पोर्न को आपकी दादी को ईमेल कर सकता है।

यह भी, यदि आप वास्तव में अशुभ हैं, हो सकता है दिखाई देते हैं सही ढंग से काम करने के लिए।

भाषा बस यह कहती है कि यदि आप किसी ऐरे की सीमा के भीतर तत्वों को एक्सेस करते हैं तो क्या होना चाहिए । यह अपरिभाषित छोड़ दिया जाता है यदि आप सीमा से बाहर जाते हैं तो क्या होता है। यह आपके कंपाइलर पर आज काम कर सकता है , लेकिन यह कानूनी C या C ++ नहीं है, और इस बात की कोई गारंटी नहीं है कि यह अगली बार जब आप प्रोग्राम चलाएंगे तब भी काम करेंगे। या यह नहीं ओवरराइट आवश्यक डेटा अब भी है, और तुम सिर्फ समस्याओं का सामना नहीं किया है, कि यह है कि है कारण के लिए जा रहा - अभी तक।

जैसे कि कोई सीमा की जाँच क्यों नहीं हो रही है, उत्तर के लिए कुछ पहलू हैं:

  • एक सरणी C. से एक बचे हुए हैं। सी सरणियों के बारे में आदिम हैं जैसा कि आप प्राप्त कर सकते हैं। सन्निहित पतों वाले तत्वों का सिर्फ एक क्रम। कोई सीमा जाँच नहीं है क्योंकि यह केवल कच्ची मेमोरी को उजागर कर रहा है। एक मजबूत सीमा-जाँच तंत्र को लागू करना C में लगभग असंभव होता।
  • सी ++ में, वर्ग प्रकारों पर सीमा-जाँच संभव है। लेकिन एक सरणी अभी भी सादे पुराने सी-संगत है। यह कोई वर्ग नहीं है। इसके अलावा, C ++ एक अन्य नियम पर भी बनाया गया है जो सीमा-जाँच को गैर-आदर्श बनाता है। C ++ मार्गदर्शक सिद्धांत "आप जो उपयोग नहीं करते हैं उसके लिए भुगतान नहीं करते हैं"। यदि आपका कोड सही है, तो आपको सीमा-जाँच की आवश्यकता नहीं है, और आपको रन-टाइम सीमा-जाँच के ओवरहेड के लिए भुगतान करने के लिए मजबूर नहीं किया जाना चाहिए।
  • तो C ++ std::vectorक्लास टेम्पलेट प्रदान करता है , जो दोनों की अनुमति देता है। operator[]कुशल बनाया गया है। भाषा मानक की आवश्यकता नहीं है कि यह सीमा जाँच करता है (हालाँकि यह इसे मना भी नहीं करता है)। एक वेक्टर में at()सदस्य फ़ंक्शन भी होता है जिसे सीमा-जाँच करने की गारंटी दी जाती है । तो C ++ में, यदि आप वेक्टर का उपयोग करते हैं, तो आपको दोनों दुनिया में सबसे अच्छा मिलता है। बिना सीमा-जाँच के आपको सरणी-जैसा प्रदर्शन मिलता है , और जब आप चाहते हैं, तब आपको सीमा-जाँच पहुँच का उपयोग करने की क्षमता मिलती है।

5
@ जयफ: हम इस अरेंज चीज का इतने लंबे समय से उपयोग कर रहे हैं, लेकिन फिर भी इस तरह की सरल त्रुटि की जांच करने के लिए कोई टेस्ट क्यों नहीं हैं?
seg.server.fault 16

7
C ++ डिज़ाइन सिद्धांत यह था कि यह बराबर C कोड से धीमा नहीं होना चाहिए, और C सरणी बाउंड चेकिंग नहीं करता है। सी डिजाइन सिद्धांत मूल रूप से गति था क्योंकि यह सिस्टम प्रोग्रामिंग के लिए लक्षित था। Array बाउंड चेकिंग में समय लगता है, और ऐसा नहीं किया जाता है। C ++ में अधिकांश उपयोगों के लिए, आपको वैसे भी सरणी के बजाय एक कंटेनर का उपयोग करना चाहिए, और आपके पास क्रमशः .at () या [] के माध्यम से किसी तत्व तक पहुँचने के लिए बाध्य चेक या कोई बाध्य चेक नहीं हो सकता है।
KTC

4
@ ऐसे चेक से कुछ खर्च होता है। यदि आप सही कोड लिखते हैं, तो आप उस कीमत का भुगतान नहीं करना चाहते हैं। यह कहने के बाद, मैं std :: वेक्टर की () विधि के लिए एक पूर्ण रूपांतरित हो गया हूं, जिसे IS ने जांचा है। इसका उपयोग करने से मुझे लगा कि "सही" कोड था, उसमें कुछ त्रुटियां हैं।

10
मेरा मानना ​​है कि जीसीसी के पुराने संस्करणों ने वास्तव में Emacs और हनोई के टावर्स का एक सिमुलेशन लॉन्च किया था, जब इसने कुछ प्रकार के अपरिभाषित व्यवहार का सामना किया था। जैसा मैंने कहा, कुछ भी हो सकता है। ;)
जलफ

4
हर बात पहले से ही कही गई है, इसलिए यह केवल एक छोटा सा परिशिष्ट है। रिलीज बिल्ड की तुलना में इन परिस्थितियों में डिबग बिल्ड बहुत क्षमाशील हो सकते हैं। डिबग जानकारी को डिबग बायनेरी में शामिल किए जाने के कारण, एक मौका कम है कि कुछ महत्वपूर्ण ओवरराइट किया गया है। यही कारण है कि कभी-कभी डिबग बिल्ड ठीक काम करने लगता है जबकि रिलीज बिल्ड क्रैश।
रिच

31

G ++ का उपयोग करके, आप कमांड लाइन विकल्प जोड़ सकते हैं -fstack-protector-all:।

आपके उदाहरण पर इसका परिणाम निम्न आया:

> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault      ./t

यह वास्तव में समस्या को खोजने या हल करने में आपकी मदद नहीं करता है, लेकिन कम से कम segfault आपको बताएगा कि कुछ गलत है।


10
मुझे अभी भी एक बेहतर विकल्प मिला: -fmflflap
Hi-Angel

1
@ हाय-एंजेल: आधुनिक समतुल्य है -fsanitize=addressजो इस बग को संकलन समय (यदि अनुकूलन) और रनटाइम पर दोनों पकड़ता है।
नैट एल्ड्रेडज

@NateEldredge +1, आजकल मैं भी उपयोग करता हूं -fsanitize=undefined,address। लेकिन यह ध्यान देने योग्य है कि std पुस्तकालय के साथ दुर्लभ कोने के मामले हैं, जब सीमा से बाहर पहुंच प्रक्षालक द्वारा पता नहीं लगाया जाता है । इस कारण से मैं इसके अतिरिक्त -D_GLIBCXX_DEBUGविकल्प का उपयोग करने की सलाह दूंगा, जो और भी अधिक चेक जोड़ता है।
हाय-एंजेल

12

जी ++ सरणी सीमा के लिए जाँच नहीं करता है, और आप 3,4 के साथ कुछ ओवरराइट कर सकते हैं, लेकिन वास्तव में महत्वपूर्ण कुछ भी नहीं है, यदि आप उच्च संख्या के साथ प्रयास करते हैं तो आपको एक दुर्घटना मिलेगी।

आप स्टैक के कुछ हिस्सों को अधिलेखित कर रहे हैं जिनका उपयोग नहीं किया जाता है, आप तब तक जारी रख सकते हैं जब तक आप स्टैक के लिए आवंटित स्थान के अंत तक नहीं पहुंच जाते और यह अंततः दुर्घटनाग्रस्त हो जाएगा।

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


6
यदि आप उस से प्राप्त करते हैं तो सरणी के पते पर [3] और सरणी [4], "वास्तव में महत्वपूर्ण कुछ भी नहीं है" ??
namezero

7

यह अपरिभाषित व्यवहार है जहाँ तक मुझे पता है। उस के साथ एक बड़ा कार्यक्रम चलाएं और यह रास्ते में कहीं दुर्घटनाग्रस्त हो जाएगा। सीमा जाँच कच्ची सरणियों (या यहां तक ​​कि std :: वेक्टर) का हिस्सा नहीं है।

std::vector::iteratorइसके बजाय std :: वेक्टर का उपयोग करें ताकि आपको इसके बारे में चिंता न करनी पड़े।

संपादित करें:

बस मनोरंजन के लिए, इसे चलाएं और देखें कि आप कितनी देर तक दुर्घटनाग्रस्त होते हैं:

int main()
{
   int array[1];

   for (int i = 0; i != 100000; i++)
   {
       array[i] = i;
   }

   return 0; //will be lucky to ever reach this
}

EDIT2:

वह मत चलाना।

Edit3:

ठीक है, यहाँ सरणियों और संकेतकर्ताओं के साथ उनके संबंधों पर एक त्वरित पाठ दिया गया है:

जब आप सरणी अनुक्रमण का उपयोग करते हैं, तो आप वास्तव में एक भेस में एक सूचक का उपयोग कर रहे हैं (जिसे "संदर्भ" कहा जाता है), जो स्वचालित रूप से सुरक्षित है। यही कारण है कि * (सरणी [1]) के बजाय, सरणी [1] स्वचालित रूप से उस मूल्य पर मूल्य लौटाता है।

जब आपके पास एक सरणी के लिए एक सूचक होता है, तो इस तरह:

int array[5];
int *ptr = array;

फिर दूसरी घोषणा में "सरणी" वास्तव में एक सूचक को पहले सरणी के लिए क्षय कर रहा है। यह इसके लिए समान व्यवहार है:

int *ptr = &array[0];

जब आप जो आवंटित करते हैं, उससे परे एक्सेस करने का प्रयास करते हैं, तो आप वास्तव में केवल एक पॉइंटर को अन्य मेमोरी (जो C ++ के बारे में शिकायत नहीं करेंगे) का उपयोग कर रहे हैं। मेरे उदाहरण कार्यक्रम को ऊपर ले जाना, जो इस के बराबर है:

int main()
{
   int array[1];
   int *ptr = array;

   for (int i = 0; i != 100000; i++, ptr++)
   {
       *ptr++ = i;
   }

   return 0; //will be lucky to ever reach this
}

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


3
मुझे लगता है कि आप वहां अपने अंतिम उदाहरण में "ptr" बढ़ाना भूल गए। आपने गलती से कुछ अच्छी तरह से परिभाषित कोड का उत्पादन किया है।
जेफ लेक

1
Haha, देखें कि आपको कच्चे सरणियों का उपयोग क्यों नहीं करना चाहिए?
jkeys 16

"यही कारण है कि * (सरणी [1]) के बजाय, सरणी [1] स्वचालित रूप से उस मूल्य पर मूल्य लौटाता है।" क्या आप सुनिश्चित हैं * (सरणी [1]) ठीक से काम करेंगे? मुझे लगता है कि यह * (सरणी + 1) होना चाहिए। ps: योग्य, यह अतीत को एक संदेश भेजने की तरह है। लेकिन, वैसे भी:
muyustan

5

संकेत

आप सीमा त्रुटि चेक के साथ तेजी से बाधा आकार सरणियों करना चाहते हैं, का उपयोग कर की कोशिश बढ़ावा :: सरणी , (भी std :: tr1 :: सरणी से <tr1/array>यह अगले सी ++ विनिर्देश में मानक कंटेनर हो जाएगा)। यह बहुत तेज है तो std :: वेक्टर। यह ढेर या अंदर की श्रेणी की याददाश्त को आरक्षित करता है, ठीक उसी तरह जैसे इंट []।
यह सरल नमूना कोड है:

#include <iostream>
#include <boost/array.hpp>
int main()
{
    boost::array<int,2> array;
    array.at(0) = 1; // checking index is inside range
    array[1] = 2;    // no error check, as fast as int array[2];
    try
    {
       // index is inside range
       std::cout << "array.at(0) = " << array.at(0) << std::endl;

       // index is outside range, throwing exception
       std::cout << "array.at(2) = " << array.at(2) << std::endl; 

       // never comes here
       std::cout << "array.at(1) = " << array.at(1) << std::endl;  
    }
    catch(const std::out_of_range& r)
    {
        std::cout << "Something goes wrong: " << r.what() << std::endl;
    }
    return 0;
}

यह कार्यक्रम प्रिंट होगा:

array.at(0) = 1
Something goes wrong: array<>: index out of range

4

C या C ++ किसी ऐरे एक्सेस के सीमा की जाँच नहीं करेगा।

आप स्टैक पर सरणी आवंटित कर रहे हैं। के माध्यम से सरणी को अनुक्रमण array[3]करना * के बराबर है (array + 3), जहां सरणी & सरणी के लिए एक संकेतक है [0]। इसके परिणामस्वरूप अपरिभाषित व्यवहार होगा।

सी में कभी-कभी इसे पकड़ने का एक तरीका एक स्थिर चेकर का उपयोग करना है, जैसे स्प्लिंट । यदि आप चलाते हैं:

splint +bounds array.c

पर,

int main(void)
{
    int array[1];

    array[1] = 1;

    return 0;
}

तब आपको चेतावनी मिलेगी:

array.c: (फ़ंक्शन मेन में) array.c: 5: 9: संभवतः आउट-ऑफ-बाउंड्स स्टोर: सरणी [1] बाधा को हल करने में असमर्थ: पूर्व शर्त को संतुष्ट करने के लिए 0> = 1 की आवश्यकता होती है: मैक्ससेट (सरणी) की आवश्यकता होती है .c: 5: 9)> = 1 एक मेमोरी राइट आवंटित बफर से परे एक पते पर लिख सकता है।


सुधार: यह पहले से ही ओएस या किसी अन्य कार्यक्रम द्वारा आवंटित किया गया है। वह अन्य मेमोरी को ओवरराइट कर रहा है।
jkeys

1
यह कहना कि "C / C ++ सीमा की जांच नहीं करेगा" पूरी तरह से सही नहीं है - ऐसा करने से किसी विशेष अनुपालन कार्यान्वयन को रोकने के लिए कुछ भी नहीं है, या तो डिफ़ॉल्ट रूप से, या कुछ संकलन झंडे के साथ। यह सिर्फ इतना है कि उनमें से कोई भी परेशान नहीं करता है।
पावेल मिनेव

3

आप अपने स्टैक को निश्चित रूप से अधिलेखित कर रहे हैं, लेकिन कार्यक्रम सरल है कि इस पर किसी का ध्यान नहीं जाता है।


2
प्लेटफॉर्म पर स्टैक ओवरराइट किया गया है या नहीं, यह निर्भर करता है।
क्रिस क्लेलैंड

3

Valgrind के माध्यम से इसे चलाएं और आपको एक त्रुटि दिखाई दे सकती है।

जैसा कि फलैना ने बताया, वैलेग्रिड ढेर भ्रष्टाचार के कई उदाहरणों का पता नहीं लगाता है। मैंने सिर्फ वेलग्रिंड के तहत नमूने की कोशिश की, और यह वास्तव में शून्य त्रुटियों की रिपोर्ट करता है। हालाँकि, Valgrind कई अन्य प्रकार की स्मृति समस्याओं को खोजने में महत्वपूर्ण भूमिका निभा सकता है, यह इस मामले में विशेष रूप से उपयोगी नहीं है जब तक कि आप --stack-check विकल्प को शामिल करने के लिए अपने bulid को संशोधित न करें। यदि आप नमूना बनाते हैं और चलाते हैं

g++ --stack-check -W -Wall errorRange.cpp -o errorRange
valgrind ./errorRange

valgrind एक त्रुटि की रिपोर्ट करेगा


2
दरअसल, स्टैक पर गलत एरे एक्सेस का निर्धारण करने के लिए वेलग्रिंड काफी खराब है। (और सही तो यह है, सबसे अच्छा यह कर सकता है कि पूरे स्टैक को एक वैध लेखन स्थान के रूप में चिह्नित किया जाए)
फलेना

@Falaina - अच्छी बात है, लेकिन Valgrind कम से कम कुछ स्टैक त्रुटियों का पता लगा सकता है।
टोड स्टाउट

और वाल्ग्रिंड कोड के साथ कुछ भी गलत नहीं देखेगा क्योंकि कंपाइलर सरणी को अनुकूलित करने के लिए काफी स्मार्ट है और बस एक शाब्दिक 3 और 4 का उत्पादन करता है। यह अनुकूलन इससे पहले होता है कि gcc सरणी सीमा की जाँच करता है जिसके कारण आउट-ऑफ-बाउंड्स चेतावनी gcc करता है नहीं दिखाया गया है।
गोसविन वॉन ब्रेडरलो

2

आपके पक्ष में काम कर रहे अपरिभाषित व्यवहार। जो कुछ भी स्मृति आप कर रहे हैं स्पष्ट रूप से कुछ भी महत्वपूर्ण पकड़ नहीं है। ध्यान दें कि C और C ++ सरणियों पर जाँच नहीं करते हैं, इसलिए ऐसा सामान संकलन या चलाने के समय पकड़ा नहीं जाएगा।


5
नहीं, अपरिभाषित व्यवहार "आपके पक्ष में काम करता है" जब यह सफाई से दुर्घटनाग्रस्त हो जाता है। जब यह काम करने लगता है, तो यह सबसे खराब स्थिति के बारे में है।
jalf

@ जॉनबोड: तब बेहतर होगा जब आप जलेफ़ की टिप्पणी के अनुसार शब्दों को सही करेंगे
डिस्ट्रक्टोरर

1

जब आप सरणी को आरंभीकृत करते हैं int array[2], तो 2 पूर्णांक के लिए स्थान आवंटित किया जाता है; लेकिन पहचानकर्ता arrayबस उस स्थान की शुरुआत की ओर इशारा करता है। जब आप तब पहुंचते हैं array[3]और array[4]संकलक तब केवल उस पते को बढ़ाते हैं जहां यह इंगित करने के लिए कि वे मान कहाँ होंगे, यदि सरणी लंबे समय तक पर्याप्त थी; array[42]किसी चीज़ को पहले एक्सेस किए बिना इसे एक्सेस करने की कोशिश करें , आपको उस स्थान पर पहले से ही मेमोरी में जो कुछ भी हुआ है, वह समाप्त हो जाएगा।

संपादित करें:

संकेत / सरणियों पर अधिक जानकारी: http://home.netcom.com/~tjensen/ptr/pointers.htm


0

जब आप int सरणी घोषित करते हैं [2]; आप 4 बाइट्स (32 बिट प्रोग्राम) के 2 मेमोरी स्पेस आरक्षित करते हैं। यदि आप अपने कोड में सरणी [4] टाइप करते हैं, तो यह अभी भी एक वैध कॉल से मेल खाता है, लेकिन केवल रन टाइम पर ही यह अनहेल्डेड अपवाद को फेंक देगा। C ++ मैन्युअल मेमोरी प्रबंधन का उपयोग करता है। यह वास्तव में एक सुरक्षा दोष है जिसका उपयोग हैकिंग कार्यक्रमों के लिए किया गया था

यह समझने में मदद कर सकता है:

int * somepointer;

somepointer [0] = somepointer [5];


0

जैसा कि मैं समझता हूं, स्थानीय चर स्टैक पर आवंटित किए जाते हैं, इसलिए अपने स्वयं के स्टैक पर सीमा से बाहर जाना केवल कुछ अन्य स्थानीय चर को अधिलेखित कर सकता है, जब तक कि आप बहुत अधिक नहीं जाते हैं और आपके स्टैक आकार से अधिक हो जाते हैं। चूंकि आपके पास आपके फ़ंक्शन में कोई अन्य चर घोषित नहीं किया गया है - यह किसी भी दुष्प्रभाव का कारण नहीं है। अपने पहले वाले के ठीक बाद एक और चर / सरणी घोषित करने का प्रयास करें और देखें कि इसके साथ क्या होगा।


0

जब आप C में 'array [index]' लिखते हैं तो इसे मशीन के निर्देशों में बदल देता है।

अनुवाद कुछ इस प्रकार है:

  1. 'सरणी का पता प्राप्त करें'
  2. 'वस्तुओं के प्रकार का आकार प्राप्त करें सरणी' से बना है
  3. 'अनुक्रमणिका के प्रकार का आकार गुणा करें'
  4. 'परिणाम को सरणी के पते पर जोड़ें'
  5. 'पढ़िए परिणामी पते पर क्या है'

परिणाम कुछ ऐसा है जो सरणी का हिस्सा हो सकता है या नहीं हो सकता है। मशीन निर्देशों की धधकती गति के बदले में आप कंप्यूटर के सुरक्षा जाल को खो देते हैं जो आपके लिए चीजों की जाँच करता है। यदि आप सावधानीपूर्वक और सावधान हैं तो यह कोई समस्या नहीं है। यदि आप मैला हैं या आप गलती से जल गए हैं। कभी-कभी यह एक अमान्य निर्देश उत्पन्न कर सकता है जो अपवाद का कारण बनता है, कभी-कभी नहीं।


0

एक अच्छा तरीका जो मैंने अक्सर देखा है और मुझे वास्तव में इस्तेमाल किया गया था वह uint THIS_IS_INFINITY = 82862863263;सरणी के अंत में कुछ NULL प्रकार तत्व (या एक निर्मित, जैसे ) को इंजेक्ट करने के लिए है ।

फिर लूप कंडीशन चेक में, TYPE *pagesWordsकुछ प्रकार का पॉइंटर सरणी है:

int pagesWordsLength = sizeof(pagesWords) / sizeof(pagesWords[0]);

realloc (pagesWords, sizeof(pagesWords[0]) * (pagesWordsLength + 1);

pagesWords[pagesWordsLength] = MY_NULL;

for (uint i = 0; i < 1000; i++)
{
  if (pagesWords[i] == MY_NULL)
  {
    break;
  }
}

यदि सरणी प्रकार से भरा हुआ है तो यह समाधान शब्द नहीं करेगा struct


0

जैसा कि अब इस प्रश्न में उल्लेख किया गया है कि std :: वेक्टर :: का उपयोग करने से समस्या हल हो जाएगी और पहुँचने से पहले एक बाध्य जाँच होगी।

यदि आपको एक स्थिर आकार सरणी की आवश्यकता है जो स्टैक पर स्थित है क्योंकि आपका पहला कोड C ++ 11 नए कंटेनर std :: array का उपयोग करता है; वेक्टर के रूप में कार्य में std :: array :: है। वास्तव में फ़ंक्शन सभी मानक कंटेनरों में मौजूद है जिसमें इसका एक अर्थ है, अर्थात, जहां ऑपरेटर [] परिभाषित किया गया है :( डीके, मैप, अनऑर्डरेड_मैप) एसटीडी के अपवाद के साथ :: बिटसेट जिसमें इसे एसटी :: बिटसेट कहा जाता है: :परीक्षा।


0

libstdc ++, जो gcc का हिस्सा है, में त्रुटि जाँच के लिए एक विशेष डीबग मोड है । यह संकलक ध्वज द्वारा सक्षम है -D_GLIBCXX_DEBUG। अन्य बातों के अलावा, यह std::vectorप्रदर्शन की कीमत पर जाँच करता है । यहाँ gcc के हालिया संस्करण के साथ ऑनलाइन डेमो है

तो वास्तव में आप libstdc ++ डीबग मोड के साथ जाँच कर सकते हैं, लेकिन आपको इसे केवल परीक्षण करते समय करना चाहिए क्योंकि यह सामान्य libstdc ++ मोड की तुलना में उल्लेखनीय प्रदर्शन की लागत है।


0

यदि आप अपना कार्यक्रम थोड़ा बदलते हैं:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    INT NOTHING;
    CHAR FOO[4];
    STRCPY(FOO, "BAR");
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    COUT << FOO << ENDL;
    return 0;
}

(राजधानियों में परिवर्तन - यदि आप इसे आज़माने जा रहे हैं तो निम्न स्थिति में रखें।)

आप देखेंगे कि वेरिएबल फू को ट्रैश किया गया है। आपका कोड मानों को किसी भी समवर्ती सरणी [3] और सरणी [4] में संग्रहीत करेगा , और उन्हें ठीक से पुनर्प्राप्त करने में सक्षम होगा, लेकिन उपयोग किया जाने वाला वास्तविक भंडारण foo से होगा ।

तो आप अपने मूल उदाहरण में सरणी की सीमाओं को पार करने के साथ "दूर हो सकते हैं", लेकिन कहीं और नुकसान पहुंचाने की कीमत पर - क्षति जो निदान करने के लिए बहुत कठिन साबित हो सकती है ।

जैसे कि कोई स्वचालित सीमा जाँच क्यों नहीं है - एक सही ढंग से लिखे गए कार्यक्रम की आवश्यकता नहीं है। एक बार ऐसा करने के बाद, रन-टाइम सीमा की जाँच करने का कोई कारण नहीं है और ऐसा करने से कार्यक्रम धीमा हो जाएगा। सबसे अच्छा है कि सभी को डिजाइन और कोडिंग के दौरान पता चले।

C ++ C पर आधारित है, जिसे यथासंभव असेंबली लैंग्वेज के लिए डिज़ाइन किया गया था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.