C realloc错误:malloc():大小无效(未排序)



我目前正在用C制作一个sdl2(/图形(版本的生活游戏,所以当屏幕调整大小时,我需要更新网格。当调整屏幕大小时,我不希望它只是改变平铺的大小,我希望它能真正创建更多的平铺。所以我重新分配了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("%dn", 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);
}

我的猜测是,当你试图将单元格重新分配给时,就会出现问题

gridRow * gridCol

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

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

让我们分析一下您的代码。网格是一个名为cells的二维阵列您可以根据保存在gridSizeW和gridSizeH中的维度进行动态分配。

理想情况下,要寻址单元格,请使用其坐标将从(1到gridSizeW;1到gridSize H(,或者更常见的是,从(0到gridSizeW-1;0到gridSize H-1(。

获取单元格值的例程是:

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

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

问题是,网格的内存表示与屏幕的尺寸无关(或几乎无关(。如果您有一个网格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接口时使用。

最新更新