【问题标题】:memcpy error segmentation fault while trying to copy 2D array of 4 char structure in C尝试在 C 中复制 4 个字符结构的二维数组时出现 memcpy 错误分段错误
【发布时间】:2021-04-09 10:43:11
【问题描述】:

嘿,我正在尝试复制从另一个图像中创建的 SDL_Color 数组。但是对于某些图像,我得到:

进程以退出代码 -1073741819 (0xC0000005) 结束

它适用于 20 x 20 像素的图像,但它适用于 50 x 50 的图像... 这是我的代码:

FILE *debugFile = fopen("C:\\Users\\Clement\\Documents\\coding\\ImageOfCLife\\debug.txt", "w+");
int imgWidth, imgHeight, channels;
unsigned char *img = stbi_load("C:\\Users\\Clement\\Documents\\coding\\ImageOfCLife\\star.jpg", &imgWidth,
                               &imgHeight, &channels, 0);
fprintf(debugFile, "Loaded image with a width of %dpx, a imgHeight of %dpx and %d channels\n", imgWidth, imgHeight, channels);
dRulesLen = sizeof(deathRules);
bRulesLen = sizeof(birthRules);
if (img == NULL) {
    fprintf(debugFile, "Error in loading the image\n");
    exit(3);
}

int ch, pix;
SDL_Color **stateMatrix1 = (SDL_Color **) malloc(imgHeight * sizeof(SDL_Color*));
if (stateMatrix1 == NULL) {
    fprintf(debugFile,"Unable to allocate memory\n");
    exit(1);
}
for (int i = 0; i < imgHeight; ++i) {
    stateMatrix1[i] = (SDL_Color *) malloc(imgWidth * sizeof(SDL_Color));
}
for (ch = 0; ch < imgHeight; ch++) {
    printf("{");
    for (pix = 0; pix < imgWidth; pix++) {
        unsigned bytePerSDL_Color = channels;
        unsigned char *SDL_ColorOffset = img + (pix + imgHeight * ch) * bytePerSDL_Color;
        SDL_Color p = initSDL_Color(SDL_ColorOffset);
        stateMatrix1[ch][pix] = p;
        printSDL_Color(p);
        printf(", ");
    }
    printf("}\n");
}
SDL_Color stateMatrix2[imgHeight][imgWidth];
memcpy(stateMatrix2, stateMatrix1, imgWidth*imgHeight*sizeof(SDL_Color)); 

最后一行是根据the debugger的问题 我试过了

memcpy(stateMatrix2, stateMatrix1, sizeof(stateMatrix2))

也是,但我得到了相同的结果。

我使用 minGW 和 Clion 在 Windows 10 上工作。我希望你能帮助我解决这个问题。

我还尝试将SDL_Color stateMatrix2[imgHeight][imgWidth]; 替换为:

    SDL_Color **stateMatrix2 = (SDL_Color **) malloc(imgHeight * sizeof(SDL_Color*));
if (stateMatrix2 == NULL) {
    fprintf(debugFile,"Unable to allocate memory\n");
    exit(1);
}
for (int i = 0; i < imgHeight; ++i) {
    stateMatrix2[i] = (SDL_Color *) malloc(imgWidth * sizeof(SDL_Color));
}

但我遇到了同样的问题。

我忘了说,但我希望 ant 能够同时使用 stateMatrix 作为函数的参数。

为了解决这个问题,我使用了下面解释的 Olaf 解决方案: 我保留了:

SDL_Color **stateMatrix1 = (SDL_Color **) malloc(imgHeight * sizeof(SDL_Color*));
if (stateMatrix1 == NULL) {
    fprintf(debugFile,"Unable to allocate memory\n");
    exit(1);
}
for (int i = 0; i < imgHeight; ++i) {
    stateMatrix1[i] = (SDL_Color *) malloc(imgWidth * sizeof(SDL_Color));
}

为矩阵和使用分配内存:

for (int i = 0; i < imgHeight; ++i) {
memcpy(stateMatrix2[i], stateMatrix1[i], imgWidth * sizeof(SDL_Color));
}

执行复制。 我还验证了两个矩阵没有链接,没有问题。

【问题讨论】:

  • stateMatrix1 不是连续的内存块。它由许多单独的malloc 内存块组成,因此不能用单个memcpy 复制。
  • stateMatrix2是一个二维数组,而stateMatrix1是一个指针数组,指向SDL_Color->不同类型的数组。
  • @kaylum 哦,所以解决方案是循环使用memcpy(stateMatrix2[i], stateMatrix1[i], imgWidth*sizeof(SDL_Color)?
  • @OlafDietsche 所以我必须以与矩阵 1 相同的方式声明 matrix2 吗?
  • 在C中,malloc的返回不需要强制转换,没有必要。见:Do I cast the result of malloc?

标签: c multidimensional-array segmentation-fault memcpy


【解决方案1】:

复制时

memcpy(stateMatrix2, stateMatrix1, imgWidth * imgHeight * sizeof(SDL_Color));

你会超出stateMatrix1的结尾,不是imgWidth * imgHeight * sizeof(SDL_Color),而是imgHeight * sizeof(SDL_Color*)


stateMatrix1 循环复制到stateMatrix2 是解决此问题的一种方法

for (int i = 0; i < imgHeight; ++i) {
    memcpy(stateMatrix2[i], stateMatrix1[i], imgWidth * sizeof(SDL_Color));
}

另一种方法是将两个矩阵设为同一类型。但是当分配stateMatrix2

SDL_Color **stateMatrix2 = (SDL_Color **) malloc(imgHeight * sizeof(SDL_Color*));

以后使用与上面相同的memcpy,您仍然会超出stateMatrix1并且现在也超出stateMatrix2 的末尾。


正确的复制方式(但由于其他原因仍然错误)是

memcpy(stateMatrix2, stateMatrix1, sizeof(*stateMatrix1));

这在大小方面是正确的,但仍然是错误的,因为它将stateMatrix1指针 复制到stateMatrix2。这有两个效果

  1. 当您使用自己的指针初始化stateMatrix2 时,会出现内存泄漏。
  2. 现在两个矩阵都指向同一个内存,这意味着改变一个,也会改变另一个。

【讨论】:

  • 我通过编辑我的问题使用您的答案发布了我的修复,如果您对此有一些额外的评论,请告诉我。再次感谢!
【解决方案2】:

您的错误在 cmets 中进行了解释。您可以通过为您的矩阵分配一个连续的内存块而不是像您所做的许多块来修复它。对于分配、解除分配和复制,这种方式更加简单(因为您可以使用一次调用 memcpy):

#include <stdio.h>
#include <stdlib.h>

struct SDL_Color {
    unsigned char rgba[4];
};

int main() {
    int ch, pix;
    int imgWidth = 100;
    int imgHeight = 100;
    struct SDL_Color (*stateMatrix1)[imgWidth][imgHeight] = malloc(sizeof(*stateMatrix1));
    if (*stateMatrix1 == NULL) {
        printf("Unable to allocate memory\n");
    } else {
        free(*stateMatrix1);
        printf("Success\n");
    }
    return 0;
}

您只需要在每次使用矩阵时取消对指向矩阵的指针的引用即可。

【讨论】:

  • 问题是我必须将那些二维数组作为参数传递给函数。为了实现它,我必须将我的 stateMatrix 构建为指针的指针,对吗?
  • 除非 imgWidthimgHeight 是常量字面量,否则最好为每一行分配指针和存储空间,而不是使用 VLA(因为从 C11 开始,对 VLA 的支持是可选的)。如果您可以选择使用单个块来模拟 2D 数组——这对于单一分配/单一释放的简单性始终是首选。如果 SDL 函数需要一个指向指针的指针,那么这就是你所坚持的。这里(*stateMatrix1)[imgWidth][imgHeight] 是一个指向 2D-VLA 的指针。
猜你喜欢
  • 1970-01-01
  • 2021-03-25
  • 2015-04-13
  • 2018-08-21
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 2022-01-21
相关资源
最近更新 更多