【问题标题】:C realloc error: malloc(): invalid size (unsorted)C realloc 错误:malloc():大小无效(未排序)
【发布时间】:2020-04-22 11:39:21
【问题描述】:

我目前正在用 C 语言制作生命游戏的 sdl2(/graphical) 版本,所以当屏幕调整大小时,我需要更新网格。当屏幕调整大小时,我不希望它只是改变图块的大小,我希望它实际创建更多图块。所以我重新分配了cells 列表,其中包含所有单元格状态,但由于某些奇怪的原因不起作用。

bool updateCells(int w, int h) {
    size_t x, y, 
          oldGridCol, 
          oldGridRow;

    oldGridCol = gridCol;
    oldGridRow = gridRow;

    gridRow = w / gridSizeW;
    gridCol = h / gridSizeH;

    cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
    if(cells == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory allocation failed!");
        return false;
    }

    for(y = 0; y < oldGridRow; y++) {
        for(x = 0; x < oldGridCol; x++) {
            writeCell(y, x, *(cells + (x + (y * oldGridCol))));
        }
    }

    return false;
}

当这个函数被调用时,realloc 函数返回这个:

malloc(): invalid size (unsorted)
Aborted

提前谢谢你!

我已经为这个程序制作了一个最小的可重现示例,它不使用 SDL2,只使用普通 C。现在由于某种原因这个示例可以工作。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>

typedef enum cellState {
    dead,
    live,
    potentialDead,
    potentialLive
} cellState_t;

size_t          gridRow,
            gridCol,
            gridSizeW,
            gridSizeH;

cellState_t     *cells;

bool            quitLoop;

bool initCells(void);
bool updateCells(int w, int h);
void writeCell(size_t row, size_t col, cellState_t state);
cellState_t readCell(size_t row, size_t col);

void die(const char *f, const size_t l, const char *fmt, ...);

int main(int argc, char *args[]) {
    int w, h;

    quitLoop = false;

    gridSizeW = 25;
    gridSizeH = 25;


    // Let's assume that the window size is 640 by 480
    gridRow = 640 / gridSizeW;
    gridCol = 480 / gridSizeH;

    if(!initCells())
        die(__FILE__, __LINE__, "Failed to initialize cells!");

    writeCell(1, 2, live);
    writeCell(2, 3, live);
    writeCell(3, 3, live);
    writeCell(3, 2, live);
    writeCell(3, 1, live);

    while(!quitLoop) {
        updateCells(640, 480);

        printf("%d\n", readCell(1, 2));
    }

    return EXIT_SUCCESS;
}

bool initCells(void) {
    cells = calloc((gridRow * gridCol), sizeof(cellState_t));
    if(cells == NULL) {
        return false;
    }

    return true;
}

bool updateCells(int w, int h) {
    size_t x, y, 
          oldGridCol, 
          oldGridRow;

    oldGridCol = gridCol;
    oldGridRow = gridRow;

    gridRow = w / gridSizeW;
    gridCol = h / gridSizeH;

    cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
    if(cells == NULL) {
        return false;
    }

    for(y = 0; y < oldGridRow; y++) {
        for(x = 0; x < oldGridCol; x++) {
            writeCell(y, x, *(cells + (x + (y * oldGridCol))));
        }
    }

    return false;
}

void writeCell(size_t row, size_t col, cellState_t state) {
    *(cells + (col + (row * gridCol))) = state;
}

cellState_t readCell(size_t row, size_t col) {
    return *(cells + (col + (row * gridCol)));
}

void die(const char *f, const size_t l, const char *fmt, ...) {
    va_list vargs;

    va_start(vargs, fmt);

    fprintf(stderr, "error from file %s on line %ld: ", f, l);
    //SDL_LogMessageV(SDL_LOG_CATEGORY_ERROR, SDL_LOG_PRIORITY_CRITICAL, fmt, vargs);

    fputc('\n', stderr);

    va_end(vargs);

    exit(EXIT_FAILURE);
}

也许是影响结果的窗口大小变量,或者类似的东西。

但是完整的代码不行,这里是完整的代码:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#define WINDOW_NAME "sdl-life"
#define WINDOWW     640
#define WINDOWH     480

typedef enum cellState {
    dead,
    live,
    potentialDead,
    potentialLive
} cellState_t;

SDL_Window      *gWindow;
SDL_Renderer        *gRenderer;
SDL_Texture     *gLiveCellTexture,
            *gGrid;

size_t          gridRow,
            gridCol,
            gridSizeW,
            gridSizeH;

cellState_t     *cells;

bool            quitLoop;

bool initSdl(void);
void closeSdl(void);
SDL_Texture *loadTexture(const char *path);
bool loadMedia(void);

bool initCells(void);
bool updateCells(int w, int h);
void writeCell(size_t row, size_t col, cellState_t state);
cellState_t readCell(size_t row, size_t col);

void displayCell(cellState_t status, SDL_Rect location);
void displayAllCells(void);

void die(const char *f, const size_t l, const char *fmt, ...);

int main(int argc, char *args[]) {
    SDL_Event event;
    int w, h;

    quitLoop = false;

    if(!initSdl())
        die(__FILE__, __LINE__, "Failed to initialize SDL!");

    if(!loadMedia())
        die(__FILE__, __LINE__, "Failed to load media!");

    SDL_GetWindowSize(gWindow, &w, &h);

    gridSizeW = 25;
    gridSizeH = 25;

    gridRow = w / gridSizeW;
    gridCol = h / gridSizeH;

    if(!initCells())
        die(__FILE__, __LINE__, "Failed to initialize cells!");

    writeCell(1, 2, live);
    writeCell(2, 3, live);
    writeCell(3, 3, live);
    writeCell(3, 2, live);
    writeCell(3, 1, live);

    SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0x00);

    while(!quitLoop) {
        while(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT)
                quitLoop = true;
        }

        SDL_RenderClear(gRenderer);

        SDL_GetWindowSize(gWindow, &w, &h);
        updateCells(w, h);

        displayAllCells();

        SDL_RenderPresent(gRenderer);
    }

    closeSdl();

    return EXIT_SUCCESS;
}

bool initSdl(void) {
    SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "The initialization process has begun");
    if(SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL: %s", SDL_GetError());
        return false;
    }

    if(!IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL_image: %s", IMG_GetError());
        return false;
    }

    if(TTF_Init() == -1) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL_ttf: %s", TTF_GetError());
        return false;
    }

    gWindow = SDL_CreateWindow(WINDOW_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOWW, WINDOWH, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
    if(gWindow == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to create the window: %s", SDL_GetError());
        return false;
    }

    gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if(gRenderer == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to create the renderer: %s", SDL_GetError());
        return false;
    }

    SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "The initialization has finished");

    return true;
}

void closeSdl(void) {
    SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "SDL is shutting DOWN!");

    free(cells);

    SDL_DestroyTexture(gLiveCellTexture);
    SDL_DestroyTexture(gGrid);
    SDL_DestroyRenderer(gRenderer);
    SDL_DestroyWindow(gWindow);

    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
}

SDL_Texture *loadTexture(const char *path) {
    SDL_Texture *newTexture;
    SDL_Surface *loadedSurface;

    loadedSurface = IMG_Load(path);
    if(loadedSurface == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
        return NULL;
    }

    SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0x0, 0xff, 0xff));

    newTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface);
    if(newTexture == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to convert surface to texture: %s", SDL_GetError());
        return NULL;
    }

    SDL_FreeSurface(loadedSurface);

    return(newTexture);
}

bool loadMedia(void) {
    gLiveCellTexture = loadTexture("livecell.png");
    if(gLiveCellTexture == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
        return false;
    }

    gGrid = loadTexture("grid.png");
    if(gGrid == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
        return false;
    }

    return true;
}

bool initCells(void) {
    cells = calloc((gridRow * gridCol), sizeof(cellState_t));
    if(cells == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory allocation failed!");
        return false;
    }

    return true;
}

bool updateCells(int w, int h) {
    size_t x, y, 
          oldGridCol, 
          oldGridRow;

    oldGridCol = gridCol;
    oldGridRow = gridRow;

    gridRow = w / gridSizeW;
    gridCol = h / gridSizeH;

    cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
    if(cells == NULL) {
        SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory reallocation failed!");
        return false;
    }

    for(y = 0; y < oldGridRow; y++) {
        for(x = 0; x < oldGridCol; x++) {
            writeCell(y, x, *(cells + (x + (y * oldGridCol))));
        }
    }

    return false;
}

void writeCell(size_t row, size_t col, cellState_t state) {
    *(cells + (col + (row * gridCol))) = state;
}

cellState_t readCell(size_t row, size_t col) {
    return *(cells + (col + (row * gridCol)));
}

void displayCell(cellState_t status, SDL_Rect location) {
    SDL_RenderCopy(gRenderer, gGrid, NULL, &location);

    if(status == live) {
        SDL_RenderCopy(gRenderer, gLiveCellTexture, NULL, &location);
    }
}

void displayAllCells(void) {
    size_t x, y;
    SDL_Rect location;

    location.w = gridSizeW;
    location.h = gridSizeH;
    location.x = 0;
    location.y = 0;

    for(y = 0; y < gridRow; y++) {
        for(x = 0; x < gridCol; x++) {
            displayCell(readCell(y, x), location);

            location.x += location.w;
        }

        location.y += location.h;
        location.x = 0;
    }
}

void die(const char *f, const size_t l, const char *fmt, ...) {
    va_list vargs;

    va_start(vargs, fmt);

    fprintf(stderr, "error from file %s on line %ld: ", f, l);
    SDL_LogMessageV(SDL_LOG_CATEGORY_ERROR, SDL_LOG_PRIORITY_CRITICAL, fmt, vargs);

    va_end(vargs);

    closeSdl();

    exit(EXIT_FAILURE);
}

【问题讨论】:

  • 什么是cells?你明白realloc 需要字节数和 not 元素数吗? IE。 sizeof 不见了。
  • 感谢您的输入,我已更正此问题,现在是 (gridRow * gridCol) * sizeof(cellState_t) 并且单元格是 cellState_t 元素的列表(/指针)。 cellState_t 是一个包含 4 个状态的枚举:dead、alive、potential_dead、potential_alive。但是还是不行,现在错误是:malloc(): invalid size (unsorted)
  • 不过,cells 是什么?它在哪里声明?它的价值是什么?
  • 我相信错误出现在未提供的代码中。请更新为完整的minimal reproducible example。我的猜测是堆栈溢出访问覆盖cells 值或标准库管理的某些内存区域,导致后续内存分配失败。使用调试器、内存检查工具(如valgrind)和编译器清理选项来进一步调试问题。
  • 请不要发布到外部网站的链接。只需在此网站上发布问题中的来源即可。

标签: c pointers memory-management sdl-2 realloc


【解决方案1】:

我的猜测是当您尝试重新分配单元格时会出现问题

gridRow * gridCol

因为 w / gridSizeW 似乎是您想要的元素数量。试试:

cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));

【讨论】:

  • 谢谢,但是当你发布这个答案时,我看到了来自 KamilCuk 的评论,我尝试了这个解决方案......但代码仍然失败,错误 malloc():invalid size (unsorted) Aborted
【解决方案2】:

让我们分析您的代码。网格是一个名为单元格的二维数组,其中 您根据其保存在 gridSizeW 和 gridSizeH 中的尺寸动态分配。

理想情况下,您使用它的坐标来寻址一个单元格 将从 (1 到 gridSizeW; 1 到 gridSizeH) 或者更常见的是从 (0 到 gridSizeW-1; 0 到 gridSizeH-1)。

获取单元格值的例程是:

cellState_t readCell(size_t row, size_t col) {
    return *(cells + (col + (row * gridCol)));
}

它实现了获取请求的行号,乘以宽度,并添加列号的想法。将 2D 地址转换为 1D 地址是正确的。

问题在于您在内存中的网格表示与屏幕的尺寸无关(或很少)。如果您有一个 grid 25 x 25(您将它们指定为初始宽度和高度),则无论 SDL_GetWindowSize() 返回什么内容,您都必须分配 25*25 个单元格 .

基本上,您应该始终使用 gridSizeW 和 gridSizeH 来处理单元格指针。您改用 gridRow 和 gridCol。只有当您更新屏幕时,您才会将网格的行+列坐标“缩放”到屏幕的 X+Y 坐标。因此,假设从 0 开始编号,您的 readcell 例程应该是:

cellState_t readCell(size_t row, size_t col) {
    return *(cells + (col + (row * gridSizeW)));
                    // gridSizeW -------^
}

变量 gridRow 和 gridCol,它们是 w/gridwidth 和 h/gridheight 的比率,正如您正确写的那样:

SDL_GetWindowSize(gWindow, &w, &h);    // w+h: screen dimensions

gridSizeW = 25;   // grid dimensions
gridSizeH = 25;

gridRow = w / gridSizeW;  // screenwidth=250? then a cell is 10 pixels wide
gridCol = h / gridSizeH;

仅在与 SDL 接口时使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2017-06-15
    • 2021-08-31
    • 2015-04-12
    • 2014-10-13
    • 2016-01-02
    • 2013-02-04
    相关资源
    最近更新 更多