@barboskin93

Как исправить ошибку при выводе матрицы?

Написал код для получения размера и содержимого матрицы, но не получается ее вывести на экран. После компиляции выводит ошибку segmentation fault.

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

int input(int* n, int* m, int ***matrix, int *flag);
void output(int n, int m, int **matrix);


int main() {
    int n, m;
    int flag =0;
    int **matrix;
    if(input(&n,&m,&matrix,&flag)) {
        output(n,m,matrix);
    } else {
        printf("n/a");
    }
    /*free(matrix[n][m]);*/

   return 0;
}


int input(int *n, int *m, int ***matrix, int *flag) {
    char ch;
    if (((scanf("%d%d%c", n,m, &ch)) || (ch != '\n')) && ((*n <= 0) || (*m <=0))){
        *flag =0;
    } else{
        **matrix = (int *)malloc((*n) * sizeof(int*));
        for (int i; i < *n; i++ ){
        for (int j; j < *m; j++) {
            **matrix = (int *)malloc((*n * *m) * sizeof(int));

            if (scanf("%d", matrix[i][j])) {
                
            } else {
               *flag =0; 
            }
        }
    }
    } 
return *flag =1;
}

void output(int n, int m, int **matrix){
    for(int i = 0; i < n; i ++){
        for(int j =0; j < m; j++){
            printf("%d", matrix[i][j]);
        }
    }
}
  • Вопрос задан
  • 158 просмотров
Решения вопроса 1
includedlibrary
@includedlibrary
int input(int *n, int *m, int ***matrix, int *flag) {
    char ch;
    // Зачем считывать ch, я не понял. Также проверка у вас неправильная.
    // scanf возвращает число считанных элементов, вам надо сравнивать это
    // число с 2, так как вы считываете n и m.
    // if(scanf("%d%d", n,m) != 2 || *n <= 0 || *m <= 0)
    //     return 0;
    if (((scanf("%d%d%c", n,m, &ch)) || (ch != '\n')) && ((*n <= 0) || (*m <=0))){
        *flag =0;
        // Тут просто сделать return 0;
    } else{
        // Всё, что ниже, нужно вынести из else блока, а сам else блок убрать
        **matrix = (int *)malloc((*n) * sizeof(int*));
        for (int i; i < *n; i++ ){
        for (int j; j < *m; j++) {
            **matrix = (int *)malloc((*n * *m) * sizeof(int));

            // if(scanf("%d", &((*matrix)[i][j])) != 1)
            //     return 0;
            if (scanf("%d", matrix[i][j])) {
                
            } else {
               *flag =0;
            }
        }
    }
    } 
// return 1;
return *flag =1;
}


Тут вы используете неверный указатель:
scanf("%d", matrix[i][j]) // так не надо
scanf("%d", &((*matrix)[i][j])) // надо так
scanf("%d", *(*matrix + i) + j) // или так


Не понятно, зачем flag делать указателем, можно объявить его в input, присвоить 1 или 0 и вернуть. Кстати, у вас сравнение неверное, сейчас возвращается всегда 1:
// очевидно, имелось в виду *flag == 1
// Но вообще, можно просто вернуть *flag.
// Или везде, заменить присваивание *flag = что_то на return что_то
return *flag =1;


Так же у вас абсолютно неверно выделяется память:
// Тут каст неверный, должно быть (int**),
// Но в си касты void* к другим типам указателей
// можно опускать. Также нужна лишь одна операция разыменовывания для matrix
**matrix = (int *)malloc((*n) * sizeof(int *));
// Забыли присвоить 0 в i
for (int i; i < *n; i++) {
  // А этот цикл надо сделать после выделения памяти для m столбцов
  // для ввода данных в выделенную память. Тут тоже забыли присвоить 0 в j.
  for (int j; j < *m; j++) {
    // Вот тут вы перезаписываете первую строку matrix,
    // хотя хотели выделить m столбцов для i строки.
    // До перазаписи дело, правда, не дойдёт, так как на предыдущем шаге
    // вы сделали два разыменовывания вместо одного и уже словили segfault
    **matrix = (int *)malloc((*n * *m) * sizeof(int));
    // ...
  }
}


Исправляется элементарно:
*matrix = malloc(*n * sizeof(int*));
for (int i = 0; i < *n; i++) {
    // *matrix - указатель на двумерный массив,
    // *matrix + i - указатель на строку (которая является указателем на одномерный массив),
    // *(matrix + i) = ... - присваивание указателю на строку адреса выделенной памяти
    *(*matrix + i) = malloc(*m * sizeof(int));
    for(int j = 0; j < *m; j++) {
        // Ввод данных
    }
}


Ну и совет на будущее - не используйте scanf, хотя проблема сейчас и не в ней. Желательно проверять результат malloc на NULL, чтобы корректно завершать программу в случае нехватки памяти, а не выводить segfault, или не завершать, а просто вызвращать ошибку и продолжать работу дальше. Также не используйте конструкции вида int ***matrix, лучше сделайте функцию, которая принимает n и m и возвращает указатель на матрицу, также сделайте отдельную функцию для ввода значений и вывода.

int** create_matrix(int n, int m);
bool read_matrix(int n, int m, int **matrix);
void write_matrix(int n, int m, int **matrix);
void free_matrix(int n, int m, int **matrix);


Ну и 2 мерный массив можно сделать через одномерный, так будет меньше вызовов malloc, а значит потенциально меньше обращений к ядру. Также, если данные всего двумерного массива будут лежать последовательно, велика вероятность, что в циклах большая часть значений будет браться из кэша, а не из памяти, что даст выигрыш в скорости.
int n = 10, int m = 5;
int *matrix = malloc(sizeof(int) * n * m);
for(int i = 0; i < n; i++) {
    for(int j = 0; j < m; j++) {
        matrix[i * m + j] // обращение к элементу в i строке в j столбце
    }
}


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

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы