【问题标题】:Using realloc to resize a 2D array in C使用 realloc 在 C 中调整二维数组的大小
【发布时间】:2017-12-15 02:34:43
【问题描述】:

分配:我们有一个用户可以“绘画”的画布——他们可以画线、添加或删除行/列等。我们必须实现的命令之一是调整画布的大小。根据分配规范,新行添加到画布顶部,新列添加到右侧。这些新的行/列用空格填充,用“*”表示。用户输入r numRows numCols

我苦苦挣扎的部分是使用 realloc。如果我有一个 5x5 的画布开始,并且用户决定将大小调整为 7x5,我会怎么做? realloc 将新行/列放在哪里,它会自动将现有行向下移动吗?我有一个函数 implementResize,当用户输入 r 时会调用它:

void implementResize(BoardState* boardState, int newRows, int newCols) {
  if (newRows > boardState->board.numRows) {
    printf("add rows\n");
    addRow(boardState, newRows);
  }
  else if (newCols < boardState->board.numRows) {
    printf("delete rows\n");
    //deleteRow();
  }
  else {
    printf("same\n");
    boardState->board.numRows = newRows;
  }
  if (newCols > boardState->board.numCols) {
    printf("add columns\n");
    //addCol();
  }
  else if (newCols < boardState->board.numCols) {
    printf("delete columns\n");
    //deleteCol();
  }
  else {
    printf("same\n");
    boardState->board.numCols = newCols;
  }
}

现在我专注于如何在画布顶部添加行。我现在的 addRow 函数代码是:

void addRow(BoardState *boardState, int newRows) {
  boardState->board.numRows = newRows;
  boardState->board.theBoard = (char**) realloc(boardState->board.theBoard, boardState->board.numRows * sizeof(char*));
}

我试图弄清楚如何为行重新分配空间。我知道我需要根据 newRows 的数量和列的数量使用嵌套的 for 循环,但我不确定这些新行的去向。如果有人能解决我的困惑,我将不胜感激。

【问题讨论】:

  • “realloc 将新的行/列放在哪里,它会自动将现有的行向下移动吗?” (1) 它不理会它们——新的块内存最后会有额外的空间。 (2) 它不会改变任何东西。 (和3)不要realloc指针本身,如果realloc失败,你会丢失指向原始内存块的指针,而不是void *tmp = realloc (boardState-&gt;board.theBoard, boardState-&gt;board.numRows * sizeof (char*)); if (!tmp) { /* handle error */ } boardState-&gt;board.theBoard = tmp;

标签: c arrays realloc


【解决方案1】:

此代码不能直接放入您的程序,因为它没有使用addColumnaddRow。这反而让您了解如何解决问题。

注释已添加到有问题的行。还有一些建议。

    int  resizeBoard(BoardState *boardState, size_t newRows, size_t newCols) {
    //verify before you dereference
    if(boardState == NULL)
        return 0;

    if(boardState->board.theBoard == NULL)
        return 0;

    const size_t oldRows = boardState->board.numRows; //more readbale

    /*
    ** if the number of rows decreased, free the excess
    ** we have to do it now because it becomes inaccessible after realloc of boardState.board.theBoard
    */
    for(int i = newRows; i < oldRows; i++)
        free(boardState->board.theBoard[i]);

    /* set these to the new values so that freeBoard gets the correct data in case of failure */
    boardState->board.numRows = newRows;
    boardState->board.numCols = newCols;

    //it is important to use a different pointer to store the value returned by realloc because if the reallocation fails, realloc will return NULL and we will lose access to the original board
    void *ptr = realloc(boardState->board.theBoard, izeof(char*)*newRows);
    if(ptr == NULL) { 
        //realloc failed
        freeBoard(boardState);
        return 0;
    }
    boardState->board.theBoard = ptr;

    //As realloc copies the previous data to the new memory location, theBoard is still pointing to the old rows (from row 0 to row [newRows - 1])
    for(int i = 0; i < min(newRows, oldRows); i++) {
        void *ptr = realloc(boardState->board.theBoard[i], sizeof(char)*newCols);
        if(ptr == NULL) {
            //realloc failed
            freeBoard(boardState);
            return 0;
        }
        boardState->board.theBoard[i] = ptr;
    }
    
    //we cannot use realloc for first time memory allocation; doing so causes undefined behaviour
    //we must separately allocate memory for the new rows
    for(int i = oldRows; i < newRows; i++)
    {
        boardState->board.theBoard[i] = malloc(sizeof(char)*newCols);
        if(boardState->board.theBoard[i] == NULL) {
            //perform cleanup
            return 0;
        }
    }
    return 1;
}

【讨论】:

    猜你喜欢
    • 2017-01-05
    • 2017-08-24
    • 2011-02-08
    • 2016-01-05
    • 1970-01-01
    • 2021-03-20
    • 2016-02-22
    • 2018-05-02
    • 2015-02-27
    相关资源
    最近更新 更多