Проблема с выделением памяти для функции - PullRequest
0 голосов
/ 13 мая 2019

После компиляции и запуска функции я получаю ошибку сегментации: 11. Я считаю, что malloc должен выполняться правильно, поэтому я не уверен, почему я получаю ошибку сегмента. Любая идея будет принята с благодарностью!

typedef struct matrix matrix;

struct matrix {
   unsigned int n_rows;
   unsigned int n_cols;
   float **entries;
};

//refer to matrix.h
matrix *matrix_zero(unsigned int n_rows, unsigned int n_cols){
  struct matrix* new = (struct matrix*)malloc(sizeof(struct matrix));
  new->entries = malloc(n_rows * n_cols * sizeof(float));
  new->n_rows=n_rows;
  new->n_cols=n_cols;
  for(int x = 0; x < n_rows; x++){
    for(int y = 0; y < n_cols; y++){
      new->entries[x][y] = 0;
    }
  }
  return new;
}

/* main: run the evidence functions above */
 int main(int argc, char *argv[])
 {
   struct matrix* test1 = matrix_zero(3,3);
   // matrix_show(test1);
 }

Ответы [ 2 ]

4 голосов
/ 13 мая 2019

Проблема, по-видимому, в вашем распределении для matrix->entries. Структура определяет указатель на указатель, но вы выделяете указатель с плавающей точкой float* против float**. Вам нужно выделить n_rows число float*, и каждый из них должен указывать на распределение n_cols число float значения. Например:

int i;
// No error checking shown here
new->entries = malloc(sizeof(float*) * n_rows);
for (i = 0; i < n_rows; i++) {
    new->entries[i] = malloc(sizeof(float) * n_cols);
}
0 голосов
/ 17 мая 2019

Вы выделили массив для rows размером cols, но компилятор не может узнать фактический размер строки для каждой строки, поэтому запись entries[i] действительно ожидает указатель на простой массив плавает, а не двумерный массив. Это одно из основных отличий в структуре от n-мерного массива и массивов указателей в C. Компилятор знает, как его измерять, только когда вы полностью определите размеры массива (например, когда вы объявляете его как float entries[N][M]; --- посмотрите, что вы не можете использовать переменные выражения в измерениях, только статические константы времени компиляции)

У вас есть два подхода:

  • Использование одного массива измерений для вычисления индекса на основе размеров строк:

    typedef struct matrix matrix;
    
    struct matrix {
        unsigned int n_rows;
        unsigned int n_cols;
        float *entries;  /* we make this to point to a single array of n_rows * n_cols entries */
    };
    
    
    new->entries = malloc(n_rows * n_cols * sizeof(float));
    new->n_rows=n_rows;
    new->n_cols=n_cols;
    for(int x = 0; x < n_rows; x++){
        for(int y = 0; y < n_cols; y++){
            new->entries[x * n_cols + y] = 0.0; /* entry position should be as shown */
    }
    
  • Использовать отдельные массивы строк из n_cols записей (это уже было показано в другом ответе @joel)

    typedef struct matrix matrix;
    
    struct matrix {
        unsigned int n_rows;
        unsigned int n_cols;
        float **entries;  /* this time the entries field points to an array of pointers to float. */
    };
    
    new->entries = malloc(n_rows * sizeof *new->entries);  /* individual cells are 'float *', not 'float' this time. */
    new->n_rows=n_rows;
    new->n_cols=n_cols;
    for(int x = 0; x < n_rows; x++){
        new->entries[x] = malloc(n_cols* sizeof **new->entries); /* this time float *'s are here */
        for(int y = 0; y < n_cols; y++){
            new->entries[x][y] = 0; /* entry position should be as shown */
        }
    }
    

Оба метода имеют замечания:

  • Первый метод требует только один malloc(3) для массива entry, так что это упрощает распределение и освобождение, но некоторые реализации могут ограничивать фактический размер одного malloc(3) в случае, если вы хотите выделить огромные матрицы , Это также облегчает освобождение всей матрицы.

  • Второй метод требует только malloc из n_rows указателей и n_rows malloc из n_cols float s. Это позволит выделить огромные матрицы (вы никогда не выделите всю матрицу в одном фрагменте), но вам придется сначала освободить все строки, а затем массив указателей на строки, прежде чем освобождать структуру матрицы.

  • Я рекомендую вам использовать malloc(n_cols * sizeof *new->entries) вместо malloc(n_cols * sizeof (float *)), поэтому вам не нужно менять это выражение в случае, если вы измените тип определения new->entries.

Наконец, подумайте, что в языке C нет магии в отношении вызова функций. Вы, вероятно, ошибочно предположили, что создание malloc( n_rows * n_cols * sizeof(float) ) автоматически преобразует указатель в двумерный массив , но в этом нет ничего волшебного, malloc(3) - это обычная функция C, подобная той, которую вы можете написать, и именно поэтому требуется фактическое количество байтов, а не размеры (в элементах) массива.

...