logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

wynik ze sprinf do tablicy

Gostek 04 Lip 2011 11:35 1386 13
REKLAMA
  • #1 9680192
    Gostek
    Poziom 17  
    Witam,

    Dawno temu napisalem kilka funkcji do wyswietlenia menu. Jedna z nich wyswietlala linie menu za pomoca tablicy wskaznikow:
    Kod: C#
    Zaloguj się, aby zobaczyć kod


    ktora zawsze dzialala OK. Ostatnio potrzebowalem wygenerowac liste wewnatrz programu, za pomoca sprintf:
    Kod: C#
    Zaloguj się, aby zobaczyć kod

    Niestety wynikiem jest sieczka.
    Ale jesli zamiast sekcji z sprinf wstawie:
    Kod: C#
    Zaloguj się, aby zobaczyć kod


    To wszystko jest OK, czy ktos moze mnie sprowadzic na wlasciwa droge ? :)
  • REKLAMA
  • #2 9680245
    BoskiDialer
    Poziom 34  
    Kod: text
    Zaloguj się, aby zobaczyć kod

    W ten sposób deklarujesz tylko tablicę wskaźników na ciągi znaków. Nie jest w żaden sposób alokowana pamięć pod właściwe ciągi znaków, stąd użycie sprintf nad tymi wskaźnikami jest niepoprawne (chyba, że wcześniej przypisano by wskaźnikom jakieś poprawne wartości).

    Ostatni kod, w którym przypisujesz ciągi znaków, jest poprawne, wszak ciąg znaków sam z siebie deklaruje przestrzeń pod siebie, a przypisanie jest tylko ustawieniem odpowiedniego wskaźnika.

    Aby kod 2 działał, musiał by być zmodyfikowany jakoś tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Inna możliwość to utworzenie tablicy w ten sposób:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Wtedy formalnie menu_main[0] będzie równe adresowi pierwszych 20 przydzielonych bajtów, menu_main[1] będzie równe adresowi następnych 20 przydzielonych bajtów etc....
  • #3 9680383
    Gostek
    Poziom 17  
    Dzieki za szybka obpowiedz, tak mi sie wlasnie zaczynalo rozswietlac, ze problem jest z alokacja pamieci ;). Zrobilem tak jak napisales w pierwszym przykladzie i dziala OK:
    Kod: C#
    Zaloguj się, aby zobaczyć kod


    Czy jest to jedyny sposob by to zadeklarowac ?
    Drugi sposob juz wczesniej sprawdzalem, ale nie dziala.
  • REKLAMA
  • Pomocny post
    #4 9680424
    BoskiDialer
    Poziom 34  
    Niestety, ale jeśli chcesz tablicę wskaźników, przy czym wskaźniki wskazują na konkretne bloki pamięci, musisz je inicjalizować. Jeśli obie tablice są globalne, to bez problemu powinno dać się to zrealizować jakoś tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    lub równoważnie:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Drugi sposób z poprzedniego postu w takim przypadku rzeczywiście może nie działać, jako że tablica dwuwymiarowa jest realizowana jako tablica jednowymiarowa, ale przez typ jest przekazany offset pomiędzy kolejnymi wierszami. Nie jest tutaj nigdzie realizowana pośrednia tablica wskaźników na kolejne wiersze, adresy wieszy są liczone w locie. Problem pojawia się tutaj w momencie przekazywania main_menu: rzutowanie z char[][20] na char* [] nie będzie działać poprawnie.
  • #5 9680435
    gaskoin
    Poziom 38  
    Możesz użyć funkcji malloc :)
  • REKLAMA
  • #6 9680457
    Gostek
    Poziom 17  
    gaskoin napisał:
    Możesz użyć funkcji malloc :)


    Rozwin prosze :)
  • #7 9680494
    BoskiDialer
    Poziom 34  
    Użycie alokatora pamięci na mikrokontrolerze (tutaj AVR) jest według mnie przerostem treści. Zwykłe statyczne alokowanie tablic oraz wypełnienie dodatkowej tablicy wskaźnikami jest najlepszym rozwiązaniem. Alokator pamięci ma tą wadę, że przydzielenie pamięci może się nie powieść (dodatkowe przypadki do obsługi), pamięć będzie ulegać fragmentacji (w przypadku przydzielania bloków o róznej długości) oraz całkowite zużycie pamięci nie będzie znane po kompilacji, tylko dopiero w trakcie wykonywania. Aby uniknąć fragmentacji można ograniczyć się do bloków o zawsze takim samym rozmiarze, a ja wtedy powiem, że można sobie utworzyć globalną tablicę składającą się z elementów o tym właśnie rozmiarze - wtedy unika się potrzeby stosowania malloc.
  • #8 9680546
    Gostek
    Poziom 17  
    No wlasnie - zapomnialem nadmienic, ze ilosc linii w menu bedzie zmienna, bedzie zalezec od wyniku innej funkcji podczas dzialania programu.
    Choc to mozna zrobic tak:
    Kod: C#
    Zaloguj się, aby zobaczyć kod
  • #9 9680579
    michalko12
    Specjalista - Mikrokontrolery
    W takim wypadku do funkcji rysującej menu wysyłałbym 1 string z odpowiednimi delimiterami dla każdej pozycji np
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    i funkcja rysująca menu pobierałaby sobie po kolei kawałki stringu na poszczególne pozycje.
  • #10 9680624
    BoskiDialer
    Poziom 34  
    Albo przekazywać wskaźnik na funkcję oraz pewien dodatkowy wskaźnik. Funkcja rysująca menu pozyskiwała by ciąg znaków za pośrednictwem przekazanej funkcji. W ten sposób nie trzeba by było trzymać wszystkich opisów na stałe w pamięci, były by generowane tylko na żądanie w momencie widoczności danej pozycji menu. Jeszcze lepiej przekazywać wskaźnik na strukturę zawierającą:
    - wskaźnik na funkcję, która będzie wypełniać bufor
    Kod: text
    Zaloguj się, aby zobaczyć kod

    - ilość pozycji menu
    - dodatkowy wskaźnik dla funkcji umożliwiający rozeznanie się w kontekście wywołania.

    Rozwiązań jest bardzo dużo, przy zmiennej ilości pozycji najbardziej jednak przemawia za mną rozwiązanie opisane przed chwilą - zalety: bardzo małe zużycie pamięci, brak ograniczenia na długość menu etc. Co więcej: struktura wyżej opisana mogła by zawierać funkcję wywoływaną np po kliknięciu w którąś pozycję menu. Do funkcji przekazywany był by indeks pozycji w menu. W ten sposób można obsłużyć dowolne menu w bardzo prosty sposób, a zmiana menu na inne polegała by tylko na podmianie tej struktury (wymiana funkcji i/lub kontekstu funkcji).
  • REKLAMA
  • #12 9680642
    michalko12
    Specjalista - Mikrokontrolery
    Tylko, że to nie jest tylko rysowanie menu, ale cała logika GUI.

    Dodano po 3 [minuty]:

    nsvinc napisał:
    Przy czym te delimitery lepiej żeby były znakiem niedrukowalnym wg. ASCII, np. 0x3 ;] Użycie dwukropka jako delimitera uniemożliwia użycie dwukropka jako znaku w tekscie do wyświetlenia (o ile mówimy o najprostszym algorytmie).

    Czepiasz się. ;)
    Piszesz w c? Masz tam jakieś niedrukowane znaki? Są znaki specjalne czy kombinacje tworzące znaki specjalne.
    Myślę, że autor zrozumiał ideę.
  • #13 9680664
    Gostek
    Poziom 17  
    To ciekawa koncepcja, i tej koncepcji moze bede sie trzymal przy pisaniu nowego MENU ;) Problemem jest tylko to, ze chcialem uniknac modyfikacji aktualnej procedury rysujacej, bo jest wykorzystywana przez inne funkcje.
    Choc korci mnie :)
    Chyba na razie zatrzymam sie przy rozwiazaniu z postu #8 zainspirowanym przez Boskiego, pozwoli mi to szybko wypchnac projekt.
    Dziekuje wszystkim.
  • #14 9680698
    nsvinc
    Poziom 35  
    michalko12 napisał:
    Są znaki specjalne czy kombinacje tworzące znaki specjalne.

    Pisalem o "najprostszym" algorytmie ;]
    Zawsze można rozpoznawać pojedynczy dwukropek jako delimiter, a >1 dwukropek pod rząd rozpoznawać jako znak dwukropek (lub więcej ich), np. "pleple:::foo" widzane po sparsowaniu jako "pleple::foo". Ale to już "bardziej skomplikowany" algorytm ;] i trzeba pisać parser ;]
REKLAMA