• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Proszę o wyjaśnienie : tablica wskaźników , odczyt z pliku, malloc().

Object Storage Arubacloud
0 głosów
1,015 wizyt
pytanie zadane 8 lutego 2017 w C i C++ przez maciekkov Początkujący (360 p.)

Witam

Próbuję odczytać dane z pliku i umieścić je w buforze. Zamiast tworzyć 30 tablic chcę stworzyć tablice wskaźników aby tam umieścić wskaźniki do poszczególnych stringów. A więc w main() zadeklarowałem pamięć

 char **bufor=(char**)malloc(30 * sizeof(char));
    for(i=0;i<30;i++){
        bufor[i]=(char*)malloc(300 * sizeof(char));
    }

1)Proszę mnie poprawić ale jeśli dobrze rozumuję zrobiłem coś następującego. 
Zadeklarowałem wskaźnik , który określa początek miejsca w pamięci gdzie kolejno będzie utworzonych 30 wskaźników do zmiennej typu char. Następnie dla każdego wskaźnika przypisałem pamięć 300 "pól" z czego każde pole jest wielkości char. Tak?

2)Czy powyższy zapis jest równoważny  z tym zapisem jeśli zdefiniujemy tą tablicę jako zmienną globalną i zostanie ona z racji tego zainicjowana  zerami?    char*bufor[30]; 

 

3) Funkcję wczytująca dane z pliku wywołałem w ten sposób      read(bufor)

    a zdefiniowałem następująco       void read(char**buf)

Czy to znaczy że wysłałem do funkcji jako argument wskaźnik do wskaźników na char?

 

4)Następnie przy użyciu poniższego kodu próbuję pobrać kolejne linie i zapisać je w pamięci.

i=0;
while( (fgets(buf[i],350,plik))!=NULL){
       
        puts(buf[i]);
        i++;
}

Nie chce działać. Kiedy w main() próbuję wyświetlić zawartość char**bufor są tam same śmieci i w połowie program się wysypuje.
CO ciekawe gdy używam lokalnej zwykłej tablicy wszystko działa. Na przykład :

char lokalny[1000]; 
while( (fgets(lokalny,350,plik))!=NULL){
        puts(lokalny);

}

Prosiłbym o pomoc w rozwiązaniu tego i napisanie czy dobrze rozumuje powyższe zagadnienia.

1 odpowiedź

+2 głosów
odpowiedź 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 8 lutego 2017 przez maciekkov
 
Najlepsza
  1. Tak.
  2. W pierwszym zapisie deklarujesz 30 tablic o wielkości 300 znaków (bajtów), zaś w drugim jedynie 30 wskaźników, a przecież sam wskaźnik nie jest tablicą. Oczywiście dane w tablicy globalnej zostaną wyzerowane, jak słusznie zauważyłeś, ale tablice zaalokowane dynamicznie nadal będą zawierać śmieci. Aby je wyzerować, należy użyć funkcję calloc.
  3. Konkretnie wysłałeś wskaźnik na wskaźnik na char. Do reszty elementów tablicy odwołujesz się poprzez arytmetykę wskaźników.
  4. W pierwszym wywołaniu fgets czytasz 350 znaków, a tablica ma rozmiar 299 + 1 (jedynka dla nulla), więc to nie ma prawa działać. W drugim zaś tablica posiada odpowiedni rozmiar, aby pomieścić wszelkie dane, ale za każdym razem są one nadpisywane przez nowe, więc ten zapis, oprócz do wypisywania w locie danych, nie ma większego sensu.
komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)
Dziękuję za wyjaśnienie i wskazanie błędu. Faktycznie pomogło.Ale tylko połowicznie.

Obecnie wczytuje już dane do buforu ale tylko kilka pierwszych rekordów zawsze tych samych i po 10 rekordzie program się wysypuje, Gdy usunąłem i++ program się nie wysypuje, Ale wiadomo nadpisuje to bufor[0]; a to tez nie rozwiązanie.

Dziwne to, bo wszystko wygląda w porządku co świadczy sam fakt odczytywania z pliku i przypisywania rekordów aż do bufor[9] wiec czemu dalej się krzaczy?

Spróbowałem przypisać mniejszą ilość wskaźników niż 10 i wysypuje również.
komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
Ile masz znaków w pliku (razem ze znakami nowej linii i końcem pliku)?
komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)
plik ma rozmiar 2040 bajtów i 1980 znaków.
komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
Pokaż najlepiej cały kod odpowiedzialny za obsługę pamięci i pliku.
komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)
Cały KOD:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define SIZE 30
void menu();
void read(char**str);
int random(int size);

int main()
{
    int i;
    char **bufor = (char**) malloc(30 * sizeof(char));
    for(i=0;i<30;i++){
        bufor[i]=(char*) malloc(300 * sizeof(char));
    }

    int ile;

    while(1)
    {
        system("cls");
        menu();
        int choice=getch();
        switch(choice)
        {
        case '1':
            printf("Wczytywanie danych\n\n\n");

            //wiatraczek
            read(bufor);
            system("pause");
            break;
        case '2':
            break;
        case '3':
            break;
        case '4':
            /*Generuje nowy kod i zapisuje go w pliku*/
            generate_code();
            printf("Plik zostal wygenerowany\n");
            system("pause");
            break;
        case '5':
            printf("Zamkniecie programu!");
            exit(0);
            break;
        }
    }
    free(bufor);
    return 0;
}
void menu()
{
    printf("       ----------------------------------------\n");
    printf("                 USER INTERFACE\n");
    printf("       ----------------------------------------\n");
    printf("              PRESS 1: LOAD DATA\n");
    printf("              PRESS 2: FIND RECORD\n");
    printf("              PRESS 3: SHOW RECORDS\n");
    printf("              PRESS 4: GENERATE NEW FILE\n");
    printf("              PRESS 5: EXIT\n");
    printf("       ----------------------------------------\n");

}
void read(char**str)
{
    int i=0;

    FILE *plik;
    plik = fopen("zadanie_bartka.txt","r");
    if(!plik)
    {
       perror("Nie udalo sie zaladowac pliku");
        exit(1);
    }

    while( (fgets(str[i],250,plik)) ){
            puts(str[i]);
            i++;
    };
    fclose(plik);

}
void generate_code()
{
    srand(time(NULL));
    int i; //licznik
    char pin[SIZE];
    /*Wypelnienie tablicy dnymi*/
    for(i=0; i<SIZE; i++)
    {
        pin[i]=i;
    }
    char *nazwa[SIZE]=   {"ZEGAREK","LAPTOP","TOSTER","RADIO","MP3","KOPTER",
                          "ZELAZKO","MYSZKA","LAMPKA","OKNO","SAMOCHOD","TABLET",
                          "TEMPOMAT","PORTFEL","MIKSER","CZAJNIK","BMW","FORD",
                          "PASSAT","RENAULT","TESLA","GOLF","BOING","RAKIETA",
                          "SONDA","CZOLG","HELI","PAROWKA","TOYOTA"
                         };
    char *mux[]    =   {"MUX_A","MUX_B","MUX_C","MUX_D"};
    char *input[2]  =   {"input","output"};
    char *pull[2]  =   {"UP","DOWN"};
    /*Otwarcie pliku*/
    FILE *plik;
    plik = fopen("zadanie_bartka.txt","w");
    if(!plik)
    {
        printf("Nie udalo sie otworzyc pliku");
        exit(1);
    }
    for(i=0; i<SIZE; i++)
    {
        fprintf(plik,"pin %2d%8s,%5s,%6s,pull %5s,out=%d\n",pin[random(SIZE)]
                ,nazwa[random(SIZE)],mux[random(4)],input[random(2)]
                ,pull[random(2)],random(2));
    }
    fclose(plik);
    return 0;
}
/*Funkcja losujaca index, skrocilem nazwe do "r" bo mi printf wychodzil na 5 linii */
int random(int size)
{
    int i,key;
    for(i=0; i<size; i++)
    {
        key=0+rand()%size;
    }
    return key;
}

 

komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
Co oznacza "program się wysypuje"?
komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)

Dokładnie to:
Po wczytaniu kilka pierwszych rekordów crash.

komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
Mam rozumieć, że w menu najpierw wywołujesz funkcję czwartą, a potem pierwszą?
komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)
Jeśli nie masz tego pliku to generujesz sobie nowy, A jeśli chcesz odczytywać obecnie utworzony to wciskasz bezpośrednio 1. Program będzie rozbudowany o szukanie poszczególnych rekordów po nazwie bądź po numerze, wyświetlania listy całych bądź kilku rekordów. Ale stanąłem bo nie działą mi bufor który jest potrzebny do wszystkiego.

 

Ogólnie to zadanie zadał mi mój kolega i jest to jak się domyślam część większego zadania dla mnie .Gość pracuje w branży kupę lat i testuje w ten sposób moją wiedzę.

 

A jak widać moja wiedza kończy się w 10 rekordzie :D hehehe
1
komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)

Zauważ, że wskaźnik nie waży jeden bajt, ale w systemie 32-bitowym cztery bajty, a w 64-bitowym osiem, więc przy alokacji tablicy wskaźników powinieneś użyć sizeof(char*), nie zaś sizeof(char). Tzn. zmieniasz wywołanie sizeof jedynie pierwsze, w pętli wszystko zostaje jak było. No i zwolnienie tablicy dwuwymiarowej nie odbywa się przez free(bufor), ale zwalniasz ją odwrotnie do jej alokacji, najpierw tablice znaków (w pętli), potem tablica wskaźników.

komentarz 8 lutego 2017 przez maciekkov Początkujący (360 p.)
Działa jak należy :) Dziękuję bardzo za wyjaśnienie. Wstawić gwiazdkę to każdy tam sobie mógł na chybił trafił  ale żeby wytłumaczyć dlaczego to już nie każdy... Widzę, że wielka wiedza się kłania :) Pozdrawiam.
komentarz 8 lutego 2017 przez Patrycjerz Mędrzec (192,320 p.)
Dziękuję za pochwały, ale jakby nie patrzeć, jest to elementarna wiedza na temat wskaźników i dynamicznej alokacji pamięci, więc trudno, abym jej nie znał.

Jeślibyś jeszcze czegoś nie rozumiał, pytaj śmiało, nawet na wiadomość prywatną.

Podobne pytania

0 głosów
1 odpowiedź 344 wizyt
pytanie zadane 25 sierpnia 2020 w C i C++ przez fortuna Początkujący (310 p.)
0 głosów
0 odpowiedzi 125 wizyt
0 głosów
1 odpowiedź 418 wizyt
pytanie zadane 27 stycznia 2018 w C i C++ przez RedRevenge Obywatel (1,230 p.)

92,579 zapytań

141,432 odpowiedzi

319,657 komentarzy

61,963 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...