Just for fun——C/C++函式返回區域性變數的問題

Salamander發表於2019-05-12

常見棧內變數

一般來說,在函式內對於存在棧上的區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放。因此,如果函式返回的是區域性變數的值,不涉及地址,程式不會出錯;但是如果返回的是區域性變數的地址(指標)的話,就造成了野指標,程式執行會出錯,因為函式只是把指標複製後返回了,但是指標指向的內容已經被釋放了,這樣指標指向的內容就是不可預料的內容,呼叫就會出錯。

#include <iostream>
using namespace std;
int fun1() {
    int i = 1;
    return i; // OK.
}
int* fun2() {
    int i = 2;
    int* ip = &i;
    return ip; // Wrong!
}
int main() {
    int r1 = fun1();
    cout << r1 << endl; // 1
    int* r2 = fun2();
    cout << *r2 << endl; // 這裡有可能可以列印出結果:2,看似正確的,但其實是有問題的。這是因為相應的記憶體還未被覆蓋,但這塊記憶體已經是自由的、不被保護的了。
    return 0;
}

字串

程式碼:

#include <iostream>
using namespace std;
char* fun3() {
    char* s = "Hello";
    return s; // OK.
}
char* fun4() {
    char s[] = "Hello";
    return s; // Wrong!
}
int main() {
    char* r3 = fun3();
    cout << r3 << endl; // Hello
    char* r4 = fun4();
    cout << r4 << endl; // 記憶體已經無效的了。列印出亂碼。
    return 0;
}

靜態變數

如果函式的返回值非要是一個區域性變數地址,可以把區域性變數宣告為static靜態變數。這樣變數儲存在靜態儲存區,程式執行過程中一直存在。

#include <iostream>
using namespace std;
int* fun5() {
    static int i = 5;
    return &i; // OK.
}
char* fun6() {
    static char s[] = "Hello";
    return s; // OK.
}
int main() {
    int* r5 = fun5();
    cout << *r5 << endl; // 5
    char* r6 = fun6();
    cout << r6 << endl; // Hello
    return 0;
}

陣列

陣列是不能作為函式的返回值的。因為編譯器會把陣列名認為是區域性變數(陣列)的地址。返回一個陣列,實際上是返回指向這個陣列首地址的指標。函式結束後,陣列作為區域性變數被釋放,這個指標則變成了野指標。同1的fun2()及2的fun4()(字元陣列)。但是宣告陣列是靜態的,然後返回是可以的

#include <iostream>
using namespace std;
int* fun7() {
    int a[3] = {1, 2, 3};
    return a; // Wrong!
}
int* fun8() {
    static int a[3] = {1, 2, 3};
    return a; // OK.
}
int main() {
    int* r7 = fun7();
    cout << *r7 << endl; // 記憶體已經是無效的了。
    int* r8 = fun8();
    cout << *r8 <<endl; // 1
    return 0;
}

堆內變數

函式返回指向儲存在堆上的變數的指標是可以的。但是,程式設計師要自己負責在函式外釋放(free/delete)分配(malloc/new)在堆上的記憶體。

#include <iostream>
using namespace std;
char* fun9() {
    char* s = (char*) malloc(sizeof(char) * 100);
    return s; // OK. 但需要程式設計師自己釋放記憶體。
}
int main() {
    char* r9 = NULL;
    r9 = fun9();
    strcpy(r9, "Hello");
    cout << r9 << endl; // Hello
    free(r9); // 要記得自己釋放記憶體。
    return 0;
}

相關文章