C — запись структуры в 2D-массив вызывает ошибку сегментации

#arrays #c #struct #segmentation-fault #pointer-to-pointer

#массивы #c #структура #ошибка сегментации #указатель на указатель

Вопрос:

Я пытаюсь написать программу, которая считывает текстовый файл в 2D-массив структур, но попытка поместить структуру в этот массив приводит к сбою программы.

Вот программа

ppm.c

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

image parse_ascii_image(FILE *fp) {
  char magic[3];
  char comm[1024];
  char size[10];
  image img;
  int height;
  int width;

  ... // some code
  
  pixel **pixelarr;
  printf("Commencing internal malloc...n");
  if (height <= 1024 amp;amp; width <= 1024 amp;amp; height > 0 amp;amp; width > 0){
    pixelarr = (pixel **) malloc(height * sizeof(pixel*));
  }else{
    fprintf(stderr, "Error: Invalid image size: %d * %d", width, height);
    return img;
  }
  for (int i = 0; i < height; i  ){
    pixelarr[i] = malloc(width * sizeof(pixel));
    
  }

  int d = 0;
  int e;
  printf("Filling in array:n");

  for (int row = 0; row < height; row  ){
    for (int col = 0; col < width; col  ){
      for (int i = 0; i < 3; i  ){
        while ((e = fgetc(fp)) != 'n'){
          d = d * 10;
          e = e - 60;
          d  = e;
        }
        if (i == 0){
          pixelarr[row][col].red = d;
        }
        if (i == 1){
          pixelarr[row][col].green = d;
        }
        if (i == 2){
          pixelarr[row][col].blue = d;
        }
        d = 0;
      }      
    }
  }
  printf("Finished! Copying pixels over: n");
  for (int row = 0; row < height; row  ){
    for (int col = 0; col < width; col  ){
      img.pixels[row][col] = pixelarr[row][col];
    // ^^^This is where the program crashes
    }
  }
  printf("Finished! Freeing internal malloc:n");
  
  ... // some more code

}
 

соответствующая информация из ppm.h:

 #ifndef PPM_H
#define PPM_H 1

#include <stdio.h>

...

typedef struct pixel pixel;
struct pixel {
  int red;
  int green;
  int blue;
};

typedef struct image image;
struct image {
  enum ppm_magic magic; // PPM format
  char comments[1024];  // All comments truncated to 1023 characters
  int width;            // image width
  int height;           // image height
  int max_color;        // maximum color value
  pixel **pixels;       // 2D array of pixel structs.
};

...

// Parses an ASCII PPM file.
image parse_ascii_image(FILE *fp);

...

#endif
 

Если кто-нибудь может помочь мне выяснить, что вызывает сбой моей программы, я был бы признателен.
Спасибо!

Комментарии:

1. img.pixels никогда не инициализируется. Кажется , все указывает на то, что вы должны просто заменить эти конечные вложенные циклы img.pixels = pixelarr; и НЕ освобождать pixelarr их впоследствии. Это касается того, кто принимает возвращаемое изображение. Вы также должны правильно инициализировать все элементы img .

2. относительно: enum ppm_magic magic; // PPM format это объявление экземпляра определенного enum типа. Но перечисление никогда не определяется перед использованием

3. относительно: struct pixel { int red; int green; int blue; }; «Цвета» в пикселе составляют 8 бит каждый, а не int (4 или 8 байт)

4. OT: относительно; pixelarr = (pixel **) malloc(height * sizeof(pixel*)); и pixelarr[i] = malloc(width * sizeof(pixel)); 1) содержимое pixel неправильно определено. (и вы предполагаете, что пиксель равен 24 битам) 2) возвращаемый тип void* — это тот, который может быть присвоен любому указателю. Приведение просто загромождает код и подвержено ошибкам. 3) всегда проверяйте (!= NULL) возвращаемое значение, чтобы убедиться, что операция прошла успешно. Если не удалось (== NULL), сообщите пользователю через: perror( "malloc failed" ); , который выведет stderr как ваше сообщение об ошибке, так и текстовую системную ошибку.

5. относительно: pixelarr[i] = malloc(width * sizeof(pixel)); строка изображения должна быть кратна 4 (независимо от видимой ширины изображения), поэтому этот оператор может быть недостаточно длинным, чтобы вместить всю строку. из-за вышесказанного this: for (int row = 0; row < height; row ){ for (int col = 0; col < width; col ){ имеет очень хорошие шансы не получить доступ ко всем правильным пикселям

Ответ №1:

Несколько проблем:
1: img.pixels никогда не инициализируется. Каждый раз, когда вы создаете указатель на что-либо, не присваивая ему сначала значение, попробуйте установить для него значение NULL, чтобы упростить отладку. Обратите внимание, что это не решит проблему. Чтобы исправить это, просто инициализируйте их экземпляром struct .
2: Вы должны освободить pixelarr . Большинство современных ОС делают это, но это все еще очень, очень хорошая практика.
3: Не было бы проще не использовать вложенные циклы, а вместо этого делать img.pixels = pixelarr ? Он достигает того же (если это не для класса, и эта часть обязательна).