如何编写一个程序来修改动态数组的元素和大小而又不知道大小?

时间:2019-01-22 18:52:31

标签: c++

以下是我最近参加编程考试的一个问题。我和其他学生都没有找到解决问题的方法。教授说这是可能的,但是拒绝告诉我们解决方案是什么。问题:

编写一个过程,其标题为:

void ArrayUpdate( int ??? array, int ??? delAmount, int ??? addAmout)
  • 该过程用于修改通过第一个参数传递的动态数组的元素。
  • 该过程应从数组中删除第一个单元格的 delAmount 。还应该使用从std :: cin读取的整数,将元素的 addAmount 添加到数组的后面。
  • “ ???”需要更换或移除。
  • 方括号“ []”只能与删除一起使用。
  • 仅包含 iostream fstream 。 (另一个问题需要fstream,因此这里可能不需要。)

3 个答案:

答案 0 :(得分:2)

  • “该过程用于修改通过第一个参数传递的动态数组的元素。” 它没有说明数组的组织方式。 @ 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);
    

答案 1 :(得分:1)

这是我要解决的问题。它与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;
    }
}

未经详尽测试。可能是其中的一两个错误。

为完整起见,这是测试代码和一个免费数组例程:

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);
}

答案 2 :(得分:0)

如果是“ ???”可以用任何您想要的替换,因此您可以将指向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
   }