簡體   English   中英

如何在不知道大小的情況下編寫一個程序來修改動態數組的元素和大小?

[英]How to write a procedure to modify the elements and size of a dynamic array without knowing the size?

以下是我最近參加的編程考試中的一個問題。 我和其他學生都沒有找到解決方法。 教授說有可能,但拒絕告訴我們解決方案是什么。 問題:

編寫一個帶有以下標題的過程:

void ArrayUpdate( int ??? array, int ??? delAmount, int ??? addAmout)
  • 該過程用於修改通過第一個參數傳遞的動態數組的元素。
  • 該過程應從陣列中刪除第一個單元格的delAmount 它還應該將addAmount的元素添加到數組的后面,並從 std::cin 讀取整數。
  • 這 ”???” 需要更換或拆除。
  • 方括號“[ ]”只能與newdelete一起使用。
  • 只能包含iostreamfstream (另一個問題需要 fstream,所以這里可能不需要它。)
  • “該過程用於修改通過第一個參數傳遞的動態數組的元素。” 它沒有說明數組是如何組織的。 正如@user4581301 所建議的,第一個元素可能是數組的大小。 換句話說,數組的第一個元素位於位置 1 而不是 0 這很可能是你老師的想法。 目的是教你指針/引用和數組布局。
  • 創建數組:

     void CreateArray( int*& array, int size ) { array = new int[ size + 1 ]; array[ 0 ] = size; }

    您可以使用int**而不是int*& ,但更難寫/讀。

  • 檢索大小

     int ArraySize( int* array ) { return *array; }
  • 用法

     int* array; CreateArray( array, 10 ); //... for ( int i = 1; i <= ArraySize(array); ++i ) // ...
  • 函數簽名

     void ArrayUpdate( int*& array, int delAmount, int addAmout);

這是我對這個問題的切入點。 它與 ZDF 非常相似,但它將數組的capacity添加到簿記中,並通過給調用者一個指向數組中間而不是開頭的指針來隱藏和隱藏簿記。 這允許用戶將數組用作常規數組,但如果他們嘗試自己delete它,則會崩潰。

在我認為需要更多解釋的地方嵌入了評論。

//Magic numbers are evil.
constexpr int bookkeeping = 2;
constexpr int sizeOff = -2;
constexpr int capOff = -1;

void ArrayUpdate( int *& array, int delAmount, int addAmount)
{
    int size;
    int capacity;

    // can't do jack with a non-existent array, so let's make sure we have one.
    if (array != nullptr)
    {
        size = *(array + sizeOff);
        capacity = *(array + capOff);
    }
    else
    {
        size = 0;
        capacity = 0;
    }
    if (delAmount > size) // can't delete more than we have.
    {
        delAmount = size; 
        // alternative: freak out here. Abort, throw exception, whatever
    }
    int * to; // track where data goes to
    int * temp; // location of new buffer, if resized
    bool resized;
    int newsize =size + addAmount - delAmount;
    if (newsize > capacity)
    { 
        capacity *=2;
        if (capacity < newsize)
        {
            capacity = newsize;
        }
        temp = new int[capacity+bookkeeping];
        to = temp + bookkeeping; // point to where we want data to go:
                                 // after the book-keeping.
        resized = true;
    }
    else
    {
        to = array;
        resized = false;
    }
    // use std::copy or memcpy here, but since we're not allowed the appropriate
    // headers, here comes ol' brute force!
    if (delAmount || resized) // need to copy old data around
    { 
        for (int index = delAmount; index < size; index++)
        {
            *to++ = *(array + index);
        }
    }
    // add new data
    for (int count = 0; count < addAmount; count++)
    {
        if (std::cin >> *to) // always test to make sure you got good input
        {
            to++;
        }
        else
        { // Bad input. Clean up
            std::cin.clear();

            // normally I'd use cin.ignore(numeric_limits<streamsize>::max(), '\n')
            // here to kill all the remaining user input, but no <limits>
            std::cin.ignore(1000, '\n');
            // might also want to just read and discard until you find the
            // first whitespace. That's can be done easily by >> to a std::string,
            // but no string header allowed. 
        }
    }

    if (resized)
    {
        if (array != nullptr) // normally deleting nullptr is safe, but not when
                              // you're going to modify it with an offset
        {
            delete[] (array - bookkeeping);
        }
        array = temp + bookkeeping; // array hides the extra book-keeping
        *(array + capOff) = capacity;
    }
    if (array != nullptr)
    {
        *(array + sizeOff) = newsize;
    }
}

沒有經過詳盡的測試。 那里可能有一兩個錯誤。

為了完整起見,這里是測試代碼和一個 Free Array 例程:

void FreeArray(int * array)
{
    delete[] (array - bookkeeping);
}

void printarray(const int * array)
{
    int size;
    int capacity;
    if (array != nullptr)
    {
        size = *(array + sizeOff);
        capacity = *(array + capOff);
    }
    else
    {
        size = 0;
        capacity = 0;
    }
    std::cout << "Size: " << size <<"\nCapacity: "<< capacity << '\n';
    for (int index = 0; index < size; index++)
    {
        std::cout << array[index] << ' ';
    }
    std::cout << std::endl;
}

int main()
{
    int * array = nullptr;
    printarray(array);
    ArrayUpdate(array, 5, 0);
    printarray(array);
    ArrayUpdate(array, 5, 5);
    printarray(array);
    ArrayUpdate(array, 5, 5);
    printarray(array);
    ArrayUpdate(array, 0, 5);
    printarray(array);
    ArrayUpdate(array, 5, 0);
    printarray(array);
}

如果 ”???” 可以用你想要的任何東西替換,所以你可以向你的函數傳遞一個指向 int 的指針,或者一個指向 int 指針的指針,等等......

因此,在處理內存管理或范圍時,C++ 中的技巧是存儲 2 個指針,一個指向數組的開頭,一個指向數組的結尾:

//a range:
int* limits[2];
int ** array = limits;

然后,如果您更改函數內范圍的大小,則必須通過引用傳遞它:

void ArrayUpdate( int ** array, int delAmount, int addAmout){
   int* begin = array[0];
   int* end = array[1];
   //end so on
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM