Элементы матрицы не сохраняются правильно после чтения из текстового файла
В настоящее время я пытаюсь прочитать матрицу из текстового файла в c, и я пытаюсь сохранить элементы матрицы в двумерном массиве в c.
Например, в текстовом файле "Matrix.txt" у меня в настоящее время есть следующая матрица 3X16:
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
Я хочу хранить ту же самую точную матрицу в c. Программа, которую я реализовал ниже:
#include <stdio.h>
#include <stdlib.h>
#define rows_Matrix 3
#define cols_Matrix 16
int main()
{
unsigned **Matrix = (unsigned **)malloc(sizeof(unsigned *)*rows_Matrix); //Rows
for (int i = 0; i < rows_Matrix; i++) //Rows
{
Matrix[i] = (unsigned *)malloc(sizeof(unsigned) * cols_Matrix); //Columns
}
FILE *file;
file = fopen("Matrix.txt", "r");
for (int i = 0; i < rows_Matrix; i++)
{
for (int j = 0; j < cols_Matrix; j++)
{
//Read elements from a text file.
if (!fscanf(file, "%d", &Matrix[i][j]))
{
break;
}
}
}
fclose(file);
//Print Matrix.
for (int i = 0; i < rows_Matrix; i++)
{
for (int j = 0; j < cols_Matrix; j++)
{
printf("%d\t", Matrix[i][j]);
}
printf("\n");
}
return 0;
}
Когда матрица сохраняется и печатается, она выглядит следующим образом:
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0
0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0
0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0
0
Он должен храниться и печататься следующим образом:
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
Я был бы очень признателен, если бы знал, почему элементы не хранятся в матрице правильно, и я подтвердил это, когда сделал умножение матриц.
2 ответа
Кажется твой tab
разделители приводят к тому, что ваш вывод переносится по краю терминала, помещая окончательное значение в каждой строке в собственную строку. Кроме вашей неспособности free
память, которую вы используете, ваш код работает.
Это не означает, что вы находитесь в чистом виде или не могли бы сделать несколько вещей более удобным способом - это сделало бы намного более легким освобождение вашей памяти - требуя только одного вызова free
,
Вместо объявления unsigned **Matrix
(указатель на указатель на тип), объявить матрицу как указатель на массив без знака [cols_Matrix]. (по сути, указатель на массив COLS
unsigned
ценности. Тогда вам нужно всего лишь выделить 3 строки, чтобы выделить всю память для вашей матрицы.
(Я избегаю печатать, поэтому переменные в примере ниже короче...)
Например, вы можете объявить matrix
как
#define ROWS 3
#define COLS 16
...
unsigned (*matrix)[COLS] = NULL, /* pointer to array of COLS elem */
row = 0, /* row counter */
col = 0; /* column counter */
Теперь единственное распределение - это все, что нужно:
matrix = malloc (ROWS * sizeof *matrix); /* allocate matrix */
if (!matrix) { /* validate allocation */
perror ("malloc-matrix");
return 1;
}
(Нет необходимости бросать возвращение malloc
, это ненужно. Смотрите: я разыгрываю результат malloc?)
Остальное похоже на то, что вы сделали. Нет ничего плохого в чтении форматированных целочисленных значений из файла с fscanf
а также %u
(или любой спецификатор числового преобразования), так как спецификатор числового преобразования будет занимать все начальные пробелы (включая новые строки). Однако вам необходимо явно проверить ваши строки / столбцы во время чтения, чтобы защитить границы памяти и предотвратить запись вне выделенного блока, например
/* read while row < ROWS & good value read */
while (row < ROWS && fscanf (fp, "%u", &matrix[row][col]) == 1) {
if (++col == COLS) { /* increment col, test against COLS */
row++; /* on match - increment row */
col = 0; /* reset col */
}
}
Теперь вы должны проверить, что все ваши данные были правильно прочитаны. Проверка окончательных значений row == ROWS
предоставляет подтверждение, например
if (row != ROWS) { /* validate all data read */
fprintf (stderr, "error: failed to read all %dx%d matrix.\n",
ROWS, COLS);
return 1;
}
Тогда достаточно просто вывести данные для подтверждения и освободить выделенную вами память, например
for (unsigned i = 0; i < ROWS; i++) { /* output matrix */
for (unsigned j = 0; j < COLS; j++)
printf ("%4u", matrix[i][j]);
putchar ('\n');
}
free (matrix); /* don't forget to free mem (single free!) */
В целом, вы можете сделать что-то вроде следующего:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 16
int main (int argc, char **argv) {
unsigned (*matrix)[COLS] = {NULL}, /* pointer to array of COLS elem */
row = 0, /* row counter */
col = 0; /* column counter */
/* read file provided as 1st argument (default stdin if no argument) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
matrix = malloc (ROWS * sizeof *matrix); /* allocate matrix */
if (!matrix) { /* validate allocation */
perror ("malloc-matrix");
return 1;
}
/* read while row < ROWS & good value read */
while (row < ROWS && fscanf (fp, "%u", &matrix[row][col]) == 1) {
if (++col == COLS) { /* increment col, test against COLS */
row++; /* on match - increment row */
col = 0; /* reset col */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (row != ROWS) { /* validate all data read */
fprintf (stderr, "error: failed to read all %dx%d matrix.\n",
ROWS, COLS);
return 1;
}
for (unsigned i = 0; i < ROWS; i++) { /* output matrix */
for (unsigned j = 0; j < COLS; j++)
printf ("%4u", matrix[i][j]);
putchar ('\n');
}
free (matrix); /* don't forget to free mem (single free!) */
return 0;
}
Пример входного файла
$ cat dat/3x16mat.txt
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
Пример использования / Вывод
$ ./bin/matrix_3x16 dat/3x16mat.txt
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
Использование памяти / проверка ошибок
В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанности в отношении любого выделенного блока памяти: (1) всегда сохранять указатель на начальный адрес для блока памяти, поэтому (2) его можно освободить, если его нет больше нужно
Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы убедиться, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или основать условный переход на неинициализированном значении и, наконец, подтвердить что вы освобождаете всю выделенную память.
Для Linux valgrind
это нормальный выбор. Есть похожие проверки памяти для каждой платформы. Все они просты в использовании, просто запустите вашу программу через него.
$ valgrind ./bin/matrix_3x16 <dat/3x16mat.txt
==24839== Memcheck, a memory error detector
==24839== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==24839== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==24839== Command: ./bin/matrix_3x16
==24839==
0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0
0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0
0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0
==24839==
==24839== HEAP SUMMARY:
==24839== in use at exit: 0 bytes in 0 blocks
==24839== total heap usage: 1 allocs, 1 frees, 192 bytes allocated
==24839==
==24839== All heap blocks were freed -- no leaks are possible
==24839==
==24839== For counts of detected and suppressed errors, rerun with: -v
==24839== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Всегда проверяйте, что вы освободили всю выделенную память и что ошибок памяти нет.
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.
Похоже, что нет проблем с сохранением вашей матрицы как таковой. Похоже, что перекос дисплея вызван ограниченным пространством на вашем экране. Просто замените вкладку двумя пробелами, изменив строку
printf("%d\t", Matrix[i][j]);
в
printf("%d ", Matrix[i][j]);
Это должно работать.