Przekazywanie tablicy przez wskaźnik

0

Mam pewien problem i właściwie nie wiem, dlaczego się tak dzieje. Mam funkcję:

int wczytajUczniow(uczen *listaUczniow, char* nazwaPliku)

gdzie uczeń to struktura. Funkcję wywołuję w następujący sposób:

iloscUczniow = wczytajUczniow(listaUczniow, "plik.txt");

gdzie listaUczniow to dynamiczna tablica struktur uczen. No i implementacja funkcji:

int wczytajUczniow(uczen *listaUczniow, char* nazwaPliku)
{
    int i, j, iloscUczniow;
    FILE *fp;
    char dane[512];
    double liczba;
    if((fp = fopen(nazwaPliku, "r")) == NULL)
    {
        printf("Nie udalo sie otworzyc pliku!");
        return 0;
    }
    fscanf(fp, "%d", &iloscUczniow);
    listaUczniow = (uczen*) malloc(sizeof(uczen)*((int)iloscUczniow));
    for(i = 0; i < iloscUczniow; i++)
    {
        fscanf(fp, "%s", dane);
        listaUczniow[i].imie = (char*)malloc(sizeof(char)*strlen(dane));
        strcpy(listaUczniow[i].imie, dane);
        fscanf(fp, "%s", dane);
        listaUczniow[i].nazwisko = (char*)malloc(sizeof(char)*strlen(dane));
        strcpy(listaUczniow[i].nazwisko, dane);
        fscanf(fp, "%s", listaUczniow[i].klasa);
        fscanf(fp, "%s", dane);
        listaUczniow[i].srednia = charToDouble(dane);
        fscanf(fp, "%s", dane);
        listaUczniow[i].dyscypliny = (dyscyplina*)malloc(sizeof(dyscyplina)*charToDouble(dane));
        listaUczniow[i].iloscDyscyplin = 0;
    }
    fclose(fp);
    printf("\nWczytano uczniow poprawnie.\n");
    return iloscUczniow;
}

Pytanie brzmi następująco: dlaczego dane widoczne są tylko w tej funkcji, a po wyjściu, czyli gdy próbuję je wypisać w mainie, wyświetlają się krzaczki (czytaj śmieci z pamięci). Funkcja sortująca wygląda identycznie, jeśli chodzi o deklarację oraz wywoływanie i tam elementy zamieniają się miejscami, co widać również w mainie.

0

Najpierw odnośnie fragmentów kodu, przyjmując, że piszesz w C:

    listaUczniow = (uczen*) malloc(sizeof(uczen)*((int)iloscUczniow));

(uczen*) malloc rzutowanie niepotrzebne, bo w C masz domyślne/automatyczne rzutowanie void* <-> T*
(int)iloscUczniow - iloscUczniow jest typu int - a Ty rzutujesz jeszcze raz? ;)
sizeof(char) - niepotrzebne, bo masz gwarancję (w standardzie), że niezależnie od tego ile char ma bitów, sizeof(char) zawsze jest równe 1.
fscanf(fp, "%s", dane); - Co się stanie, jeżeli w pliku będzie więcej niż 512 (rozmiar dane) znaków nie-białych pod rząd? Przykład:
Plik data:12345678901234567890 123

#include <stdio.h>

int main(void) {
    FILE* file = fopen("data", "r");
    if (file) {
        char buf[10];
        fscanf(file, "%s", buf);// kaboom
        fclose(file);
    }
    return 0;
}

malloc(sizeof(char)*strlen(dane)); w malloc - a gdzie jest miejsce dla \0? :)

0

Ok, dzięki za rady.

Co do ilości znaków, to mam gwarancję, że będzie ich mniej niż 512. Poza tym dane wczytują się poprawnie. Problem mam w tym, że potem, gdy już wychodzę z funkcji, to te dane mi się 'gubią' i gdy próbuję coś wypisać w mainie, to wychodzą same śmieci.

0

A możesz jakiś pełny przykład dać? Tj z funkcją main i danymi? Tak żeby można było prześledzić działanie.

0

Proszę: http://wklej.org/id/508560/

Tam generalnie kodu jest sporo, ale głównie chodzi mi o funkcję o której pisałem wyżej. Nie wiem dlaczego, ale po wyjściu z funkcji, w tablicy listaUczniow są jakieś śmieci, a np.po wykonaniu funckji, która sortuje uczniów (wListeWedlugNazwisk) w funkcji main nazwiska również są posortowane.

Przykładowe dane dla pliku kupa.txt:

2
Stefan Kulesza 1b 4.1 1
Marcin Debski 2b 3.2 1

Przykładowe dane dla pliku tekst.txt:

2
Biegi 2 0 2
Skok w dal 1 1

0

Po próbie kompilacji w gcc 4.5.2 (tryb C99):

test.c: In function 'main':
test.c:86:73: warning: suggest braces around empty body in an 'if' statement
test.c:181:13: warning: passing argument 3 of 'zapiszDyscypliny' discards qualifiers from pointer target type
test.c:41:6: note: expected 'char *' but argument is of type 'const char *'
test.c:183:13: warning: passing argument 3 of 'zapiszUczniow' discards qualifiers from pointer target type
test.c:42:6: note: expected 'char *' but argument is of type 'const char *'
test.c:186:13: warning: passing argument 2 of 'wczytajUczniow' discards qualifiers from pointer target type
test.c:44:5: note: expected 'char *' but argument is of type 'const char *'
test.c:187:13: warning: passing argument 2 of 'wczytajDyscypliny' discards qualifiers from pointer target type
test.c:43:5: note: expected 'char *' but argument is of type 'const char *'
test.c:53:14: warning: unused parameter 'argc'
test.c:53:26: warning: unused parameter 'argv'
test.c: In function 'wListeWgNazwisk':
test.c:205:10: warning: declaration of 'dyscyplina' shadows a global declaration
test.c:18:3: warning: shadowed declaration is here
test.c:205:10: warning: unused variable 'dyscyplina'
test.c: In function 'wczytajDane':
test.c:271:67: warning: suggest braces around empty body in an 'if' statement
test.c:279:22: warning: comparison between signed and unsigned integer expressions
test.c:291:75: warning: suggest braces around empty body in an 'if' statement
test.c:302:67: warning: suggest braces around empty body in an 'if' statement
test.c:310:22: warning: comparison between signed and unsigned integer expressions
test.c:317:75: warning: suggest braces around empty body in an 'if' statement
test.c:328:91: warning: suggest braces around empty body in an 'if' statement
test.c:338:99: warning: suggest braces around empty body in an 'if' statement
test.c:346:76: warning: suggest braces around empty body in an 'if' statement
test.c:351:22: warning: comparison between signed and unsigned integer expressions
test.c:390:84: warning: suggest braces around empty body in an 'if' statement
test.c:402:71: warning: suggest braces around empty body in an 'if' statement
test.c:406:26: warning: comparison between signed and unsigned integer expressions
test.c:410:21: warning: format '%d' expects type 'int *', but argument 2 has type 'char *'
test.c:424:83: warning: suggest braces around empty body in an 'if' statement
test.c:433:27: warning: assignment from incompatible pointer type
test.c: In function 'charToDouble':
test.c:445:18: warning: comparison between signed and unsigned integer expressions
test.c: In function 'dodajDyscypline':
test.c:477:34: warning: declaration of 'dyscyplina' shadows a global declaration
test.c:18:3: warning: shadowed declaration is here
test.c:481:70: warning: suggest braces around empty body in an 'if' statement
test.c: In function 'usunDyscypline':
test.c:494:12: warning: declaration of 'uczen' shadows a global declaration
test.c:27:3: warning: shadowed declaration is here
test.c: In function 'edytujDyscypline':
test.c:551:70: warning: suggest braces around empty body in an 'if' statement
test.c: In function 'kopiujUcznia':
test.c:624:12: warning: unused variable 'j'
test.c: In function 'wyszukajUcznia':
test.c:725:96: warning: suggest braces around empty body in an 'if' statement
test.c:742:96: warning: suggest braces around empty body in an 'if' statement
test.c:745:45: warning: left-hand operand of comma expression has no effect
test.c:757:96: warning: suggest braces around empty body in an 'if' statement
test.c:760:42: warning: left-hand operand of comma expression has no effect
test.c:772:96: warning: suggest braces around empty body in an 'if' statement
test.c: In function 'zapiszDyscypliny':
test.c:799:5: warning: implicit declaration of function 'itoa'
test.c:799:5: warning: nested extern declaration of 'itoa'
test.c:799:5: warning: passing argument 1 of 'fputs' makes pointer from integer without a cast
e:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.5.2/../../../../include/stdio.h:356:37: note: expected 'const char *' but argument is of type 'int'
test.c:805:9: warning: passing argument 1 of 'fputs' makes pointer from integer without a cast
e:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.5.2/../../../../include/stdio.h:356:37: note: expected 'const char *' but argument is of type 'int'
test.c:809:13: warning: passing argument 1 of 'fputs' makes pointer from integer without a cast
e:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.5.2/../../../../include/stdio.h:356:37: note: expected 'const char *' but argument is of type 'int'
test.c: In function 'zapiszUczniow':
test.c:822:5: warning: passing argument 1 of 'fputs' makes pointer from integer without a cast
e:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.5.2/../../../../include/stdio.h:356:37: note: expected 'const char *' but argument is of type 'int'
test.c:835:9: warning: passing argument 1 of 'fputs' makes pointer from integer without a cast
e:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.5.2/../../../../include/stdio.h:356:37: note: expected 'const char *' but argument is of type 'int'
test.c:818:12: warning: unused variable 'j'
test.c: In function 'wczytajUczniow':
test.c:870:36: warning: assignment from incompatible pointer type
test.c:847:12: warning: unused variable 'liczba'
test.c:844:12: warning: unused variable 'j'
test.c: In function 'polaczUczniowZDyscyplinami':
test.c:910:106: warning: unused parameter 'iloscUczniow'

Te if-y to rzeczywiście mają być puste?

0

Tak, ify mają być puste póki co. Poprawiłem błędy (nie wiedziałem tylko o co chodzi z tymi warningami przy fputs), ale domyślam się, że itoa zwraca wskaźnik a nie int, kompiluję gcc -ansi -pedantic -Wall

http://wklej.org/id/508679/

1

Dane masz widoczne tylko w tej funkcji, bo przypisujesz nowy adres (zwrócony przez malloc) lokalnej kopii wskaźnika.

int wczytajUczniow(uczen **listaUczniow, char* nazwaPliku) {
//...
*listaUczniow = malloc(...);
//...
}
// i wywołanie
wczytajUczniow(&lista, ".");
0

A co do Twojej metody, to jednak nie działa. Było to czego się obawiałem - referencja do tablicy odnosi się tylko do pierwszego elementu, w kolejnych mam wszędzie nulle.

strdupa musiałem napisać swojego, bo gcc w szkole wywalał warningi na tym standardowych, a program ma się kompilować bez warningow :X

0

U mnie w cholerę więcej warningów wyświetla, chociażby z itoa (użycia przy fputs) :P Więc jeśli chcesz mieć tak całkiem na czysto, to jeszcze trochę musiałbyś pozmieniać. ;)

0

No tak tak, warningów teraz jeszcze jest sporo, ale na razie chcę zrobić, żeby to wszystko działało tak jak powinno, a cały czas nie wiem jak zrobić, żebym mógł sobie zaalokować pamięć dla tablicy struktur, wypełnić tą pamięć i żeby to było potem jeszcze widocznie w mainie. Niestety sposób, który podał nav działa, ale tylko dla 1 elementu (bo tylko dla tego przekazywany jest adres pamięci przez referencję).

Ktoś to przerzucił z C/C++ do newbie a tutaj problem okazał się chyba bardziej skomplikowany niż na taki wyglądał

0
int wczytajUczniow(uczen **listaUczniow, char* nazwaPliku)
{
    int i, iloscUczniow;
    FILE *fp;
    char dane[512];
    if((fp = fopen(nazwaPliku, "r")) == NULL)
    {
        printf("Nie udalo sie otworzyc pliku!");
        return 0;
    }
    fscanf(fp, "%d", &iloscUczniow);
    *listaUczniow = malloc(sizeof(uczen)*iloscUczniow);
    for(i = 0; i < iloscUczniow; i++)
    {
        fscanf(fp, "%s", dane);
        listaUczniow[i]->imie = malloc(strlen(dane));
        strcpy(listaUczniow[i]->imie, dane);
        fscanf(fp, "%s", dane);
        listaUczniow[i]->nazwisko = malloc(strlen(dane));
        strcpy(listaUczniow[i]->nazwisko, dane);
        fscanf(fp, "%s", listaUczniow[i]->klasa);
        fscanf(fp, "%s", dane);
        listaUczniow[i]->srednia = charToDouble(dane);
        fscanf(fp, "%s", dane);
        listaUczniow[i]->dyscypliny = malloc(sizeof(dyscyplina)*atoi(dane));
        listaUczniow[i]->iloscDyscyplin = 0;
        printf("%s %s %s %f\n", listaUczniow[i]->imie, listaUczniow[i]->nazwisko, listaUczniow[i]->klasa, listaUczniow[i]->srednia);
    }
    if( fclose(fp) == 0) printf("Si udalo");
    else    printf("Sie nie udalo!");
    printf("\nWczytano uczniow poprawnie. \n");
    return iloscUczniow;
}

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