ОК - эта программа реорганизована больше. Выделены три большие секции - матрица (с именем), набор матриц, и пользователский интрефейс. Более или менее ограничен доступ к внутренней структуре. Наверное, правильнее было бы вынуть имя из матрицы, но уж совсем кромсать программу не хотелось. Как рыбе воды, не хватаеат exceptions для обработки ошибок. Тяжко, господа, на C писати. Из-за этого в matrix_read() и размер, и goto. И еще одна хитрость -
float Values[0]; в описании матрицы. Во первых, матрица отводиться прямо в структуре. Во вторых,
Values[0]; позволяют обращаться к массиву в конце, не отводя памяти. Коли не будет компилироваться, надо ноль на единичку поменять.
Код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define FILENAME "matrizes.dat"
#define MAXNAMESZ 80
#define MAXDIMSZ 40
#define MAXLINESZ 256
#define MAXDIM 100
#define MATRIXLISTSTEP 100
#define MXELEMENT(mx, r, c) ((mx)->Values[(mx)->Cols * (r) + (c)])
#define E_FFORMAT -16384
#define E_FEOF -16383
typedef struct marix_type
{
char* Name;
int Rows;
int Cols;
float Values[0];
} MATRIX;
typedef struct matrix_list_type
{
int Num_matrixes;
int Matrixes_size;
MATRIX** Matrixes;
} MATRIX_LIST;
/******************************************************************************************
** miscelaneous utilities
******************************************************************************************/
// allocate memory for string and copy it
char* mkstr(const char* s)
{
char* p;
p = (char*)malloc(strlen(s)+1);
if (p == NULL) {
return "*** error *** not enough memory";
} else {
strcpy(p, s);
return p;
}
}
// read string form file
int getstr(FILE* f, char* buffer, int buffersz) {
char dummy[80];
char* p;
p = fgets(buffer, buffersz, f);
if (p == NULL) {
buffer[0] = 0;
return -1;
} else {
int failed = 0;
if (buffer[strlen(buffer)-1] == '\n') {
// delete end-of-line symbol
buffer[strlen(buffer)-1] = 0;
} else {
// flush rest of the line
while ((p != NULL) && (p[strlen(p)-1] != '\n')) {
p = fgets(dummy, sizeof(dummy), f);
failed = 1;
}
}
return (failed? -1: (int)strlen(buffer));
}
}
/******************************************************************************************
** matrix management
******************************************************************************************/
MATRIX* matrix_create(const char* name, int rows, int cols) {
MATRIX* matrix;
size_t mxsize;
mxsize = sizeof(MATRIX) + sizeof(matrix->Values[0])*(rows*cols);
matrix = (MATRIX*)malloc(mxsize);
memset(matrix, 0, mxsize);
matrix->Name = mkstr(name);
matrix->Rows = rows;
matrix->Cols = cols;
return matrix;
}
void matrix_delete(MATRIX* matrix) {
free(matrix->Name);
free(matrix);
}
void matrix_fill_random(MATRIX* matrix) {
int i, j;
srand((int)time(NULL));
for (i=0; i < matrix->Rows; i++) {
for (j=0; j < matrix->Cols; j++) {
MXELEMENT(matrix, i, j) = (float)rand() / RAND_MAX;
}
}
}
MATRIX* matrix_transpose(MATRIX* matrix, const char* name) {
MATRIX* trans_matrix;
int i, j;
trans_matrix = matrix_create(name, matrix->Cols, matrix->Rows);
for (i=0; i<trans_matrix->Rows; i++) {
for(j=0; j<trans_matrix->Cols; j++) {
MXELEMENT(trans_matrix, i, j) = MXELEMENT(matrix, j, i);
}
}
return trans_matrix;
}
MATRIX* matrix_sum(MATRIX* matrix1, MATRIX* matrix2, const char* name) {
MATRIX *res_matrix;
int i, j;
res_matrix = matrix_create(name, matrix1->Rows, matrix1->Cols);
for (i=0; i < res_matrix->Rows; i++) {
for (j=0; j < res_matrix->Cols; j++) {
MXELEMENT(res_matrix, i, j) = MXELEMENT(matrix1, i, j) + MXELEMENT(matrix2, i, j);
}
}
return res_matrix;
}
void matrix_show(MATRIX* matrix) {
int i, j;
printf("%s:\n", matrix->Name);
printf("%d x %d\n", matrix->Rows, matrix->Cols);
for (i=0; i<matrix->Rows; i++) {
for (j=0; j<matrix->Cols; j++) {
printf(" %.4f", MXELEMENT(matrix, i, j));
}
putchar('\n');
}
putchar('\n');
}
int matrix_write(MATRIX* matrix, FILE* f) {
int i, j;
int res;
res = fprintf(f, "%s;%d;%d\n", matrix->Name, matrix->Rows, matrix->Cols);
if (res < 0) return res;
for(i=0; i < matrix->Rows; i++) {
for(j=0; j < matrix->Cols; j++) {
res = fprintf(f, "%d,%d,%.4f\n", i, j, MXELEMENT(matrix, i, j));
if (res < 0) return res;
}
}
res = fprintf(f, "\n");
return res;
}
int matrix_read(MATRIX** pmatrix, FILE*f) {
MATRIX* matrix = NULL;
int i, j, ii, jj;
int rows, cols;
char line[MAXLINESZ], *ptr, ch1, ch2, ch3;
float x;
int res;
*pmatrix = NULL;
res = getstr(f, line, sizeof(line));
if (res == -1) return E_FEOF;
if (res < 0) goto error;
ptr = strchr(line, ';');
if (ptr == NULL) goto format_error;
*ptr = 0;
res = sscanf(ptr+1, "%d%c%d%c", &rows, &ch1, &cols, &ch2);
if ((res != 3) || (ch1 != ';') || (rows < 1) || (rows > MAXDIM) || (cols < 1) || (cols > MAXDIM)) {
goto format_error;
}
matrix = matrix_create(line, rows, cols);
for(i=0; i < matrix->Rows; i++) {
for(j=0; j < matrix->Cols; j++) {
res = getstr(f, line, sizeof(line));
if (res < 0) goto error;
res = sscanf(line, "%d%c%d%c%f%c", &ii, &ch1, &jj, &ch2, &x, &ch3);
if ((res != 5) || (ch1 != ',') || (ch2 != ',') || (ii != i) || (jj != j)) {
goto format_error;
}
MXELEMENT(matrix, i, j) = x;
}
}
res = getstr(f, line, sizeof(line));
if (res != 0) goto format_error;
*pmatrix = matrix;
return 0;
// error processing
format_error:
res = E_FFORMAT;
// intentional fall-through
error:
if (matrix) {
matrix_delete(matrix);
}
return res;
}
/******************************************************************************************
** matrix list management
******************************************************************************************/
void ml_init(MATRIX_LIST* matrix_list) {
matrix_list->Num_matrixes = 0;
matrix_list->Matrixes_size = 0;
matrix_list->Matrixes = NULL;
}
void ml_free(MATRIX_LIST* matrix_list) {
int ix;
for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
matrix_delete(matrix_list->Matrixes[ix]);
}
free(matrix_list->Matrixes);
}
void ml_check_spot(MATRIX_LIST* matrix_list) {
if (matrix_list->Num_matrixes >= matrix_list->Matrixes_size) {
matrix_list->Matrixes_size += MATRIXLISTSTEP;
matrix_list->Matrixes =
(MATRIX**)realloc(matrix_list->Matrixes, (matrix_list->Matrixes_size) * sizeof(matrix_list->Matrixes[0]));
}
}
void ml_add(MATRIX_LIST* matrix_list, MATRIX* matrix) {
ml_check_spot(matrix_list);
matrix_list->Matrixes[matrix_list->Num_matrixes] = matrix;
++matrix_list->Num_matrixes;
}
void ml_del(MATRIX_LIST* matrix_list, MATRIX* matrix) {
int ix;
for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
if (matrix_list->Matrixes[ix] == matrix) break;
}
if (ix >= matrix_list->Num_matrixes) {
printf("something wrong in program - matrix to remove not found\n");
} else {
for ( ; ix < matrix_list->Num_matrixes - 1; ++ix) {
matrix_list->Matrixes[ix] = matrix_list->Matrixes[ix+1];
};
--matrix_list->Num_matrixes;
}
}
MATRIX* ml_find(MATRIX_LIST* matrix_list, const char* name) {
int ix;
for (ix = 0; ix < matrix_list->Num_matrixes; ++ix) {
if (strcmp(matrix_list->Matrixes[ix]->Name, name) == 0) {
return matrix_list->Matrixes[ix];
}
}
return NULL;
}
int ml_is_empty(MATRIX_LIST* matrix_list) {
return (matrix_list->Num_matrixes == 0);
}
void ml_show(MATRIX_LIST* matrix_list) {
int i;
if (ml_is_empty(matrix_list)) {
puts("List of matrixes is empty!");
} else {
for(i=0; i<matrix_list->Num_matrixes; i++) {
printf("%s (%d x %d)\n", matrix_list->Matrixes[i]->Name,
matrix_list->Matrixes[i]->Rows, matrix_list->Matrixes[i]->Cols);
}
}
}
int ml_write(MATRIX_LIST* matrix_list, FILE* f) {
int k;
int res = 0;
for(k=0; k<matrix_list->Num_matrixes; k++)
{
res = matrix_write(matrix_list->Matrixes[k], f);
if (res < 0) break;
}
return res;
}
int ml_read(MATRIX_LIST* matrix_list, FILE* f) {
int res = 0;
MATRIX* matrix;
while (!feof(f)) {
res = matrix_read(&matrix, f);
if (res < 0) break;
ml_add(matrix_list, matrix);
}
return res;
}
/******************************************************************************************
** user interface
******************************************************************************************/
int getname(char* prompt, char* buffer, int buffsize) {
int res;
printf("enter the %s:\n> ", prompt);
res = getstr(stdin, buffer, buffsize);
if (res < 0) {
printf("name is too long...\n");
}
return res;
}
int ui_check_empty(MATRIX_LIST* matrix_list) {
if (ml_is_empty(matrix_list)) {
printf("no variables defined\n");
return 1;
} else {
return 0;
}
}
void ui_new_matrix(MATRIX_LIST* matrix_list)
{
char name[MAXNAMESZ], dimensions[MAXDIMSZ];
int res;
MATRIX* matrix;
char ch1 = 0, ch2 = 0;
int rows = -1, cols = -1;
printf("What are the dimensions of the matrix?\n(number of lines and columns separated by space, in range 1..%d)\n> ", MAXDIM);
res = getstr(stdin, dimensions, sizeof(dimensions));
if (res < 0) {
printf("dimensions are too long...\n");
return;
}
res = sscanf(dimensions, "%d%c%d%c", &rows, &ch1, &cols, &ch2);
if ((res != 3) || (ch1 != ' ') || (rows < 1) || (rows > MAXDIM) || (cols < 1) || (cols > MAXDIM)) {
puts("Wrong dimensions!");
return;
}
if (getname("variable name", name, sizeof(name)) < 0) return;
if (ml_find(matrix_list, name))
{
puts("This name is already in used!");
return;
}
matrix = matrix_create(name, rows, cols);
matrix_fill_random(matrix);
ml_add(matrix_list, matrix);
}
void ui_delete_matrix(MATRIX_LIST* matrix_list)
{
char name[MAXNAMESZ];
MATRIX* matrix;
if (ui_check_empty(matrix_list)) return;
if (getname("variable name", name, sizeof(name)) < 0) return;
matrix = ml_find(matrix_list, name);
if (!matrix) {
puts("Variable not found!");
return;
}
printf("remove var: %s(%dx%d)\n", matrix->Name, matrix->Rows, matrix->Cols);
ml_del(matrix_list, matrix);
matrix_delete(matrix);
}
void ui_transpose_matrix(MATRIX_LIST* matrix_list)
{
char name[MAXNAMESZ];
MATRIX *matrix, *trans_matrix;
if (ui_check_empty(matrix_list)) return;
if (getname("variable name", name, sizeof(name)) < 0) return;
matrix = ml_find(matrix_list, name);
if (!matrix)
{
puts("Variable not found!");
return;
}
if (getname("variable name for transposed matrix", name, sizeof(name)) < 0) return;
if (ml_find(matrix_list, name))
{
puts("This name is already in use!");
return;
}
trans_matrix = matrix_transpose(matrix, name);
ml_add(matrix_list, trans_matrix);
}
void ui_sum_matrixes(MATRIX_LIST* matrix_list)
{
char name[MAXNAMESZ];
MATRIX *matrix1, *matrix2, *res_matrix;
if (ui_check_empty(matrix_list)) return;
if (getname("variable name (1st operand)", name, sizeof(name)) < 0) return;
matrix1 = ml_find(matrix_list, name);
if (!matrix1)
{
puts("Variable not found!");
return;
}
if (getname("variable name (2nd operand)", name, sizeof(name)) < 0) return;
matrix2 = ml_find(matrix_list, name);
if (!matrix2)
{
puts("Variable not found!");
return;
}
if ((matrix1->Rows != matrix2->Rows) || (matrix1->Cols != matrix2->Cols))
{
puts("Matrixes have different dimensions!");
return;
}
if (getname("variable name for sum", name, sizeof(name)) < 0) return;
if (ml_find(matrix_list, name))
{
puts("This name is already in use!");
return;
}
res_matrix = matrix_sum(matrix1, matrix2, name);
ml_add(matrix_list, res_matrix);
}
void ui_show_matrix(MATRIX_LIST* matrix_list)
{
char name[MAXNAMESZ];
MATRIX* matrix;
if (ui_check_empty(matrix_list)) return;
if (getname("variable name", name, sizeof(name)) < 0) return;
matrix = ml_find(matrix_list, name);
if (!matrix) {
puts("Variable not found!");
return;
}
matrix_show(matrix);
}
void ui_write_to_file(char* filename, MATRIX_LIST* matrix_list)
{
FILE* f;
int res;
f = fopen(filename, "w");
res = ml_write(matrix_list, f);
if (res < 0) {
printf("io errors detected writing to the file.\nSome information may be lost\n");
}
fclose(f);
}
void ui_read_from_file(char* filename, MATRIX_LIST* matrix_list)
{
FILE* f;
int res;
f = fopen(filename, "r");
if (!f) {
printf("file <%s> not found\n", filename);
return;
}
res = ml_read(matrix_list, f);
if (res == E_FFORMAT) {
printf("file format errors detected reading from the file.\nSome information may be lost\n");
} else if (res != E_FEOF) {
printf("io errors detected reading from the file.\nSome information may be lost\n");
}
fclose(f);
}
int main()
{
MATRIX_LIST matrix_list;
int choice;
char str[5];
ml_init(&matrix_list);
puts("$ matprog");
ui_read_from_file(FILENAME, &matrix_list);
ml_show(&matrix_list);
for (;;)
{
puts("\nShow matixes..................1");
puts("Show matrix...................2");
puts("Remove matrix.................3");
puts("New arbitrary matrix..........4");
puts("Transponse....................5");
puts("Sum...........................6");
puts("Exit..........................x");
putchar('>');
getstr(stdin, str, sizeof(str));
if ((str[0] == 'x') || (str[0] == 'X'))
break;
choice = atoi(str);
switch (choice)
{
case 1: {
ml_show(&matrix_list);
} break;
case 2: {
ui_show_matrix(&matrix_list);
} break;
case 3: {
ui_delete_matrix(&matrix_list);
} break;
case 4: {
ui_new_matrix(&matrix_list);
} break;
case 5: {
ui_transpose_matrix(&matrix_list);
} break;
case 6: {
ui_sum_matrixes(&matrix_list);
} break;
default: {
puts("Wrong choice!");
} break;
}
}
ui_write_to_file(FILENAME, &matrix_list);
ml_free(&matrix_list);
return 0;
}