在C语言中使用一个包含结构体二维数组的结构体的编码问题

6
我正在使用一个二维结构体数组,它是另一个结构体的一部分。由于我没有经验,所以遇到了问题。这个函数在接近结尾的“test”循环后失败了。它在 seg 错之前正确地打印出一行。

我的代码读取数据到一个虚拟的二维结构体数组的部分运行得非常好,所以问题一定出在将数组分配为另一个结构体(imageStruct)的一部分上。

如果您能提供任何帮助,我将不胜感激!

/*the structure of each pixel*/
typedef struct
{
 int R,G,B;
}pixelStruct;

/*data for each image*/
typedef struct
{ 
 int height;
 int width;
 pixelStruct *arr; /*pointer to 2-d array of  pixels*/
} imageStruct;


imageStruct ReadImage(char * filename)
{
 FILE *image=fopen(filename,"r");
 imageStruct thisImage;

        /*get header data from image*/

        /*make a 2-d array of of pixels*/
 pixelStruct imageArr[thisImage.height][thisImage.width];

        /*Read in the image. */

        /*I know this works because I after storing the image data in the
          imageArr array, I printed each element from the array to the
          screen.*/

 /*so now I want to take the array called imageArr and put it in the
   imageStruct called thisImage*/

  thisImage.arr = malloc(sizeof(imageArr));
  //allocate enough space in struct for the image array. 

 *thisImage.arr = *imageArr; /*put imageArr into the thisImage imagestruct*/

//test to see if assignment worked: (this is where it fails)

 for (i = 0; i < thisImage.height; i++)
 {
  for (j = 0; j < thisImage.width; j++)
  {
   printf("\n%d: R: %d G: %d B: %d\n", i ,thisImage.arr[i][j].R,
          thisImage.arr[i][j].G, thisImage.arr[i][j].B);
  }
 } 

 return thisImage;
}

如果你想知道我为什么首先使用了一个虚拟数组,那是因为当我开始编写这段代码时,我无法弄清楚如何做到现在我正在尝试的事情。

编辑:有人建议我在imageStruct的typedef中没有正确初始化我的二维数组。如果确实是这个问题,有人能帮我纠正吗?


顺便说一句:如果你正在处理像素,你可能想考虑使用一个平坦的线性缓冲区,然后用buffer[y*width + x]来索引点(x,y)。这是相当常见的做法,如果你必须将该缓冲区传递给其他人的代码,那么这种格式可能会有益处。 - asveikau
谢谢您的建议!我会考虑的。那么我就可以忘记这个关于二维数组的混乱了! - KMM
我得出结论,试图将2-D数组作为结构体的一部分是没有希望的。我已经转换为1-D数组,现在一切都正常了。感谢所有帮助过我的人,这是我遇到过的最有帮助的编程论坛! - KMM
5个回答

6

您似乎能够创建可变长度的数组,这意味着您在使用C99系统或支持该系统的系统上。但是,并非所有编译器都支持它们。如果您想使用它们,则不需要在结构体中声明arr指针。假设没有可变长度数组,让我们看一下您代码的相关部分:

/*data for each image*/
typedef struct
{ 
    int height;
    int width;
    pixelStruct *arr; /*pointer to 2-d array of  pixels*/
} imageStruct;

arr是指向pixelStruct的指针,而不是指向像素的二维数组。当然,您可以使用arr来访问这样的数组,但这个注释是误导性的,并暗示了一个误解。如果您真的想声明这样一个变量,您可以这样做:

pixelStruct (*arr)[2][3];

并且arr将是一个指向"像素结构体的3维数组2"的指针,这意味着arr指向一个二维数组。但这并不是你想要的。公平地说,这不是你声明的内容,所以一切都好。但你的评论表明你对C语言中的指针存在误解,这在你的代码中得到了体现。

此时,你最好阅读一篇关于C语言中数组和指针的好介绍文章,其中一篇非常好的文章是Chris Torek的C For Smarties: Arrays and Pointers。特别是,请确保你理解该页面上第一个图和函数f的所有定义。

由于你想要能够使用“列”和“行”索引以自然的方式索引arr,因此我建议你将arr声明为指向指针的指针。所以你的结构变成了:

/* data for each image */
typedef struct
{ 
    int height;
    int width;
    pixelStruct **arr; /* Image data of height*width dimensions */
} imageStruct;

然后在你的ReadImage函数中,你需要分配所需的内存:

int i;
thisImage.arr = malloc(thisImage.height * sizeof *thisImage.arr);
for (i=0; i < thisImage.height; ++i)
    thisImage.arr[i] = malloc(thisImage.width * sizeof *thisImage.arr[i]);

请注意,为了清晰起见,我没有对malloc进行任何错误检查。实际上,您应该检查malloc是否返回NULL并采取适当措施。
假设所有内存分配都成功了,现在您可以在thisImage.arr中读取您的图像(就像您在原始函数中为imageArr所做的那样)。
一旦您完成了对thisImage.arr的使用,请确保释放它:
for (i=0; i < thisImage.height; ++i)
    free(thisImage.arr[i]);

free(thisImage.arr);

实际上,您需要将上述分配和释放部分包装在它们各自的函数中,这些函数分别分配和释放arr对象,并进行错误检查。


哇,感谢你如此深入的回答!你说得对,我对C语言指针的理解很差。我想我的问题现在完全解决了。再次感谢! - KMM

2

我认为当您使用运行时大小的数组时,sizeof imageArr不会按照您的预期工作。顺便说一下,它们是C99功能中的一种“利基”功能。您应该添加一些关键值的打印输出,例如sizeof,以查看其是否符合您的预期。

更清晰的方法是使用显式分配数组:

thisImage.arr = malloc(thisImage.width * thisImage.height * sizeof *thisImage.arr);

我认为实现这样一个“真正”的二维数组是很难的(即使可能)。我建议您自己进行地址计算,例如像这样访问像素:

unsigned int x = 3, y = 1; // Assume image is larger.
print("pixel at (%d,%d) is r=%d g=%d b=%d\n", x, y, thisImage.arr[y * thisImage.width + x]);

我不认为所需的维数信息可以在运行时与数组关联起来,我认为这是不可能的。


如果高度=10,宽度=1,并且矩阵上的每个点都有3个整数用于像素结构体,则每个插槽应为3*4 = 12字节,因此对于整个矩阵,它是120...我是正确的吗?如果是这样,那么我的代码"sizeof imageArr"就可以正常工作。我尝试了你的代码,但是sizeof *thisImage.arr的结果为4。当我用你的malloc代码替换我的代码时,我得到了完全相同的结果。感谢你迄今为止的帮助! - KMM
如果 sizeof *thisImage.arr 是四,那么你展示的代码就有问题了。它应该是指向数据的大小,即 sizeof (pixelStruct)。你有包含星号吗? - unwind
是的,你说得对。我把声明从pixelstruct *arr改成了pixelstruct **arr。现在结果是12和120,但这与我的原始malloc相同。谢谢。 - KMM
我猜那就是我的问题。它无法作为二维数组工作。感谢您的所有输入!我将切换到一维。 - KMM

0

看起来您正在尝试通过赋值复制数组。 您不能使用简单的赋值运算符来做到这一点,您必须使用一些函数来复制内容,例如memcpy。

*thisImage.arr = *imageArr;
thisimage.arr[0] = imagearr[0];

上述语句执行的是相同的操作。 然而,这很可能不是导致内存损坏的原因。

由于您正在使用二维数组,请确保正确初始化它们。 查看代码,应该无法编译:在您的图像结构中声明了一维数组,但您却将其引用为二维数组?


如何在图像结构中声明二维数组?谢谢。 - KMM

0

高度和宽度未定义;您可能需要首先初始化它们,例如:

thisImage.height = 10; thisImage.width = 20;

此外,

  • colorRGB是什么?

高度和宽度是我在“获取图像头数据”部分取出的代码中定义的内容。这些值没有问题。ColorRGB是我的pixelStruct结构的原始名称。我进行了查找和替换以更改它,但我错过了一个。 - KMM

0

*thisImage.arr = *imageArr; /*将imageArr放入thisImage图像结构中*/

这样是行不通的。您必须将arr声明为colorRGB **,并相应地进行分配等操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接