[英]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)
創建數組:
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.