繁体   English   中英

C 重新分配错误:malloc():大小无效(未排序)

[英]C realloc error: malloc(): invalid size (unsorted)

我目前正在 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;
}

当这个 function 被称为realloc function 返回这个:

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);
}

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

但是完整的代码不起作用,这是完整的代码:

#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));

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

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

您获取单元格值的例程是:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM