2016-03-23 5 views
8

मुझे सी ++ के सीखने में एक समस्या आई है, जहां स्थानीय चर में एक स्थानीय चर को एक दूसरे नाम में उसी नाम के साथ पारित किया जा रहा है, ये दोनों कार्य मुख्य में चलते हैं()।स्थानीय वैरिएबल को पास किया जा रहा है (सी ++)

जब ऐसा चलाया जाता है,

#include <iostream> 
using namespace std; 

void next(); 
void again(); 

int main() 
{ 
    int a = 2; 
    cout << a << endl; 
    next(); 
    again(); 
    return 0; 
} 

void next() 
{ 
    int a = 5; 
    cout << a << endl; 
} 

void again() 
{ 
    int a; 
    cout << a << endl; 
} 

यह आउटपुट:

2 
5 
5 

मुझे लगता है कि फिर से उम्मीद() अशक्त या 0 के बाद से 'एक' वहाँ फिर से घोषित किया जाता है कह सकते हैं कि, और अभी तक ऐसा लगता है उस मान का उपयोग करने के लिए जो 'ए' को अगले() में असाइन किया गया था।

अगला() स्थानीय चर 'ए' के ​​मान को फिर से() फिर से क्यों पास करता है यदि) 'ए' को फिर से एक बार घोषित किया जाता है()?

+3

कुछ भी पास नहीं हुआ। 'ए' में फिर से() 'प्रारंभ नहीं किया गया था, कोई भी मूल्य संभव है। – songyuanyao

+0

सहमत हैं इसलिए 'ए' का मान अपरिभाषित व्यवहार है। – drescherjm

उत्तर

7

http://en.cppreference.com/w/cpp/language/ub

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

1

यह पूरी तरह से संयोग और अपरिभाषित व्यवहार है।

क्या हुआ है कि आपके पास एक दूसरे के तुरंत बाद दो कार्य हैं। दोनों में कम या समान समान फ़ंक्शन प्रोलॉग होंगे और दोनों स्टैक पर बिल्कुल उसी आकार के एक चर को आरक्षित करेंगे।

चूंकि नाटक में कोई अन्य चर नहीं है और कॉल के बीच स्टैक को संशोधित नहीं किया गया है, तो आप पिछले फ़ंक्शन के स्थानीय चर के समान स्थान पर दूसरे फ़ंक्शन "लैंडिंग" में स्थानीय चर के साथ समाप्त हो जाते हैं।

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

5

एक अप्रारंभीकृत गैर static* (एक कौर ओफ़्फ़! कि था) में निर्मित प्रकार के स्थानीय चर एक अनिश्चित मूल्य है। char प्रकारों के अलावा, उस मान का उपयोग औपचारिक रूप से अपरिभाषित व्यवहार, a.k.a. यूबी उत्पन्न करता है। जो कुछ भी आप देखते हैं उसके साथ कुछ भी हो सकता है।

अपने संकलक और विकल्प, ढेर क्षेत्र है कि next की कॉल में a के लिए इस्तेमाल किया गया था, साथ

जाहिर साथ again की कॉल, जहां यह again में a के लिए पुन: उपयोग किया गया था जब तक कुछ और के लिए इस्तेमाल नहीं किया गया था, अब पहले के समान मूल्य।

लेकिन आप उस पर भरोसा नहीं कर सकते हैं। यूबी के साथ कुछ भी, या कुछ भी नहीं हो सकता है।


* या पॉड प्रकार के और अधिक आम तौर पर, सादा पुराना डाटा। इसका मानक विनिर्देश कुछ जटिल है। सी ++ 11 में यह §8.5/11 के साथ शुरू होता है, "यदि किसी ऑब्जेक्ट के लिए कोई प्रारंभकर्ता निर्दिष्ट नहीं है, तो ऑब्जेक्ट डिफ़ॉल्ट-प्रारंभ होता है; यदि कोई प्रारंभिकता नहीं की जाती है, तो स्वचालित या गतिशील संग्रहण अवधि वाले ऑब्जेक्ट में अनिश्चित मूल्य होता है। " जहां "स्वचालित और नरक; भंडारण अवधि "में स्थानीय गैर -static चर के मामले शामिल हैं। और जहां "प्रारंभिकरण" §8.5/6 के माध्यम से दो तरीकों से नहीं हो सकता है जो डिफ़ॉल्ट प्रारंभिक परिभाषा को परिभाषित करता है, यानी या तो कुछ भी नहीं, डिफ़ॉल्ट कन्स्ट्रक्टर के माध्यम से, या ऑब्जेक्ट के माध्यम से कक्षा या सरणी प्रकार के नहीं।

संबंधित मुद्दे