2016-12-07 3 views
-1

Я пытаюсь создать матрицу из произвольных размеров. Я могу сделать это просто, вызвав scanf в главном, а затем назначая матричные элементы в строке за строкой, но пытаясь сделать это в одной функции вне основного (и только если scanf() вызывается вне основного) дает мне ошибку Segfault:Scanf Segfaults Вне main()

int **genmat(int nrow, int ncol){ 
    int i,j; 
    int **mat = (int**) malloc(sizeof(int)*ncol*nrow); 
    char rowbuff[16]; 
    for(i=0; i < nrow; i++){ 
     INPUT: scanf("%[^\n]%*c",rowbuff); 
     if(strlen(rowbuff) != ncol){ 
      printf("Error: Input must be string of length %d\n", ncol); 
      goto INPUT; 
     } 
     else{ 
      for(j=0; j < ncol; j++){ 
       if(rowbuff[j] == '1'){ 
        mat[i][j] = 1; 
       } 
       else{ 
        mat[i][j] = 0; 
       } 
      } 
     } 
    } 
    return(mat); 
} 

следующие работы просто отлично:

int *genrow(int ncol, char *rowbuff){ 
    int i; 
    int *row = malloc(sizeof(int)*ncol); 
    for(i=0;i<ncol;i++){ 
     row[i] = rowbuff[i]%2; 
    } 
    return(row); 
} 

следующее в моей главной функции для вызова GENROW() для каждой строки матрицы:

for(i=0; i < row; i++){ 
     INPUT: scanf("%[^\n]%*c",rowbuff); 
     if(strlen(rowbuff) != col){ 
      printf("Error: Input must be string of length %d\n", col); 
      goto INPUT; 
     } 
     else{ 
      int *newrow = genrow(col, rowbuff); 
      for(j=0; j < col; j++){ 
       matrix[i][j] = newrow[j]; 
      } 
      free(newrow); 
      newrow = NULL; 
     } 
    } 

Почему поведение по-разному в этих двух контекстах?

+3

'int ** mat = (int **) malloc (sizeof (int) * ncol * nrow);' это не делает то, что вы думаете.'mat [i]' приводит к 'int *' (указатель на 'int'), который остается неопределенным. И комментарии к запасу, [прекратить использование функций выделения памяти в программе C] (https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – WhozCraig

+2

И, пожалуйста, никогда не используйте goto и label ... – Fefux

+2

'int ** mat = (int **) malloc (sizeof (int) * ncol * nrow);' должно быть 'int (* mat) [ncol] = malloc (nrow * sizeof * mat); '. – mch

ответ

0

Динамически выделяются 2D массивы, к сожалению, обременительны и уродливы в C. Чтобы правильно распределить их, очень важно, чтобы вы сделали это с одним вызовом в malloc, как и пытались сделать. В противном случае это будет не 2D-массив, а скорее некоторая сегментированная, медленная таблица поиска.

Однако результатом этого вызова malloc будет указатель на 2D-массив, а не указатель на указатель. На самом деле указатели-указатели не имеют никакого отношения к 2D-массивам - это распространенное, но неверное убеждение.

Что вы должны сделать это:

int (*mat)[nrow][ncol] = malloc(sizeof(int[nrow][ncol]); 

Это указатель массива в 2D массив. Этот синтаксис уже немного обременителен, но для ухудшения ситуации непросто передать этот указатель массива на главную, поскольку это локальная переменная указателя. Таким образом, вам нужно будет использовать указатель на указатель массива ... и нет никакого способа сделать это. Это выглядит следующим образом:

void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol]) 
{ 
    *mat = malloc(sizeof(int[nrow][ncol])); 

Чтобы облегчить обиход немного, вы можете создать временный указатель на строки, которая не требует несколько уровней косвенности и поэтому намного проще работать с:

int (*matrix)[ncol] = *mat[0]; // in the pointed-at 2D array, point at first row 

    for(size_t r=0; r<nrow; r++) // whatever you want to do with this matrix: 
    { 
    for(size_t c=0; c<ncol; c++) 
    { 
     matrix[r][c] = 1; // much more convenient syntax than (**mat)[r][c] 
    } 
    } 

От главного, вы должны вызвать такой код:

size_t row = 3; 
size_t col = 4; 

int (*mat)[row][col]; 
genmat(row, col, &mat); 

Пример:

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


void genmat (size_t nrow, size_t ncol, int (**mat)[nrow][ncol]) 
{ 
    *mat = malloc(sizeof(int[nrow][ncol])); 
    int (*matrix)[ncol] = *mat[0]; 

    for(size_t r=0; r<nrow; r++) 
    { 
    for(size_t c=0; c<ncol; c++) 
    { 
     matrix[r][c] = 1; 
    } 
    } 
} 

void printmat (size_t nrow, size_t ncol, int mat[nrow][ncol]) 
{ 
    for(size_t r=0; r<nrow; r++) 
    { 
    for(size_t c=0; c<ncol; c++) 
    { 
     printf("%d ", mat[r][c]); 
    } 
    printf("\n"); 
    } 
} 

int main (void) 
{ 
    size_t row = 3; 
    size_t col = 4; 

    int (*mat)[row][col]; 
    genmat(row, col, &mat); 

    printmat(row, col, *mat); 

    free(mat); 
    return 0; 
} 

Обратите внимание: реальный код должен адресовать случай, когда malloc возвращает NULL.

+0

Это похоже на то, что он получил. Я думаю, что я более или менее понимаю, что вы сделали с genmat (исправьте меня, если я ошибаюсь), а это то, что вы создали массив с двумя индексами в основном, сказали genmat, где он жил, а затем просто выполняли задания без указания genmat, чтобы вернуть указатель (так как '** mat [i] [j]' будет эффективно быть объектом, указывающим на указатель вместо некоторой фактической * вещи * в памяти с записями 'i * j'). Я * не знаком с тем, как работают объявления с круглыми скобками. Можете ли вы связать меня с любым хорошим материалом в декларациях? – Chib

+0

@Chib Вот более подробное объяснение: http://stackoverflow.com/questions/32050256/function-to-dynamically-allocate-matrix/32050859#32050859 – Lundin

-1

Я предполагаю, что проблемы с int **mat = (int**) malloc(sizeof(int)*ncol*nrow); Вы пытаетесь выделить 2D-массив правильно? Но это не правильный метод выделения памяти. Вы не можете выделить весь кусок памяти один короткий. Что вы должны делать здесь, выделить память для всех строк (в основном указатель для сохранения адреса столбца), а затем для столбцов

int **mat= (int **)malloc(nrow * sizeof(int *)); 
for (i=0; i<nrow; i++) 
    mat[i] = (int *)malloc(ncol * sizeof(int)); 

Смотрите эту ссылку для получения дополнительной информации http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/

+0

Это не 2D-массив, это справочная таблица. OP использует 2D-массив. Разумеется, правильный метод состоит в том, чтобы выделить память как один кусок, иначе это не будет массив. – Lundin

+0

Кстати, этот сайт ужасен, прекратите читать его и не рекомендуйте его другим. – Lundin

+0

plz предлагает альтернативный вариант для этого geeksforgeeks – pdsr

Смежные вопросы