2014-02-16 112 views
2

我想編寫一個代表一組整數的類。這是一項家庭作業,但對於我來說,我無法弄清楚這個問題。C++:指針指向的值變化

在類「IntSet」中,我有兩個私有變量;一個是指向數組的指針,另一個指向數組的大小。我可以創建這個類的對象,並按預期工作。但是我有一個名爲「join」的函數,它返回IntSet類的一個對象。它基本上將數組連接在一起,然後使用該數組創建返回對象。

這裏是我的代碼:

#include <iostream> 
using namespace std; 

class IntSet { 
     int * arrPtr; 
     int arrSize; 
    public: 
     //Default Constructor 
     IntSet() { 
      int arr[0]; 
      arrPtr = arr; 
      arrSize = 0; 
     } 
     //Overloaded Constructor 
     IntSet(int arr[], int size) { 
      arrPtr = arr; 
      arrSize = size; 
     } 

     //Copy Constructor 
     IntSet(const IntSet &i) { 
      arrPtr = i.arrPtr; 
      arrSize = i.arrSize; 
     } 

     /* 
     * Returns a pointer to the first 
     * element in the array 
     */ 
     int* getArr() { 
      return arrPtr; 
     } 

     int getSize() { 
      return arrSize; 
     } 

     IntSet join(IntSet &setAdd) { 

      //Make a new array 
      int temp[arrSize + setAdd.getSize()]; 

      //Add the the values from the current instance's array pointer 
      //to the beginning of the temp array 
      for (int i = 0; i < arrSize; i++) { 
       temp[i] = *(arrPtr + i); 
      } 

      //Add the values from the passed in object's array pointer 
      //to the temp array but after the previously added values 
      for (int i = 0; i < setAdd.getSize(); i++) { 
       temp[i + arrSize] = *(setAdd.getArr() + i); 
      } 

      //Create a new instance that takes the temp array pointer and the 
      //size of the temp array 
      IntSet i(temp, arrSize + setAdd.getSize()); 

      //Showing that the instance before it passes works as expected 
      cout << "In join function:" << endl; 
      for (int j = 0; j < i.getSize(); j++) { 
       cout << *(i.getArr() + j) << endl; 
      } 

      //Return the object 
      return i; 
     } 

}; 

int main() { 

    //Make two arrays 
    int arr1[2] = {2 ,4}; 
    int arr2[3] = {5, 2, 7}; 

    //Make two objects normally 
    IntSet i(arr1, 2); 
    IntSet j(arr2, 3); 


    //This object has an "array" that has arr1 and arr2 concatenated, essentially 
    //I use the copy constructor here but the issue still occurs if I instead use 
    //Inset k = i.join(j); 
    IntSet k(i.join(j)); 

    //Shows the error. It is not the same values as it was before it was returned 
    cout << "In main function:" << endl; 

    for (int l = 0; l < k.getSize(); l++) { 
     cout << *(k.getArr() + l) << endl; 
    } 

    return 0; 
} 

的程序編譯和輸出的是現在:

In join function: 
2 
4 
5 
2 
7 
In main function: 
10 
0 
-2020743083 
32737 
-2017308032 

我不知道爲什麼,但10和0都是一樣的每我重新編譯並運行。另外,如果我打印出指針的地址而不是值(在連接函數和主函數中),我會得到相同的內存地址。

對不起,如果我濫用術語,我來自java背景,所以指針等對我來說有點新鮮。如果需要澄清,請詢問。

在此先感謝。

+1

在你的構造函數中聲明一個局部變量並保持一個指針不能很好 – codah

回答

4
int temp[arrSize + setAdd.getSize()]; 

這是一個本地數組,它的生存期一旦函數返回就結束。

IntSet i(temp, arrSize + setAdd.getSize()); 

這裏你正在構建與這一類的IntSet。事實上,構造簡單地改變一個成員指針的temp值:

IntSet(int arr[], int size) { 
    arrPtr = arr; 
    arrSize = size; 
} 

結果,因爲這temp,因此也i.arrPtr離開join後指向末端的對象的生命週期,你將有一個野指針。稍後在main後引用此指針會調用未定義的行爲。

您需要動態地使用new[]分配數組,然後使用delete[]將其刪除。你的構造函數也是如此。另請注意,如果在析構函數中使用joindelete[]中的new[],則還必須確保複製構造函數實際上覆制數組(使用new[]創建新數組並複製內容)。如果你簡單地分配指針,那麼源對象和目標對象都將指向相同的數組,並且它們都將嘗試在解構時刪除它,並再次調用未定義的行爲。

但是,既然這個C++,你不妨使用一個std::vector它爲你做這一切。(或std::set如果你真的想要一個整數集)

+0

我完全忽略了temp的作用域。將它更改爲動態分配'新'後,它工作。謝謝你和@Willem。 – xadeka

+0

+1,作爲獎勵,在實踐中使用全部三種(向量,集合和標準算法,如'std :: set_intersection'是[完成此操作的一種方式](http://ideone.com/bQ3Yu8)在學術界以外。值得OP肯定的調查。 – WhozCraig

0

與您的代碼最快的修復方法就是改變

int temp[arrSize + setAdd.getSize()]; 

這個

int * temp = new int[arrSize + setAdd.getSize()]; 

的事情是,你在棧上分配的臨時,所以當join()返回的內存是釋放。通過在堆上分配內存(按照修復),當join()返回時內存不會被釋放。

您的代碼還有其他問題 - 取決於分配的要點。我認爲當你考慮在堆上留下內存的影響時,大多數這些問題都會得到解決。