Проблема кодирования с использованием двумерного массива структур внутри другой структуры в C

Я работаю с двумерным массивом структур, который является частью другой структуры. Это не то, с чем я многое сделал, поэтому у меня проблема. Эта функция завершается сбоем после прохождения "тестового" цикла for ближе к концу. Он правильно выводит одну строку, прежде чем обнаружит ошибки.

Части моего кода, которые считывают данные в фиктивный двумерный массив структур, работают очень хорошо, поэтому мой массив должен быть частью другой структуры (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;
}

(В случае, если вам интересно, почему я использую фиктивный массив в первую очередь, это потому, что когда я начал писать этот код, я не мог понять, как сделать то, что я пытаюсь сделать сейчас.)

РЕДАКТИРОВАТЬ: Один человек предположил, что я не правильно инициализировал мой 2-мерный массив в typedef для imageStruct. Может ли кто-нибудь помочь мне исправить это, если это действительно проблема?

5 ответов

Решение

Похоже, вы можете создавать массивы переменной длины, поэтому вы работаете в системе C99 или в системе, которая ее поддерживает. Но не все компиляторы поддерживают их. Если вы хотите использовать их, вам не нужно arr объявление указателя в вашей структуре. Предполагая отсутствие массивов переменной длины, давайте посмотрим на соответствующие части вашего кода:

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

arr это указатель на pixelStructа не к 2-му массиву пикселей. Конечно, вы можете использовать arr получить доступ к такому массиву, но комментарий вводит в заблуждение, и он намекает на недоразумение. Если вы действительно хотите объявить такую ​​переменную, вы должны сделать что-то вроде:

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

а также arr будет указатель на "массив 2 из массива 3 pixelStruct", что означает, что arr указывает на 2-й массив. Это не совсем то, что вы хотите. Честно говоря, это не то, что вы заявляете, так что все хорошо. Но ваш комментарий предполагает неправильное понимание указателей в C, и это проявляется позже в вашем коде.

На этом этапе вам будет полезно прочесть хорошее введение в массивы и указатели на C, и действительно хорошим является C For Smarties: Arrays and Pointers от Chris Torek. В частности, пожалуйста, убедитесь, что вы понимаете первую диаграмму на странице и все в определении функции 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 объект, и позаботьтесь о проверке ошибок.

Я не думаю sizeof imageArr работает так, как вы ожидаете, когда используете массивы во время выполнения. Что, кстати, является своего рода "нишевой" функцией C99. Вы должны добавить некоторые распечатки важных значений, такие как sizeof чтобы увидеть, если он делает то, что вы думаете.

Более понятным было бы использовать явное выделение массива:

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

Я также думаю, что трудно (если вообще возможно) реализовать "настоящий" 2D-массив, подобный этому. Я бы порекомендовал просто выполнить вычисление адреса самостоятельно, то есть получить доступ к такому пикселю:

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

Я не вижу, как требуемая информация измерения может быть связана с массивом во время выполнения; Я не думаю, что это возможно.

Высота и ширина не определены; вы можете сначала инициализировать их, как в

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

также,

  • что такое colorRGB?

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

Это не сработает. Вы должны объявить обр как colorRGB **распределить его соответственно и т. д.

Похоже, что вы пытаетесь скопировать массив по присваиванию. Вы не можете использовать простой оператор присваивания, чтобы сделать это, вы должны использовать некоторую функцию для копирования вещей, например memcpy.

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

Вышеуказанные заявления делают то же самое. Однако это, скорее всего, не является причиной повреждения памяти.

Поскольку вы работаете с двумерными массивами, убедитесь, что вы правильно их инициализируете. Глядя на код, не следует даже компилировать: массив объявлен как одномерный в вашей структуре изображения, но вы называете двумерным?

Другие вопросы по тегам