使用realloc在C中调整2D数组的大小

时间:2017-12-15 02:34:44

标签: c arrays realloc

分配:我们有一个用户可以“绘制”的画布 - 它们可以绘制线条,添加或删除行/列等。我们必须实现的一个命令是调整画布大小。根据分配规范,新行将添加到画布顶部,新行将添加到右侧。这些新行/列填充空格,用'*'表示。用户输入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循环,但我不确定这些新行的位置。如果有人能清除我的困惑,我会很感激。

1 个答案:

答案 0 :(得分:0)

此代码无法直接放入您的程序,因为它不使用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;
}