Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Szkolenia SonelSzkolenia Sonel
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[AVR][C] jak działać ze stringami lub wskaźnikami

05 Jun 2008 19:14 11080 35
  • Level 42  
    Witam,

    sorki za może dziwne pytanie ale dopiero uczę się C, to początki. Otóż jak tu działać na tzw STRINGACH

    chciałbym np w programie do jakiejś zmiennej czy wskaźnika (obojętnie co) w trakcie programu w różnych np IF'ach podstawiać jakiś tam różny tekst. No i tu napotykam na ogromny problem. Jak to robić.

    Narazie wiem tyle, że jak zdeklaruję sobie np:

    Code:
    char my_str[] = "jakis napis";


    to wszystko będzie dobrze i będę mógł sobie używać my_str jako mój string do wyświetlania np napisów na LCD

    ale już przecież w kodzie nie można sobie napisać :

    Code:
    my_str = "jakis napis";


    --------------------------

    próbowałem więc tak:

    Code:
    char *wsk_str;


    a potem w kodzie zrobiłem sobie:

    Code:
    wsk_str = "jakis napis" 


    i jeśli tylko taka jedna linijka jest to jakoś to działa ale jeśli dalej gdzieś
    zrobię

    Code:
    wsk_str = "inny tekst" 


    to już jakieś cyrki mi się dzieją, eeeeh coś nie mogę zaskoczyć z tym

    .......................................

    generalnie - jak działać na stringach - albo jak sobie z tym radzić, żeby było jakoś podobnie jak w Bascomie czy jak na PCtach w Pascalu. Tam string to string i wiadomo co i jak - a tu???? .... taaak wiem, na pewno jest lepiej tylko trzeba z tym zaskoczyć - proszę o jakieś podpowiedzi naprowadzające

    pozdrawiam
    [30.03.2021, darmowy webinar] Nowoczesna diagnostyka maszyn, monitorowanie i przewidywanie awarii. Zarejestruj się
  • Szkolenia SonelSzkolenia Sonel
  • Helpful post
    MCUs specialist
    string jest tablicą charów.

    deklarujac
    char string[]="abcd";
    otrzymujesz tablice 5cio elementowa, do ktorej zmienna string jest wskaznikiem [;
    1. dlaczego 5 elementowa? bo masz w niej 'abcd\0' - znak \0 (ASCII 0) oznacza koniec stringa
    2. dlaczgo wskaznik? otoz zmienna 'string' jest wskaznikiem pierwszego elementu tablicy czyli string[0].

    w istocie w C nie da sie przypisac do zmiennej stringa w sposob bezposredni, jednak jest to do zalatwienia jedna uniwersalna funkcja, ktora w kazdym kompilatorze juz jest i jest nia chyba strcpy. jak ci sie nudzi i chcesz sie czegos nauczyc, to mozesz napisac sobie taka sam <;

    idea jest po prostu taka, ze zamiast:
    zmienna="string";
    robisz
    funkcja(zmienna,"string");

    generalnie w jezyku C nie ma czegos takiego jak string i wszystko opiera sie na tablicy. dlatego trzeba traktowac stringi jako taka wlasnie tablice. tak samo przeciez nie machniesz w jednej linijce czegos takiego:

    array={1,2,3,4,5}; (oczywiscie poza deklaracja na poczatku kodu)

    ale juz mozesz zrobic tak:

    *string='a';
    *(string+1)='b';
    *(string+2)='c';

    albo

    string[0]='a';
    string[1]='b';
    string[2]='c';

    BARDZO WAZNA RZECZA jest to, abys stringa zakonczyl znakiem NULL - \0 co pozwoli ci przetwarzac w funkcjach stringi niezaleznie od ich dlugosci.

    dlatego rozmiar jakiejs zmiennej, ktora uzyjesz do przechowywania stringow musi byc o 1 wiekszy:

    char zmienna[10];

    pomiesci ci to napis o dlugosci 9 znakow, 10 znakiem _powinno_ byc \0. jak go nie dasz, to oczywiscie sie nic nie stanie, ale przetwarzanie stringow bedzie trudniejsze, a program moze isc czasem w maliny. zwykle funkcje przetwarzaja stringa pod postacia:

    while(*(++string_ptr))
    {
    ...
    }

    tak wiec robi ona cos do momentu napotkania zera. jak zera nie bedzie, to ci przemieli caly RAM i w ktoryms tam momencie sie wylozy <:

    mam nadzieje ze znasz angielski [; http://www.cplusplus.com/reference/clibrary/cstring/strcpy.html
    jak nie to po polskiemu: http://pl.wikibooks.org/wiki/C/strcpy

    jak poszukasz po necie, to znajdziesz gdzies pewnei zrodlo tej funkcji, pewnie zajmuje ze 3 linijki

    0x41 0x56 0x45!!
  • Helpful post
    Level 34  
    mirekk36 wrote:

    próbowałem więc tak:

    Code:
    char *wsk_str;


    a potem w kodzie zrobiłem sobie:

    Code:
    wsk_str = "jakis napis" 


    i jeśli tylko taka jedna linijka jest to jakoś to działa ale jeśli dalej gdzieś
    zrobię

    Code:
    wsk_str = "inny tekst" 


    to już jakieś cyrki mi się dzieją, eeeeh coś nie mogę zaskoczyć z tym


    Generalnie dobrze kombinujesz ;), tak jak najbardziej można w C, ale...
    W AVR, z uwagi na rozdzieloną pamięć programu i danych, przy zwykłych napisach i wskaźnikach do nich, te napisy muszą się znaleźć w RAMie, bo do FLASHa kompilator nie potrafi się wprost odwołać (GCC, niestety, nie jest przystosowane do architektury typu harwardzkiego). Zatem na początku kompilator kopiuje napisy do RAMu, a ponieważ tego jest mało, to mogą zostać np. zamazane przez stos. Więc upewnij się, że tak nie jest u Ciebie.
    Można wymusić umieszczenie napisów wyłącznie we FLASHu, ale wtedy trzeba sie do nich odwoływać w specjalny sposób. Poczytaj w manual-u do AVR Libc o przechowywaniu stringów w pamięci programu http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
  • Level 42  
    dziękuję panowie bardzo za takie właśnie krótkie kompendium wiedzy. Czegoś takiego oczekiwałem. Trochę mnie przeraża może jeszcze to całkiem nowe jak dla mnie podejście do stringów i ich obróbki, ale w końcu cała winda chodzi w C ;) (linuxy chyba też?) - więc nie będę marudził tylko się uczył. Freddie fajny opis, szelus dobre uzupełnienie i źródła

    THX
  • Level 25  
    Nie wiem jak w AVR ale w moim kompilatorze dla PIC by wyswietlac napis statyczny (z ROMU) wystarczy przed stringiem dodac const by poinformowac, ze pobranie znakow dokona sie z pamieci programu. Bez tego "dodatku" kompilator wyswietli tylko napisy z pamieci danych (pamieciozerne, ale tez czasem potrzebne, jesli tworzymy napis dynamicznie). Funkcja do wyswietlania napisow stringa typu NULL-end terminated ponizej (ta akurat dla UART-a ale w jasny sposob pokazuje idee wysylania znak po znaku, ktora moze sie koledze przydac)

    BF

    Code:

    void SendString(const char* Text){
    while(*Text){           //krec tak dlugo az nie napotkasz konca stringa (NULL)
       while(!TRMT);        //czekaj na zezwolenie (flaga sprzetowa UART)
       TXREG = *Text++;     //wyslij kolejny znak stringa Text
       }
    }


    BF
  • Szkolenia SonelSzkolenia Sonel
  • Level 31  
    Bigfoot wrote:
    Nie wiem jak w AVR ale w moim kompilatorze dla PIC by wyswietlac napis statyczny (z ROMU) wystarczy przed stringiem dodac const by poinformowac, ze pobranie znakow dokona sie z pamieci programu.


    W AVR-GCC tak nie jest.
  • Level 19  
    Porównaj, komentarz chyba zbędny.
    Code:

    #include <avr/pgmspace.h>
    const char st_w_RAM[]="abcd";
    const char st_w_ROM[] PROGMEM ="tekst w pamieci flash";


    Nie tylko tablice znaków:
    Code:

    const float PI PROGMEM=3.14159;
    const float PARAMETRY[3] PROGMEM={1.212, 2.4, 3.56};
  • Level 42  
    odnośnie zapamiętywania i pobierania stringów z pamięci ROM(flash) to nie mam jakby problemów ale chodzi mi o sposoby obróbki tych "ala" stringów. Tzn po wykładzie kolegi Freedie już czuję o co chodzi ale np tak:

    w pascalu(delphi) mam taką swoją ulubioną i często potrzebną mi funkcję

    Code:
    function ScanStrSP(var Text: string; Separator: string): string;
    
    var
      I: Integer;
    begin
      Text:=TrimLeft(Text);
      I := 1;
      while (I <= Length(Text)) and (Text[I] <> Separator) do Inc(I);
      Result := Copy(Text, 1, I-1);
      Text := Copy(Text, I+1, Length(Text)-I);
    end;


    nie miałem najmniejszego problemu z przerobieniem jej na Bascoma - i zrobiłem to tak:

    Code:
    Function Scanstrsp(text As String , Byval Sep As String) As String
    
    Local I As Byte , Dl As Byte

      I = 1
      While I <= Len(text)
        If Mid(text , I , 1) <> Sep Then
          Incr I
        Else
          Exit While
        End If
      Wend
      Dl = Len(text) - I
      Decr I
      Scanstrsp = Left(text , I)
      Text = Right(text , Dl)

    End Function


    tylko, że w Pascalu i Bascomie jest podobne podejście do stringów. A w C jak widzę - będę musiał zrobić potrójne salto z podwinięciem i czterema fikołkami, żeby tak obrobić string'a ;) (na moim dotychczasowym poziomie wiedzy oczywiście)

    znalazłem wprawdzie w C tę standardową bibliotekę, która oferuje podstawowe operacje na takich łańcuchach znaków jak sklejanie, wyszukiwanie itp - ale muszę to podejrzeć i zobaczyć , nauczyć , przestawić myślenie - tak jak to się robi na co dzień w C ;)
  • MCUs specialist
    jesli dobrze widze, to funkcja ta dzieli stringa na dwa kawalki, oddzielone separatorem.

    jesli tak, to da sie to zrobic w C bardzo prosto. jesli nie, to nie czytac dalej [;

    na poczatku programu trzeba miec zadeklarowane dwa bufory:

    Code:

    char bufor1[]="Przykladowy tekst, ktory podzielimy", bufor2[30];


    teraz funkcja powinna wygladac MNIEJ WIECEJ tak:
    petla typu do...while (zalatwi to od razu sprawe zakonczenia jednego ze stringow), ktora przepisuje najpierw jednego stringa do drugiego, sprawdzajac czy aktualny znak nie jest separatorem, a jesli tak, to zaczyna ona przepisywac stringa pierwszego od jakiegos miejsca na jego poczatek (przesuwac go)

    da sie to, jak wiadomo, zrobic na milion sposobow [; taki narzucajacy sie i w miare przejrzysty (do tego bardzo wazna lekcja - przekazywanie parametrow przez adres [; konieczne do operacji na tablicach lub wielu zmiennych w funkcjach):

    Code:

    void ScanStrSP(*bufor1,*bufor2,*separator)
    {
        char *src,*dest;

        dest=bufor2; // na poczatku przepisujemy z bufor1 do bufor2
        src=bufor1;

        do
        {
            if(*src==*separator) // jesli osiagniety zostanie separator, to pomijany jest aktualny krok, konczony jest string wynikowy i zmieniany wskaznik bufora docelowego
            {
                *dest='\0';
                dest=bufor1;
                continue;
            }
            *src++=*dest++; // rzeczywiste skopiowanie jednego znaku ze zrodla do bufora
        } while(*src) // petla trwa do osiagniecia znaku \0 w buforze zrodlowym, czyli przemielenia calego stringa

    }


    wywolanie takiej funkcji wygladac bedzie

    Code:

    ScanStrSP(bufor1,bufor2,",");


    lub

    Code:

    ScanStrSP(&bufor1[0],&bufor2[0],",");


    w efekcie po przemieleniu zawartosc buforow powinna wygladac nastepujaco:
    bufor1:
    " ktory podzielimy\0 ktory podzielimy\0"
    bufor2:
    "Przykladowy tekst\0<smieci do konca bufora>"

    oczywiscie mog sie mylic [; funkcja wycina separator - jesli ma go nie wycinac, to trzeba ja troche zmienic oczywiscie. jak wiec widzisz - cala sprawa zalatwiona jest jedna petla z jednym warunkiem koncowym i z jednym ifem w srodku [;

    0x41 0x56 0x45!!
  • Level 19  
    Jeżeli można wyciąć separator to trochę szybciej:
    Code:

    char t1[]="jakis tekst";
    char * t2;

    i=0;
    while(t1[i++]!=' '); //separatorem jest tutaj spacja
    t1[i-1]=0;
    t2=t1+i;

    t1 zawiera napis "jakis" a t2 "tekst"
    oczywiście można dodać dodatkowe warunki gdyby separator nie istniał w ciągu oraz czy t1 da się podzielić (nie jest np jednoznakowy)
  • MCUs specialist
    tyle ze t2 w sumie niczego nie zawiera, bo operuje na zmiennej t1. w zalenosci od zastosowan moze to byc dobre lub zle.

    w sumie to petle mozna rozwiazac rowniez tym sposobem (najpierw znalezc separator, a potem przekopiowac reszte stringa, zastepujac separator znakiem \0.

    jak widac - ilu ludzi, tyle pomyslow [;

    0x41 0x56 0x45!!
  • Level 19  
    Quote:
    tyle ze t2 w sumie niczego nie zawiera

    to prawda, źle się wyraziłem. W C ani t1 ani t2 nie zawiera żadnych
    napisów. Przed wykonaniem tych 3 linijek t1 wskazuje na napis "jakis tekst" a po wykonaniu t1 wskazuje "jakis" a t2 wskazuje na napis "tekst"
    To czy potrzebne jest kopiowanie zależy od tego co bedziemy robić z dalej z t1, czy np nie bedzie potrzebny jako bufor w pierwotnej wielkości.
  • Level 42  
    dzięki za podpowiedzi, dzisiaj wieczorkiem będę miał co robić eeeeh - zaćwiczę to na śmierć, tym bardziej, że te wasze przykłady tak jednak, krótko daje się napisać. Więc tylko początkującemu jak mi, może się wydawać, że trzeba jakieś extra salta programistyczne dokonywać ;)

    .... ale ok zanim się wgryzę w kod wieczorkiem to od razu na gorąco jeszcze jedno dopytam odnośnie tch przykładów

    .... otóż chciałbym aby ta funkcja zwróciła mi jako parametr na wyjściu ten odcięty do separatora łańcuch natomiast skróciła łańuch wejściowy(czyli ten który podajemy do funkcji na starcie jako paramter)

    czyli tak na szybko kombinuję, żeby nie było tego void na początku tylko jakiś wskaźnik do tego odciętego łańcucha.

    hmmmm tylko co? wewnątrz funkcji trzeba by było jakoś (sorry za wyrażenie) - zaalokować pamięć RAM żeby to mogło odbywać się jakoś dynamicznie. Mówiąc o alokowaniu pamięci myślę jakbym robił to na PC'cie a może tu się w ogóle tak nie robi???

    albo może w ogóle w C nie stosuje się w ten sposób zwracania parametrów na wyjściu ?

    generalnie często stosuję tę funkcję gdy np przez RS232 przesyłam jakieś informacje, wiele parametrów. Pakuję je wtedy do długiego stringa i go całego wysyłam przez RS232 , np:

    Code:
    "header;dana01;12;tekst;cokolwiek"


    a następnie tam gdzie zostaje odebrany ten cały string tą właśnie funkcją po kolei odzyskuję parametry (ja wiem w jakiej one są kolejności i które są liczbami a które tekstem itp)

    czyli pierwsze wywołanie funkcji np:

    Code:
    hdr = ScanStrSP(moj_string, ';')


    spowoduje że w zmiennej hdr będę miał łańcuszek "header"

    a potem kolejno jakieś tam zmienne zdeklarowane i:

    Code:
    dn01 = ScanStrSP(moj_string, ';')
    
    licz1 = ScanStrSP(moj_string, ';')
    txt  = ScanStrSP(moj_string, ';')


    i po tych operacjach wiadomo co mam w kolejnych zmiennych a w stringu przekazywanym moj_string pozostało już tylko słówko "cokolwiek" - bo był on za każdym razem skracany.

    oczywiście na razie nie proszę o gotowe rozwiązanie - bo wolałbym sam poćwiczyć wieczorkiem a później najwyżej dopytam - interesuje mnie tylko na teraz to co mówiłem wcześniej - czy da radę tak zwracać parametr na wyjściu z tej funkcji???? , a samo skracanie parametru wejściowego - to na pewno da radę bo można go jakoś przepisywać wewnątrz. Będę z tym kombinował
  • Level 35  
    ludzie!! nie 'char' a UNSIGNED CHAR !! pierwsza istotna sprawa.

    Wskaznik na 'char' czy na 'unsigned char' to niewielka róźnica, bo bajt to bajt. Ale kompilator i tak zwróci ostrzerzenie przy kompilacji jesli pod adres wzkaznika na char zapiszemy zmienna typu unsigned char...

    ale: _W_TABLICACH_PRZECHOWUJĄCYCH_STRING_STOSUJEMY_UNSIGNED_CHAR_....
  • Helpful post
    MCUs specialist
    bezposrednio nie jest to mozliwe tak jak ze zwroceniem wartosci liczbowej. funkcja w c moze zwrocic tylko JEDNA wartosc. moze zwrocic wskaznik - czyli jakby poczatek tego stringa. tyle ze zaalokowane wewnatrz funkcji zmienne po jej zakonczeniu sa zwalniane i nalezy zalozyc, ze przestaja istniec. oczywiscie wiadomo, ze przez chwile cos tam na tym stosie bedzie lezec, ale NIE ZAWSZE - rownie dobrze dane moga zostac zmasakrowane od razu po zamknieciu funkcji, dlatego nie mozna tak zakladac.

    rozwiazania sa 2.

    1. musisz miec globalny bufor, na ktorym bedzie operowala twoja funkcja (slabe rozwiazanie)
    2. musisz w funkcji nadrzednej miec lokalny bufor, ktorego adres podajesz do funkcji, tak zeby miala ona na czym operowac - dokladnie to jest zrobione w tym kodzie, ktory ja napisalem. zeby funkcja zwracala ci uchwycik do stringa przycietego od poczatku, wystarczy ze na koncu dopiszesz jedna linijke, ale skoro mowisz, ze ma nie byc gotowca, to ... to nie bedzie [;

    skracanie parametru wejsciowego (pozorne coprawda, bo RAMu tablica zajmuje wciaz dokladnie tylesamo, tyle ze zawartosc sie troche przesunela) rozwiazane jest rowniez w kodzie ktory ci tam wymodzilem powyzej <: sorry - na nastepny raz ostrzegaj od razu, ze ma nie byc gotowcow <:

    tak BTW to jakies ksiazki zwykle maja dosyc rozwiniete rozdzialy o tych kombinacjach jakimi jest praca ze stringami i przekazywanie 'z' i 'do' funkcji tablic. pogooglaj za opisem przekazywania parametru przez adres, tablicami i stringami w C... pierwszy wynik takiego wyszukiwania jest nawet sensowny

    to prace domowa masz, ale nie ma sie co zniechecac, bo C naprawde jest prosciutkie.

    0x41 0x56 0x45!!
  • Helpful post
    Level 19  
    Przyjrzyj się dokładnie temu co napisałem - właśnie do separowania parametrów się doskonale nadaje. Skrócenie łańcuch następuje niejako samoczynnie - nie potrzeba dodatkowej pamięci kopiowania
    Ogólnie:
    zapis char t[]="abcde" oznacza tablicę 6 elementową (5 liter + 0) przy czym t z definicji wskazuje pierwszy znak (a) w związku z tym t+2 wskazuje 3 znak (c). Przypuśćmy, że 'c' jest separatorem wszysko czego potrzebujem do rozdzielenia tych 2 argumentów (ab i de) to zadeklarować pusty wskaźnik (który wskazuje cokolwiek) oraz wpisać 0 w miejsce c a temu nowemu wskaźnikowi przypisać wartość t+3 (czyli początek drugiego parametru - de).
    Możesz zadeklarować funkcję w sposób rekursywny tak aby wczytywała parametry niezależnie od ich ilości lub nieco prościej wywołać ją tyle razy ile jest parametrów za każdym razie podając na wejściu ten wskaźnik, który pozostał - (w moim przykładzie t2). Możemy też zamienić t1 i t2
    (jak przy innych zmiennych temp=t1; t1=t2; t2=temp) i wtedy wywołujemy wielekrotnie funkcję z tym samym parametrem t1.
    Można jeszcze prościej ale nię bedę teraz mieszał :)
    Zwróć tylko uwagę, że łatwo zadeklarować funkcję, które zwróci rozdzielone parametry w tablicy zadeklarowanej char *par[8] <- to jest tabela 8 parametrów (8 stringów).
  • Level 35  
    ->mirekk36

    z tego co piszesz rozumiem ze chcesz parsować jakis konkretny string (długi string) wejsciowy i chlastać go na mniejsze wg odpowiednich zasad? Jesli tak to zbadaj ten kod

    Code:

    rxr=0; _k=0;
    while (u1rxf[rxr]) //u1rxf w tym przypadku jest twoim 'długim' stringiem ktorego dzielisz na kaawałki, rxr jest indeksem 0 tego stringa, bo skąś trzeba zacząć
        {
        paramstr[_j][_k]=u1rxf[rxr]; //przyjmijmy ze masz dwuwymiarową
    //tablice charów - pierwszy indeks to numer parametru, drugi to znaki
    //zawarte w tym parametrze - unsigned char paramstr[5][20]; tutaj
    //przepisuj znaki z głównego stringa do mniejszego na poczatek
        rxr++; _k++; //pomocnicza zmienna _k
        if (u1rxf[rxr]=='-') {_j++; _k=0; rxr++; }; //sprawdż czy bierzący znak to kreska - jesli tak, to zwieksz licznik parametru i wyzeruj licznik znaku w parametrze
        };


    Kod powyzszy parsuje łańcuch parametrów zakonczony znakiem pustym na kawałki które w stringu wejsciowym (u1txr) są oddzielone '-'...

    przyklad:

    string zawarty w u1txr z poczatkiem w 0 : "Moj-testowy-parametr\0"

    Po wywołaniu parsera otrzymasz:

    paramstr[0] == "Moj\0"
    paramstr[1] == "testowy\0"
    paramstr[2] == "parametr\0"

    Moze ci jakos pomogłem jesli o to chodziło, jesli nie to pomoze komuś innemu :)

    pozdrawiam

    Dodano po 2 [minuty]:

    Dodaje, że przyjąłem ze tablica paramstr w całości jest wypełniona zerami
  • Level 16  
    nsvinc wrote:
    _W_TABLICACH_PRZECHOWUJĄCYCH_STRING_STOSUJEMY_UNSIGNED_CHAR_....


    Od kiedy? Widocznie biblioteka string.h jest źle napisana.
  • Level 35  
    ->UDMA

    Wyobraź sobie ze standardowy char jest od -128 do 127 tak? Fakt ze STANDARDOWA tabela znaków ASCII jest do 127...ale co wtedy jesli wykorzystujesz rozszerzony ASCII (np. LATIN2)? Chcesz mi powiedzieć ze ktoś zadeklarował -71 znak? Dla bezpieczeństwa powinno się stosować unsigned char. Istnieją biblioteki string.h ktore są napisane dla chara bez znaku i obsluguja latiny, bo standardowe tego nie robią.

    Niedawno napisałem sporo własnych funkcji obracających stringami i jesli ktos chce mogę udostępnić. Funkcje obsługują chara bez znaku wlasnie dla ąęśćżźół itp...:

    StrUp(unsigned char *a);
    StrLw(unsigned char *a);
    StrPokemon(unsigned char *a);
    StrCopyToToken(unsigned char token,unsigned char *src,unsigned char *dest);
    StrCopyToIndex(unsigned int to,unsigned char *src,unsigned char *dest);
    StrCopyFromToToken(unsigned int from,unsigned int to,unsigned char token,unsigned char *src,unsigned char *dest);
    StrLoadCodepage(unsigned char *cp);

    ..i sporo więcej....

    [tak na marginesie: prawie wszystkie LCDki alfanumeryczne (i nie tylko) kozystają z rozszerzonej tablicy ASCII]
  • Level 25  
    nsvinc ma racje ale nie myla sie tak do konca Ci, ktorzy zawsze pisza tylko 'char'. Czesto po prostu kompilator ma domyslnie zaznaczona opcje TRAKTUJ CHAR JAKO UNSIGNED CHAR. I po prostu nawet piszac char kompilator wie, ze chodzi o unsigned char. Jezeli jasno sie okresli signed char - wtedy potraktuje liczbe jako -128:127. Ja jednak nauczony doswiadczeniem na roznych platformach zawsze dla bezpieczenstwa jawnie pisze unsigned char. Radze to tez innym :)

    BF
  • Level 35  
    Ja bym sie akurat z tym kłócił że kompilator ma 'domyslne' zamiane chara na unsigned char....Np. nie znalzlem takiej opcji w konfiguracji C30 microchipa...
  • Level 42  
    nsvinc -> może się mylę albo czegoś nie wiem , ale jak zacząłem pisać wszędzie "unsigned char" a próbuję coś pisać za pomocą AVR Studio ożenionym z GCC to zaczęły się cyrki z jakimiś warningami.

    okazuje się bowiem, że w AVR Studio a może i GCC tego nie jestem w stanie jeszcze stwierdzić jest chyba domyślnie ustawiony char jako unsigned char

    jak wyłączę ptaszka w parametrach projektu, żeby nie było tak domyślnie to trzeba sobie wtedy oczywiście wszędzie ustawiać na unsigned char. Ale tu znowu ZONK bo jak użyłem funkcji strcpy_P - to znowu warning, że jest niezgodność. Więc zajżałem do "pgmspace.h" a tam jak byk definicja funkcji ze zwykłym char bez unsigned

    Code:
    extern char *strcpy_P(char *, PGM_P); 


    [AVR][C] jak działać ze stringami lub wskaźnikami

    więc dlatego tylko próbuję wnioskować, że w GCC domyślnie char jest jako unsigned

    - działam dalej, aczkolwiek narazie to wszystko wydaje mi się pokręcone na maxa - choć czuję przez skórę, że jest fajne ;)
  • Level 35  
    stringi w c nie są trudne, jak dla mnie trudniejsze są np. w javie czy pascalu [tam to dopiero namotane] w każdym razie zycze powodzenia
  • Level 25  
    nsvinc wrote:
    nie znalzlem takiej opcji w konfiguracji C30 microchipa...


    nsvinc: Radze lepiej zapoznac sie z opcjami kompilatora, ktorego uzywasz (C30)... Ponizej cztery printscreeny z czterech roznych kompilatorow C (C++). Ja szczerze mowiac nie znam takiego, w ktorego opcji by nie bylo wyboru signed/unsigned char... Czasem domyslnie ustawiony jest typ signed, czasem unsigned - ale zawsze do wyboru przez programiste!

    C30
    [AVR][C] jak działać ze stringami lub wskaźnikami

    HiTech PIC
    [AVR][C] jak działać ze stringami lub wskaźnikami

    BB C++
    [AVR][C] jak działać ze stringami lub wskaźnikami

    AVR-GCC
    [AVR][C] jak działać ze stringami lub wskaźnikami

    BF
  • Level 42  
    Witam,

    no i po długich jak dla mnie bojach zrobiłem sobie w końcu tę funkcję i mi działa poprawnie. Tylko zapewne jak wy panowie spojrzycie, to od razu dostanie mi się za tą pętlę while(1) w funkcji oraz polecenia break w niej.

    Dla mnie najważniejsze, że się udało, zresztą zgodnie z sugestią kolegi ktrot. Tylko teraz czy mógłby mi ktoś podpowiedzieć jak można się pozbyć tego while(1) i napisać to jakoś może krócej? - tak bardziej w stylu C niż narazie moim ;)


    Code:
    char napis[20];  // zmienna w RAM (taki buforek)
    
    char *buf;  // wskaźnik używany do zmiennej napis
    prog_char my_str[] = "ola;domek;kot"; // string w pamięci programu

    char * scanstrsp(char* str, char separator)
    {
       uint8_t i = 0;
       while( 1 )
       {
          if (str[i] == separator)
          {
             str[i] = 0;
             buf = str + i + 1;   
             break;
          }
          if (str[i] == 0)
          {
             buf = str + i;
             break;
          }

          i++;
       }

       return str;
    }


    int main(void)
    {
                    // tu kopiuję sobie z pamięci programu tekst do zmiennej w RAM
       strcpy_P(napis, my_str);
                     
                    // tu ustawiam wskaźnik buf na początek tablicy ze stringiem do parsowania
       buf = napis;
       lcd(napis); // wyświetlam go sobie w 1 linijce w całości


       locate(2,1);
       lcd(scanstrsp(buf, ';'));  // w 2 linijce pojawia się ładnie "ola"

       locate(3,1);
       lcd(scanstrsp(buf, ';')); // w 3 linijce pojawia się "domek"

       locate(4,1);
       lcd(scanstrsp(buf, ';'));  // w 4 linijce pojawia się "kot"

                    // i tu już wskaźnik buf jest pusty


       while(1);


       return 0;
    }
  • Level 19  
    Nieźle. Może będziesz pierwszy na elektrodzie (a w każdym razie jednym z nielicznych), który pisze w C. 99% programów jest C podobne, tzn składnia z C ale myślenia jak w Basicu.
    Tak na szybko to spłodziłem takie coś:

    Code:

    char *par[8];
    char t[]="ab1;cd2;ef3;gh4;tyu5;";

    int param()
    {
    int i=0; int j=0;
      par[0]=t;
      while (t[i])
      { 
      while(t[i++]!=';');
      par[++j]=t+i;
      t[i-1]=0;
      }
      return j;   
    }

    void main()
    {
      int n;
    n=param();    //n zawiera liczbę parametrów
                         //a tablica wskaźników par wskazania
                         //na poszczególne    parametry
    while(1);
    }


    U Ciebie jednak lepsze jest parametryczne wywołanie funkcji, u mnie stały dostęp do parametrów w dowolnej kolejności.
  • MCUs specialist
    EDIT - post zedytowany, bo walnalem glupote.

    EDIT: ta czesc zostala wycieta, bo zamiast probowac przerabiac to co masz, lepiej machnac cos, w czym nie ma tego problemu.

    ogolnie petle mozna by zalatwic nieco inaczej, zeby to lepiej dzialalo i nie trzeba bylo kombinowac (break & if)...

    np:

    Code:
    char * scanstrsp(char* str, char separator) 
    
    {
        char* saved_str=str;
        while(*str!=0 && *str != separator) // petla oblicza pozycje separatora, albo koniec stringa
            str++;
        // koniec petli, tzn ze zostal osiagniety albo separator, albo koniec
        buf=((*str)?str+1:str); // jesli to koniec (*str==0), to bufor = adres konca (str), jesli tylko separator (*str!=0) - bufor = znak za separatorem (str+1)
        *str='\0'; // przypisac mozna i tak, bo warunek zajmie wiecej kodu i czasu
        return saved_str; //zwraca zapisana wczesniej wartosc do poczatku mielonego stringa
    }


    jesli koniecznie chcesz, to tez da sie przerobic na wersje tablicowa (czyli z indexowaniem po i), ale moim zdaniem nie warto. na 90% to bedzie wydajniejsze

    @√€!!
  • Level 25  
    ktrot wrote:
    Może będziesz pierwszy na elektrodzie (a w każdym razie jednym z nielicznych), który pisze w C.


    Co ty za herezje opowiadasz?

    BF
  • Level 42  
    dzięki Fredie -> udoskonaliłem już swoją funkcję:

    Code:
    char * scanstrsp(char* str, char separator)
    
    {

       char *rt = str;

       while( (*str) && (*str!=separator) ) str++;

       buf = str;

       if ( *str )
       {
          *str = 0;
          buf++;
       }

       return rt;
    }


    teraz chyba wygląda lepiej - a i w procku zajmuje o 12 bajtów mniej w pamięci programu. Chociaż jak zobaczyłem to parsowanie parametrów jakie podał wyżej kolega ktrot to też jest super rozwiązaniem

    .... coraz bardziej mi się ta zabawa z C podoba
  • Helpful post
    MCUs specialist
    zedytowalem przed sekunda swojego posta finalnie, ale widze ze czytales juz dobra wersje chyba.

    w sumie mozna by ja jeszcze poprawic (polaczyc to wpisywanie \0 do warunku), ale widze ze juz to zrobiles, wiec nie bede wyskakiwal z tym juz <:

    0x41 0x56 0x45!!