【发布时间】: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