2017-04-02 170 views
1

我試圖寫一個程序,從CIN使用指針讀取的值,然後輸出該值沿着他們的陣列中的位置。我無法弄清楚爲什麼printNumbers1有效,但printNumbers2不能。下面是程序(接近底部的相關代碼):C++指針/ for循環混亂

#include <iostream> 

using namespace std; 

int *readNumbers(int); 
void printNumbers1(int*); 
void printNumbers2(int*); 

int main() 
{ 
    int *numbers = readNumbers(5); 
    printNumbers1(numbers); 
    printNumbers2(numbers); 
    return 0; 
} 

int *readNumbers(int n) 
{ 
    int a[n]; 
    int *numbers; 
    numbers = &a[0]; 
    for (int i=0; i<n; i++) 
    { 
     cin >> *(numbers+i); 
    } 

    return numbers; 
} 

void printNumbers1(int *numbers) 
{ 
    cout << 0 << ' ' << *(numbers) << endl 
     << 1 << ' ' << *(numbers+1) << endl 
     << 2 << ' ' << *(numbers+2) << endl 
     << 3 << ' ' << *(numbers+3) << endl 
     << 4 << ' ' << *(numbers+4) << endl; 
} 

void printNumbers2(int *numbers) 
{ 
    for (int i=0; i<5; i++) 
    { 
     cout << i << ' ' << *(numbers+i) << endl; 
    } 
} 

當我運行程序,它可以作爲用於printNumbers1但輸出看似隨機數和0的printNumbers2的組合。我覺得這兩個printNumbers函數應該具有相同的功能,但它們不會。我錯過了什麼?

+0

'a'是一個局部變量。它將超出範圍並在函數結束時變爲無效。返回一個指向它的指針是一個壞主意,因爲指針將指向壞內存。你很可能不得不使用'new'和'delete'。 – user4581301

回答

2

這是因爲兩件事情的組合:

  • C++不允許變長數組 - 這是一個受歡迎的擴展,但該聲明int a[n]不是標準。
  • 您不能從函數 - 指針numbers內部返回指向局部變量的指針readNumbers指向a,即局部變量。你可以在函數內部使用這個指針,但是在函數之外它會變得無效,因爲a超出了範圍。

使用外的範圍的變量會導致未定義行爲This Q&A提供了一個非常好的解釋發生了什麼,以及它爲什麼看起來像程序工作正常。

如果你想使用內置的指針,刪除int a[n],並改變numbers聲明如下:

int *numbers = new int[n]; 

您還需要添加

delete[] numbers; 

之前return 0線,以避免內存泄漏。

我假設你寫了這個代碼作爲學習活動的一部分。但是,一般來說,C++中更好的方法是使用std::vector<int>,它隱藏了代碼中的指針操作,併爲您處理資源管理。

+0

謝謝!唯一讓我困惑的是爲什麼'printNumbers1'工作,如果'a'超出'readNumbers'之外的函數的作用域。 –

+0

@MemelordSupreme如果一個數組超出範圍,它並不意味着它有隨機垃圾:它可能有你以前放在那裏的東西,所以,不幸的是,不正確的代碼可能會顯示工作。然而,這並不是真的有效,只是隨機垃圾恰好符合你期望看到的情況。 – dasblinkenlight

+0

@dasblinkenlight請添加關於未定義行爲的註釋;那是什麼導致看似正確的行爲。 –

1

readNumbers指針返回到具有自動存儲持續時間的變量。

上廢棄該指針的行爲是不確定的。

使用一個std ::向量來代替。依靠返回值優化來消除正在進行的任何多餘值副本。

0

在這裏已創建的數組a [n]的在函數內部,所以它是一個局部變量,因此,這種陣列可以或可以不被所述功能的ends.Never使用本地變量的地址範圍後刪除在功能之外。此代碼正在工作:

#include <iostream> 

using namespace std; 

int *readNumbers(int); 
void printNumbers1(int*); 
void printNumbers2(int*); 

int main() 
{ 
    int *numbers = readNumbers(5); 
    printNumbers1(numbers); 
    printNumbers2(numbers); 
    return 0; 
} 

int *numbers; 

int *readNumbers(int n) 
{ 

    numbers = new int[n]; 
    for (int i=0; i<n; i++) 
    { 
     cin >> *(numbers+i); 
    } 

    return numbers; 
} 

void printNumbers1(int *numbers) 
{ 
cout << 0 << ' ' << *(numbers) << endl 
    << 1 << ' ' << *(numbers+1) << endl 
    << 2 << ' ' << *(numbers+2) << endl 
    << 3 << ' ' << *(numbers+3) << endl 
    << 4 << ' ' << *(numbers+4) << endl; 
} 

void printNumbers2(int *numbers) 
{ 
for (int i=0; i<5; i++) 
{ 
    cout << i << ' ' << *(numbers+i) << endl; 
} 
} 
+0

強烈建議使用[]而不是指針數學進行索引。 – user4581301