Po kolei:
Kod: Zaznacz cały
f=fopen(name,"r");
if(f==NULL)
{
printf("Nie mozna otworzyc pliku!
");
exit(0);
}
Napisałbym to tak:
Kod: Zaznacz cały
if((f = fopen(name, "r") == NULL))
{
fputs("Nie mozna otworzyc pliku!", stderr);
exit(EXIT_FAILURE);
}
1) im mniej linii kodu, tym lepiej - oczywiście zachowując przy tym czytelność
2) do wyświetlania błędów logiki aplikacji (czyli w razie błędów w trakcie działania programu) służy strumień
stderr
- standard error (standardowe wyjście na błędy)
Chodzi o to, że łatwiej wtedy odróżnić zwykły tekst wyświetlany w konsoli od informacji o błędach.
Jest jeszcze coś takiego jak funkcja
perror
- program error, ona służy do wyświetlania błędów w systemie (typu nie można zaalokować pamięci).
Zauważ, że
fputs("Napis",stdout);
jest równoważne
puts("napis");
3)
exit()
może zwracać jedną z 2 wartości:
EXIT_SUCCESS
lub
EXIT_FAILURE
. Pierwsza z nich jest równoważna
exit(0)
, natomiast druga
exit(1)
- i tak jak w przypadku
size_t
to sprawia, że kod się staje czytelniejszy.
Na dobrą sprawę
exit()
może zwracać jedną z 256 wartości, no, ale te dwie co opisałem głównie się wykorzystuje (szczególnie na początku).
Swoją drogą, to powinnaś do kodu dodać właśnie takie sprawdzenie, czy pamięć została zaalokowana. Wygladałoby to tak:
Kod: Zaznacz cały
float **allocMem(size_t rows, size_t columns)
{
float **matrix = malloc(rows * sizeof(float *));
checkMem(matrix);
for(size_t i = 0; i < rows; ++i)
{
matrix[i] = malloc(columns * sizeof(float));
checkMem(matrix[i]);
}
return matrix;
}
void checkMem(void *memory)
{
if(memory == NULL)
{
errno = ENOMEM;
perror("Nie mozna zaalokowac pamieci!
");
exit(EXIT_FAILURE);
}
}
void *memory
oznacza, że funkcja przyjmie wskaźnik dowolnego typu (bez względu na to, czy to będzie int, float, czy cokolwiek innego).
errno
oznacza kod błędu - ENOMEM oznacza error no memory, czyli brak pamięci. Aby to działało, należy załączyć
<errno.h>
Wracając do programu - przy wczytywaniu rozmiarów macierzy znowu lepiej byłoby dać
size_t
Kod: Zaznacz cały
size_t row, col;
fscanf(f, "%zu %zu", &row, &col);
%zu
to jest specyfikator dla
size_t
.
Nie mam natomiast pomysłu, jak przerobić powyższy kod na funkcję, która wczytywałaby i zwracała jednocześnie liczbę wierszy i kolumn macierzy
Na przykład stwórz funkcję
void getDim(char *file_name, size_t *dim_array)
(get dimensions, dimensions array) - i po prostu w głównej funkcji stworzysz sobie tablicę dwuelementową (np. pierwszy element to szerokość, drugi to wysokość), przekażesz ją do funkcji i tam wypełnisz. Lepiej by to było zrobić przez strukturę - ale nie wiem czy takowe miałaś. Funkcja nie może zwracać więcej niż jednego elementu, więc zrobić to wprost się nie da.