2016-03-23 73 views
8

Ich habe ein Problem in meinem Lernen von C++, wo eine lokale Variable in einer Funktion an die lokale Variable mit dem gleichen Namen in einer anderen Funktion übergeben wird, beide dieser Funktionen in Main ausgeführt().Lokale Variablen übergeben (C++)

Wenn dies ausgeführt wird,

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

es gibt:

2 
5 
5 

ich, dass wieder() erwartet würde sagen, null oder 0, da 'a' wieder dort erklärt wird, und doch scheint es, um den Wert zu verwenden, der 'a' in next() zugewiesen wurde.

Warum übergibt next() den Wert der lokalen Variablen 'a' erneut an(), wenn 'a' erneut in ein anderes Mal deklariert wird()?

+3

Nichts ist bestanden. 'a' in' again() 'wurde nicht initialisiert, irgendein Wert ist möglich. – songyuanyao

+0

Einverstanden, also ist der Wert von "a" in undefiniertem Verhalten. – drescherjm

Antwort

7

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

Sie sind richtig, eine nicht initialisierte Variable ist ein No-No. Sie dürfen jedoch eine Variable deklarieren und erst später initialisieren. Speicher ist reserviert, um die ganze Zahl zu halten, aber welcher Wert in dieser Erinnerung ist, bis du das tust, kann alles sein. Einige Compiler initialisieren Variablen automatisch auf Junk-Werte (um Ihnen beim Auffinden von Fehlern zu helfen), einige werden automatisch auf die Standardwerte initialisiert und andere tun gar nichts. C++ selbst verspricht nichts, daher ist es undefiniertes Verhalten. In Ihrem Fall, mit Ihrem einfachen Programm, ist es einfach genug, sich vorzustellen, wie der Compiler Assembler-Code erstellt hat, der genau dasselbe Speicherstück wiederverwendete, ohne es zu verändern. Das ist jedoch blindes Glück, und selbst in Ihrem einfachen Programm wird nicht garantiert passieren. Diese Arten von Fehlern können tatsächlich ziemlich heimtückisch sein, also machen Sie es zur Regel: Seien Sie wachsam gegenüber nicht initialisierten Variablen.

1

Dies ist ein völlig zufälliges und undefiniertes Verhalten.

Was passiert ist, dass Sie zwei Funktionen haben, die unmittelbar nacheinander aufgerufen werden. Beide haben mehr oder weniger identische Funktionsprotokolle und beide reservieren eine Variable von genau der gleichen Größe auf dem Stapel.

Da keine anderen Variablen im Spiel sind und der Stack zwischen den Aufrufen nicht geändert wird, passiert es nur, dass die lokale Variable in der zweiten Funktion "landing" an derselben Stelle wie die lokale Variable der vorherigen Funktion steht.

Natürlich ist dies nicht gut, auf die man sich verlassen kann. In der Tat ist es ein perfektes Beispiel dafür, warum Sie immer Variablen initialisieren sollten!

5

Ein nicht initialisierte nicht static lokaler Variable * eingebauter Typ (phew! Dass ein Mund voll war) einen unbestimmten Wert . Mit Ausnahme der char-Typen ergibt die Verwendung dieses Werts formal undefiniertes Verhalten, alias UB. Alles kann passieren, einschließlich des Verhaltens, das du siehst.

Offenbar mit dem Compiler und Optionen, der Stapelbereich, der für a im Aufruf von next wurde nicht für etwas anderes, bis den Anruf von again verwendet wurde, wo es für die a in again, jetzt mit dem wiederverwendet wurde gleicher Wert wie vorher.

Aber Sie können sich nicht darauf verlassen. Mit UB kann alles oder nichts passieren.


* Oder allgemeiner von POD-Typ, Plain Old Daten. Die Spezifikation des Standards ist etwas kompliziert. In C++ 11 beginnt es mit §8.5/11, "Wenn für ein Objekt kein Initialisierer angegeben ist, wird das Objekt standardmäßig initialisiert; Wenn keine Initialisierung durchgeführt wird, hat ein Objekt mit automatischer oder dynamischer Speicherdauer einen unbestimmten Wert. ". Wo "automatisch & hellip; Speicherdauer "umfasst den Fall der lokalen Variablen static. Und wo die "no initialization" auf zwei Arten über §8.5/6 erfolgen kann, die default initialization definiert, nämlich entweder über einen do-nothing-Standardkonstruktor oder über das Objekt, das nicht vom Klassen- oder Array-Typ ist.