2

此代码旨在将图像文件中的值读取到数组中(我知道大小为 16*8)。

当我动态创建 img 数组以便我可以拥有任何大小的图像时,它在运行时会崩溃,当我手动将其设置为正确的大小 ( char img[16][8];) 时,它可以工作。

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

int main()
{
    FILE *fin;
    fin= fopen ("test.pgm","rb");
    if (fin == NULL)
    {
        printf ("ERROR");
        fclose(fin);
    }

    int i=0,j=0,u=16,v=8,d;
    char test[20];
    char k;
    char c[10];
    while((k=fgetc(fin))!='\n')
    {
        test[j]=k;  
        j=j+1;
    }

    char **img = (char**) calloc(u,sizeof(char*));
    for ( i = 0; i < u; i++ )
    {
        img[i] = (char*) calloc(v,sizeof(char));
    }

    fread(img,1,(u*v),fin);
    for (i=0; i<u; i++)
    {
        for (j=0; j<v; j++)
        {
            printf("%d ",img[i][j]);
        }
        printf("\n");
    }
    fclose(fin);
}
4

3 回答 3

3

由于您正在动态分配 16 个单独的 8 字节数组,因此您需要计算 16 个单独的读取到每个数组中。(我已经删除了不必要的,并且可能容易出错的强制转换为calloc())。

char **img = calloc(u,sizeof(char*));
for ( i = 0; i < u; i++ )
    {
    img[i] = calloc(v,sizeof(char));
    fread(img[i],1,v,fin);
    }

/*fread(img,1,(u*v),fin);*/

您的单个fread()调用适用于char img[16][8],因为在这种情况下,img它由大小为16 * 8字节的连续内存组成。但是,该调用不适用于您创建动态分配数组的方式,因为img现在是一个指针数组,因此fread()您的调用将用文件中的数据覆盖这些指针值。

如果您想对 进行一次调用fread(),则可以更改动态分配(并与 VLA 结合)

char (*img)[v];
img = malloc(u * sizeof(*img));
fread(img,1,(u*v),fin);

这声明为指向(已初始化为 8)img的数组v的指针。然后它在连续分配中分配(即 16 个)多个数组。现在,可以像你一样用于单个调用,并且还保留相同的“2D”寻址。charvuvcharimgimgfread()char img[16][8]img

于 2013-09-09T05:08:44.980 回答
2

jxh答案正确地诊断了原始代码的问题,而这个答案没有(部分是因为这个)。它还展示了 C99 中添加的可变长度数组 VLA 的强大功能。它真的很整洁,应该被接受。

如果您坚持使用 C89(可能是因为您使用 MSVC 在 Windows 上工作),那么如果您连续分配空间,您仍然可以进行单次读取。但是,如果您还打算使用双索引表示法,您仍然需要指针数组,或者您将需要使用这种表示法img[i*v+j](以及不同的类型img)。这段代码实现了额外的指针数组,还包括对原始代码的各种其他小错误修复(最重要的是它在打开文件失败后返回,而不是报告“错误”并继续,好像什么都没有出错了,包括尝试fclose()空指针,这对崩溃有好处)。

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

int main(void)
{
    const char *filename = "test.pgm";
    FILE *fin = fopen(filename, "rb");
    if (fin == NULL)
    {
        fprintf(stderr, "ERROR opening file %s\n", filename);
        return(1);
    }

    int i;
    int j = 0;
    int u=16;
    int v=8;
    char test[20];
    int k;

    while ((k = fgetc(fin)) != '\n')
        test[j++] = k;
    test[j] = '\0';
    printf("test: %s\n", test);

    char **img = (char**) calloc(u,sizeof(char*));
    char *space = (char *)calloc(u*v, sizeof(char));
    for (i = 0; i < u; i++)
        img[i] = &space[v*i];

    if (fread(img[0], 1, (u*v), fin) != (size_t)(u*v))
    {
        fprintf(stderr, "Error: short read\n");
        return(1);
    }

    for (i = 0; i < u; i++)
    {
        for (j = 0; j < v; j++)
            printf("%3d ", img[i][j]);
        printf("\n");
    }
    fclose(fin);
    free(img[0]);
    free(img);
    return(0);
}

请注意,读入的循环test没有正确检查错误;它可能会溢出,并且它也不会检测到 EOF。

输入数据:

abcdefghij
aaaaaaa
bbbbbbb
ccccccc
ddddddd
eeeeeee
fffffff
ggggggg
hhhhhhh
iiiiiii
jjjjjjj
kkkkkkk
lllllll
mmmmmmm
nnnnnnn
ooooooo
ppppppp

输出数据:

test: abcdefghij
 97  97  97  97  97  97  97  10 
 98  98  98  98  98  98  98  10 
 99  99  99  99  99  99  99  10 
100 100 100 100 100 100 100  10 
101 101 101 101 101 101 101  10 
102 102 102 102 102 102 102  10 
103 103 103 103 103 103 103  10 
104 104 104 104 104 104 104  10 
105 105 105 105 105 105 105  10 
106 106 106 106 106 106 106  10 
107 107 107 107 107 107 107  10 
108 108 108 108 108 108 108  10 
109 109 109 109 109 109 109  10 
110 110 110 110 110 110 110  10 
111 111 111 111 111 111 111  10 
112 112 112 112 112 112 112  10 
于 2013-09-09T05:26:49.917 回答
0

你进入你的指针数组,但它们指向内存中的不同位置,所以这不起作用。

为了让它工作,设置指针指向同一个块但在不同的偏移量

所以而不是

char **img = calloc(u,sizeof(char*));
for ( i = 0; i < u; i++ )
{
    img[i] = calloc(v,sizeof(char));
}

char **img = calloc(u,sizeof(char*));
char *block = calloc(u*v,sizeof(char);
for ( i = 0; i < u; i++ )
{
    img[i] = block + v*i;
}

然后

fread(block,1,(u*v),fin);
于 2013-09-09T06:30:24.553 回答