Это предварено моими главными комментариями.
Мне пришлось провести рефакторинг dim
, чтобы обработать произвольно большую матрицу, поэтому мне пришлось сканировать первую строку файла char-by-char, считая пробелыстроки (что дает количество столбцов - 1).Он обрабатывает / удаляет начальные / конечные пробелы [искажено]
У меня было dim
, затем перематывайте файл и используйте fscanf
и realloc
для динамического создания матрицы.
Вот рабочий код [прошу прощения за бесполезную очистку стиля]:
#include <stdio.h>
#include <stdlib.h>
struct mat {
int cols;
int rows;
double *m;
};
// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
int c;
int c2;
FILE *f = fopen(file, "r+");
// strip leading whitespace [if any] off first line
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n')
break;
if (c != ' ')
break;
}
// scan first line and count columns (number of space separaters)
while (1) {
c2 = ' ';
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n') {
if (c2 != ' ')
++cols;
break;
}
if (c == ' ') {
if (c != c2)
++cols;
break;
}
c2 = c;
}
if (c == '\n')
break;
}
// convert number of whitespace separaters into number of columns
if (cols > 0)
++cols;
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failure\n");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0; idx < cols; ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}
double *
alloc_matrix(int cols, int rows)
{
double *m = (double *) malloc(cols * rows * sizeof(double));
if (m == 0) {
printf("Memory allocation error.\n");
exit(-1);
}
return m;
}
void
multiplication(double *m1, double *m2, double *m3, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m3[i * cols + j] = 0;
for (int k = 0; k < cols; k++) {
m3[i * cols + j] += m1[i * cols + k] * m2[k * cols + j];
}
}
}
}
void
write_matrix(double *m, int cols, int rows)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%f ", m[i * cols + j]);
}
printf("\n");
}
}
int
main(int argc, char *argv[])
{
if (argc < 3) {
printf("Not enough arguments.\n");
exit(1);
}
struct mat m1 = dim(argv[1]);
struct mat m2 = dim(argv[2]);
printf(" %d %d \n", m1.cols, m1.rows);
printf(" %d %d \n", m2.cols, m2.rows);
int c1 = m1.cols;
int r1 = m1.rows;
int c2 = m2.cols;
int r2 = m2.rows;
if (r1 != c2) {
printf("Matrixes are not suitable for multiplication.\n");
exit(-1);
}
double *mtx3 = alloc_matrix(c1, r2);
multiplication(m1.m, m2.m, mtx3, c1, r2);
write_matrix(mtx3, c1, r2);
free(m1.m);
free(m2.m);
free(mtx3);
return 0;
}
Вот два тестовых файла, которые я использовал.Обратите внимание, что, хотя вы не видите его, в первой строке есть пробел [в качестве теста]:
Это m1.txt
:
1 2 3 4
5 6 7 8
9 10 11 12
Вот второй файл:
1 2 3
4 5 6
7 8 9
10 11 12
Вот вывод программы:
4 3
3 4
38.000000 44.000000 202.000000 232.000000
98.000000 116.000000 438.000000 504.000000
158.000000 188.000000 674.000000 776.000000
9.000000 10.000000 87.000000 100.000000
ОБНОВЛЕНИЕ:
Вот альтернативная функция dim
, которая заменяет[несколько хрупкое] сканирование по символам первой строки с поиском новой строки [для получения длины строки], затем malloc
буфера, fgets
, а затем цикл по strtok
для подсчета не-пространство строк в строках (т.е. количество столбцов):
// size and read in matrix
struct mat
dim(const char *file)
{
struct mat m;
int rows = 0;
int cols = 0;
int maxcnt;
int curcnt;
int ret;
char *buf;
char *bp;
char *tok;
int c;
int c2;
FILE *f = fopen(file, "r+");
// count number of chars in first line of the file
curcnt = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
++curcnt;
if (c == '\n')
break;
}
++curcnt;
buf = malloc(curcnt);
rewind(f);
fgets(buf,curcnt,f);
cols = 0;
bp = buf;
while (1) {
tok = strtok(bp," \n");
if (tok == NULL)
break;
++cols;
bp = NULL;
}
free(buf);
rewind(f);
m.rows = 0;
m.cols = cols;
m.m = NULL;
curcnt = 0;
maxcnt = 0;
while (1) {
if (curcnt >= maxcnt) {
maxcnt += m.cols * 100;
double *tmp = realloc(m.m,sizeof(double) * maxcnt);
if (tmp == NULL) {
printf("dim: realloc failure\n");
exit(1);
}
m.m = tmp;
}
ret = 0;
for (int idx = 0; idx < cols; ++idx, ++curcnt) {
ret = fscanf(f, "%lf", &m.m[curcnt]);
if (ret != 1)
break;
}
if (ret != 1)
break;
rows += 1;
}
fclose(f);
m.rows = rows;
// trim matrix to actual size;
m.m = realloc(m.m,sizeof(double) * rows * cols);
return m;
}
ОБНОВЛЕНИЕ № 2:
Мне не понравилось ни одно решение дляполучим количество столбцов, поэтому вот более чистый, который быстрее первого, но проще и менее громоздок:
// scan first line and count columns
int
colcalc(FILE *f)
{
int c;
int noncur;
int nonprev = 0;
int cols = 0;
while (1) {
c = fgetc(f);
if (c == EOF)
break;
if (c == '\n')
break;
// only count non-whitespace chars
switch (c) {
case ' ':
case '\t':
noncur = 0;
break;
default:
noncur = 1;
break;
}
// column starts on _first_ char in word
if (noncur)
cols += (noncur != nonprev);
nonprev = noncur;
}
rewind(f);
return cols;
}
ОБНОВЛЕНИЕ № 3:
Я опробовал 2 предыдущих способа, и он работает так гладко!Еще раз, спасибо!и ваши комментарии о том, как сделать мою программу проще с меньшим количеством переменных и прочего!
Не за что!
Мой стиль / методология кодирования взят из [очень] старой книги: ««Элементы стиля программирования» Кернигана и Плаугера.
Примеры из этой книги написаны на Фортране, но максимумы находятся в одном ряду с «Завершенным кодом» Стива Макконнелла.
Из главы 7[Эффективность и инструменты]:
- Сделайте это правильно, прежде чем сделать это быстрее.
- Держите это правильно, когда вы сделаете это быстрее.
- Сделайте так, чтобы вам было ясносделайте это быстрее.
- Не жертвуйте ясностью ради небольшого увеличения "эффективности".
- Не напрягайтесь, чтобы повторно использовать код;Вместо этого реорганизуйте.
- Убедитесь, что особые случаи действительно особенные.
- Упрощайте, чтобы сделать это быстрее.
- Не делайте код, чтобы сделать это быстрее - найдителучший алгоритм.
- Инструмент ваших программ.Измерьте, прежде чем вносить изменения в «эффективность».