Czytanie danych z pliku, zapisywanie ich do struktury, a następnie wyświetlanie na ekranie w C.

0

Mam taki problem. Oto mój plik wejściowy

S skalar1 3
S skalar2 5
V wektor1 3
2 4 7
V wektor2 3
3 6 1
M macierz_A 3 3
1 2 3
4 5 6
7 8 9
M macierz_B 3 3
9 8 7
6 5 4
3 2 1

Chciałbym z niego odczytać wszystkie elementy. Składają się one z macierzy, wektora, skalara. A każdy z nich słowa-klucza, nazwy, wymiaru (wektor i macierz) oraz wartości. Problem jest taki. Próbuję czytać te wszystkie pliki, tylko wyskakuje mi błąd segmentacji,

./primal.x dane.txt wyniki.txt
Naruszenie ochrony pamięci (zrzut pamięci)

Oto mój kod

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

int main (int argc, char *argv[])
{    
    FILE *wz, *wc;  
    int dimension, dimensionX, dimensionY;

    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source\n",argv[0]);
    exit(1);
    }

    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }
    if( (wc= fopen(argv[2], "w")) == NULL) {
    printf("Open error %s\n", argv[2]);
    exit(2);
    }

    struct Vector 
    { 
        char keyWord;
        char elementName[20];
        int dimension;
        double V[dimension];
    };
    typedef struct Vector wek;

    struct Scalar 
    { 
        char keyWord;
        char elementName[20];
        double wartosc;
    };
    typedef struct Scalar ska;

    struct Array
    {
        char keyWord;
        char elementName[20];
        int dimensionX;
        int dimensionY;
        double M[dimensionX][dimensionY];
    };
    typedef struct Array mac;

    struct Vector w1, w2;
    struct Scalar s1, s2;
    struct Array m1, m2;

    wek readVector(FILE *wz)
{
    wek w;
    fscanf(wz, "%s", &w.keyWord);
    fscanf(wz, "%20s", &w.elementName[0]);
    for (int j = 0; j < dimension; ++j)
            fscanf(wz, "%10lf", &w.V[j]);
    return w;
}
    ska readScalar(FILE *wz)
{
    ska s;
    fscanf(wz, "%s", &s.keyWord);
    fscanf(wz, "%20s", &s.elementName[0]);
    fscanf(wz, "%10lf", &s.wartosc);
    return s;
}
    mac readArray(FILE *wz)
{
    mac m;
    fscanf(wz, "%s", &m.keyWord);
    fscanf(wz, "%20s", &m.elementName[0]);
    for (int i = 0; i < m.dimensionX; ++i)
        for (int j = 0; j < m.dimensionY; ++j)
            fscanf(wz, "%10lf", &m.M[i][j]);
    return m;
}
    s1 = readScalar(wz);
    s2 = readScalar(wz);
    w1 = readVector(wz);
    w2 = readVector(wz);
    m1 = readArray(wz);
    m2 = readArray(wz);
    printf("Symbol %c, nazwa %s, wartosc %lf", s1.keyWord, s1.elementName, s1.wartosc);
    fclose(wz);
    fclose(wc);

    return 0;
}

Chyba przeczuwam w czym jest problem, ale pewny nie jestem.
Problem jest z pamięcią. Chodzi dokładnie o nazwy, czyli wszędzie, gdzie się znajduje

char elementName[20];

do każdej struktury wsadziłem tego typu zmienną.
Teraz próbuję wsadzić podczas wczytywania do tej tablicy znaków literki. Tablica ma sporą pojemność, więc wszystko powinno się zmieścić. Zaczynam od pierwszej pozycji w tablicy przy wczytywaniu no nie?

    fscanf(wz, "%20s", &m.elementName[0]);

Zastanawiałem się jeszcze nad użyciem tablicy wskaźników typu

    const char *s = "Monty Python";

Ale jak w takim wypadku rezerwować pamięć, trzeba używać malloc czy coś takiego? Poradźcie mi chłopaki czy to z tego wziął się błąd i jak najlepiej sobie z tym poradzić

1

To jest rzeczywisty kod? Deklarowanie typów w main itd ?
To się tzw kupy nie tzryma.

Dopóki nie ugruntujesz C, i nie zdyscyplinujesz samego siebie w wyrażaniu swoich idei w kodzie (oraz opisach), to segfaulty będą Cię witać każdego ranka

2

może na początku użyj debugger'a, żeby Ci wskazał, w którym miejscu ten błąd występuje.

3

W konsoli trzeba włączyć tworzenie pliku core w przypadku gdy program się wysypuje:
$ ulimit -c unlimited
potem program uruchamiamy, a gdy zrzuci core to można użyć gdb, cgdb (gdb z kolorami) lub debuggera w IDE, wtedy pokaże linię która spowodowała błąd:
$ cgdb main core
oczywiście kompilować trzeba z flagą -g, np:
$ gcc -g -Wall -Wextra -ansi -std=c11 -o main main.c

Jeżeli założysz, że np. maksymalne wymiary wektora i macierzy nie będą w pliku przekroczone to można uniknąć zabawy z przydzielaniem pamięci. Jak jej marnowanie okaże się problemem to trzeba zacząć korzystać ze wskaźników i malloc/free:

#define MAX_NAME 20
#define MAX_ARRAY_DIM 50

typedef struct Scalar {
    char name[MAX_NAME];
    double wartosc;
} Scalar;

typedef struct Vector {
    char name[MAX_NAME];
    int dim;
    double data[MAX_ARRAY_DIM];
} Vector;

twój program zakłada określone dane w pliku wejściowy, lepiej byłoby na początku sprawdzać token i wtedy wywołać określoną funkcje do wczytywania. To mogło by np. wyglądać tak:

typedef struct Element {
    char type;
    union {
        Scalar s;
        Vector v;
        Matrix m;
    } elem;
} Element;

void readVector(FILE *file, Vector* v) {
    fscanf(file, " %s %d ", &v->name[0], &v->dim);
    for (int j = 0; j < v->dim; ++j) {
        fscanf(file, "%10lf", &v->data[j]);
    }
}

void readElement(FILE *file, Element* e) {
    char type;
    fscanf(file, " %c ", &type);
    switch (type) {
    case 'S':
        e->type = 'S';
        readScalar(file, &e->elem.s);
        break;
    case 'V':
        e->type = 'V';
        readVector(file, &e->elem.v);
        break;
    case 'M':
        e->type = 'M';
        readMatrix(file, &e->elem.m);
        break;
    default:
        fputs("Error: unknown token!\n", stderr);
        exit(1);
    }
}

int main() {
    // ...
    Element elements[10];
    for (int i = 0; i < 6; i++) {
        readElement(plik1, &elements[i]);
    }
}

w funkcji fscanf warto dodawać spacje w napisie formatującym, bo mogą być problemy ze znakiem nowej linii. Chyba to jest główny problem w twoim programie.

0

Chyba jestem ślepy, ale gdzie jest ustawiany dimesion ? Czy tam są tablice o rozmiarze ustawianym dynamicznie w run-time na podstawie zmiennej?

edit: to do oryginału OP

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0