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

C i tablice zmiennych - indeksowanie, wpisywanie, itoa()

smajlas 24 Mar 2008 23:20 6457 13
REKLAMA
  • #1 4950406
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Witam.
    Zająłem się dzisiaj tablicami (to w ramach prób odczytu numeru seryjnego z urządzenia Dallasa). Aby sobie ułatwić i sprawdzić jedną z funkcji zdefiniowałem tablicę 16-elementową z wartościami liczbowymi, a następnie chciałbym wyświetlić osiem pierwszych liczb na LCD, w postaci numerycznej, czyli na LCD chcę w tym przypadku uzyskać 12345678 (a nie "krzaczki" spod adresów 1-8 mojego CGROM-u). W tym celu użyłem funkcji itoa(). Niestety, napotkałem pewien opór ze strony kompilatora.
    
    int bufor[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    char bufor1[16]; //bufor na przekształcone wartości
    char buforz[4]; //bufor pomocniczy
    char h;
    int i;
     for(i=0;i<8;i++)	//wypisz na LCD osiem pierwszych znaków z tablicy bufor
     {
    h=itoa(bufor[i],buforz,10);
    bufor1[i]=h;
     write_char(bufor1[i]);
     }
    

    Próba skompilowania tak przygotowanego kodu kończy się powodzeniem, ale kompilator ostrzega:
    warning: assignment makes integer from pointer without a cast

    Co dziwne, jeśli zamiast:
    h=itoa(bufor[i],buforz,10);

    wstawię
    itoa(bufor[i],buforz,10);

    to wszystko jest ok. Niestety, wtedy nie osiągam zamierzonego efektu, bo do tablicy bufor1 nie trafia nic... (co jest jasne)
    1. Co zrobić, żeby jakoś przerobić zmienne z wartości liczbowych na kody ASCII? A może jakieś rzutowanie typów?
    (chcę to później wyświetlić na LCD za pomocą funkcji write_char(), żeby udało się wyświetlić również zera, czego write_text() najwidoczniej nie umie, bo wyświetla mi tylko część seriala...)
  • REKLAMA
  • #2 4950506
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    pierwszy wynik w google i wszystko jasne...

    http://www.google.com/search?client=opera&rls=pl&q=itoa&sourceid=opera&ie=utf-8&oe=utf-8

    http://www.cplusplus.com/reference/clibrary/cstdlib/itoa.html

    itoa(bufor[i],buforz,10);
    bufor1[i]=buforz[0];

    pozatym - miej swiadomosc, ze tym sposobem przepisujesz tylko pierwszy znak - dla dwucyfrowych liczb trzeba wymyslic lepszy sposob dolaczania tablic - trzeba kopiowac az do osiagniecia znaku \0

    0x41 0x56 0x45!!
  • REKLAMA
  • #3 4950596
    nsvinc
    Poziom 35  
    Posty: 2870
    Pomógł: 262
    Ocena: 88
    uzyj funkcji strncpy z biblioteki string.h zeby skopiować ilestam znaków, a funkcji strcpy zeby skopiować cały łańcuch znaków do /0

    itoa zwraca wskaznik do stringa docelowego, ktorego uzywac nie musisz, bo funkcja przez wzkaznik modyfikuje tablice docelową.
  • #4 4952048
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Oj, nie pomyślałem, że itoa() zwraca wskaźnik, a nie int :/ Tego - przyznam się - nie sprawdziłem (mea culpa).
    I jak widzę, znowu trafiłem na przeszkodę, bo:
    Co jeśli odczytywany serial wśród innych liczb ma w środku zero? Jak się nie dać oszukać, że to koniec ciągu? Z drugiej strony znana jest jego długość, więc potrzebny mi sposób, żeby bez względu na zawartość tablicy odczytywać pierwsze 64bity (czyli 8 znaków, mam rację?)
  • REKLAMA
  • #6 4954875
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    nsvinc napisał:
    I nie kombinuj z kopiowaniem, lepiej uzywaj do takich operacji funkcji sprintf()....


    w wolnym tlumaczeniu:
    I nie kombinuj z mysleniem, lepiej zajmij 2kB pamieci uzywajac funkcji, ktora wykorzystasz w 0.1%

    pozatym - nie rozumiem za bardzo problemu z zerem... w liczbie zero moze sobie byc, ale po skonwertowaniu na ASCII zero staje sie 'zerem' czyli 0x30, czyli zdecydowanie !=0x0... wiec niby gdzie tu problem?

    0x41 0x56 0x45!!
  • #7 4955054
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Program musi się zmieścić w AT90S2313, czyli max 2k kodu. W tym przypadku lepiej unikać rozbudowanych funkcji, z których mało będę korzystał...
    Próbowałem tak:
    
     ow_reset();
     ow_write_byte(0x33); //33h to jest ReadROM
     for (i=0;i>8;i++)
     {
     bufor1[i]=ow_read_byte(); //za każdym następnym zapisem bajta przenosimy się do następnego elementu tablicy za pomocą indeksu [i]
     }
    
     ow_reset();
    for (i=0;i>8;i++)
    {
    itoa(bufor1[i],bufor,10);
    
    }
    write_text(bufor); //odczyt z tablicy - podobnie jak zapis

    ale w odpowiedzi na LCD otrzymałem tajemniczą liczbę "3"
    write_text() wygląda tak:
    
    void write_text(char *s)
    {
    while(*s) 				// do napotkania 0
      {
      write_char(*s); 		// zapisz znak wskazywany przez s na LCD
      s++; 					// zwiększ s (przygotuj nastepny znak)
      }
    }
    
  • #8 4955091
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    a czemu tajemnicza? skoro nie robisz tego w petli, to wyrzuciles na LCD ostatni z odczytanych 8 bajtow. czemu sadzisz, ze na pewno nie jest to 3?

    0x41 0x56 0x45!!
  • #9 4957453
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Freddie Chopin napisał:
    a czemu tajemnicza? skoro nie robisz tego w petli, to wyrzuciles na LCD ostatni z odczytanych 8 bajtow. czemu sadzisz, ze na pewno nie jest to 3?

    0x41 0x56 0x45!!

    Poza tym , wyświetlanie numeru seryjnego(ID) DS-a w postaci dziesiętnej , to oględnie mówiąc głupo** ... zły pomysł :D
    Proponuję liczby szesnastkowe.

    Piotrek
  • #10 4959572
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Dzięki za dotychczasową pomoc.
    Przyglądnąłem się trochę i powalczyłem ze wskaźnikami. (Wskaźniki - brr!! Jak widzę, nie dało się tego ominąć w tym przypadku. Może kiedyś się oswoję)
    Dla sprawdzenia zrobiłem:
    
    int bufor[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    char bufor1[16];
    char buforz[8];
    int i;
     for(i=0;i<8;i++)	
     {
       itoa(bufor[i],buforz,10);	//linia 1
       bufor1[i]=buforz[0];		//linia 2
     }
     
    write_text(&bufor1[0]); 		//linia 3
    

    i zadziałało :) Przynajmniej w tym przypadku, bo próba użycia tego do odczytu seriala niekoniecznie musiała się udać :/
    
    for (i=0;i>8;i++)
     {
     bufor1[i]=ow_read_byte(); //za każdym następnym zapisem bajta przenosimy się do następnego elementu tablicy za pomocą indeksu [i]
     }
    for (i=0;i>8;i++)
    {
    itoa(bufor1[i],bufor,16);
    buforpom[i]=bufor[0];
    }
    //i=0;
    write_text(&buforpom[0]);
    

    ...
    Ach, dobra, widzę że poszedłem na skróty. Jak do pierwszego przykładu w tablicę powpisywałem liczby dwucyfrowe to przestało być tak kolorowo. Muszę zmienić sposób "przerobu" liczb...
    Ok, jutro cd.
  • #11 4975567
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Ciąg dalszy:
    Po zmianie:
    
    int i;
     for(i=0;i<8;i++)	//wypisz na LCD osiem pierwszych znaków z tablicy bufor
     {
       itoa(bufor[i],buforz,10);	//linia 1
       bufor1[i+i]=buforz[0];		//linia 2
       bufor1[i+i+1]=buforz[1];
     }
     
    write_text(&bufor1[0]); 		//linia 3
    

    jest w porządku, ale tylko kiedy tablica bufor[] składa się z liczb dwucyfrowych, gdzie dziesiątki nie są zerami, czyli:
    
    int bufor[16]={41,42,43,64,34,66,67,68,69,10,11,12,13,14,15,16};
    

    jest ok, wyświetla dobrze, ale kiedy wstawię zero gdzieś w środku, np:
    
    int bufor[16]={41,42,43,64,00,66,67,68,69,10,11,12,13,14,15,16};
    

    na LCD wyświetlone zostaje 414243640 i... nic więcej. Ten problem jest jak na razie dla mnie najistotniejszy, bo wydaje mi się, że w serialu jednego z urządzeń mam zero, podobnie jak w tej tablicy.
    Kiedy wstawię
    
    int bufor[16]={01,02,03,04,05,06,07,10,11,12,13,14,15,16};
    

    na LCD 1 i nic więcej, (wiem, nie ma 08 i 09, ale o tym później)
    próba wpisania
    
    int bufor[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    

    też daje 1 na LCD.
    Dlaczego nie wyświetla zer? Przecież to nie koniec stringa...
    No i ten błąd:
    przy próbie wpisania w tablicę:
    
    int bufor[16]={01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16};
    

    otrzymuję komunikat kompilatora:
    "lcd7_1.c:158:38: invalid digit "8" in octal constant
    lcd7_1.c:158:41: invalid digit "9" in octal constant"
    Kto mu powiedział, że to są stałe w octal-u?? Czyżby coś w makefile?
  • Pomocny post
    #12 4975599
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    sam mu to powiedziales. liczby w formacie osemkowym zaczynaja sie dla kompilatorow od zera. szesnastkowe zaczynaja sie od 0x, binarne od 0b, osemkowe od 0

    
    bufor1[i+i]=buforz[0];      //linia 2 
       bufor1[i+i+1]=buforz[1];
    


    a co to za herezje? masz tutaj odpowiedz, czemu LCD sie krzaczy. konwertujesz liczbe jednocyfrowa. sila rzeczy - dostajesz jedna cyfre. czyli to co robisz w drugiej linijce jest... kopiowaniem znaku konca stringa: '\0'. twoja petla jest zle zbudowana niestety. nalezaloby to zrobic tak:

    
    
    // dodatkowy licznik tablicy i dodatkowy wskaznik - czysta wygoda, nie
    // sadze, aby mozna bylo sie obejsc bez tych 2 zmiennych
    int i,j=0; 
    char* char_ptr;
     for(i=0;i<8;i++)   //wypisz na LCD osiem pierwszych znaków z tablicy bufor 
     { 
       char_ptr=itoa(bufor[i],buforz,10);   //linia 1 
    
       do
         bufor1[j++]=*char_ptr++;
      while(*char_ptr);
    
    // kopiujesz znaki z tablicy wynikowej (wskazywanej przez char_ptr) do
    // bufora, az do napotkania znaku konca stringa
    
     } 
    
    bufor[j]='\0'; 
    // moze byc tez (istnieje szansa, ze bedzie szybciej i optymalniej):
    // bufor1[j]=*char_ptr;
      
    write_text(bufor1);       // a tak sie powinno podawac adres tablicy do funkcji <:
    


    takie cos powinno dzialac


    0x41 0x56 0x45!!
  • REKLAMA
  • Pomocny post
    #13 4975698
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    smajlas napisał:
    Ciąg dalszy:...

    ... bezradnego miotania się :|
    Powtarzam : liczby dziesiętne w tym przypadku = głupota
    Przykład:
    1) dane[2]={0x02,0x37}; ->na lcd zobaczysz 255
    2) dane[2]={0x19,0x05}; ->na lcd zobaczysz 255
    Bez komentarza ;)
    Proponuję np.
    
    unsigned char bufor[16]={0x19,0x05,0xcd,0x0c,0x0a,0x3b,0xaa,0xff};
    char bufor1[17]; 
    char *ptr_to_char=bufor1;
    int i;
    
    int main()
    {
    	for(i=0;i<8;i++)   //wypisz na LCD osiem pierwszych znaków z tablicy bufor
    	{
    		*ptr_to_char++=(bufor[i]>>4)+(((bufor[i]>>4)>0x09) ? 0x37 : 0x30);
    		*ptr_to_char++=(bufor[i]& 0x0F)+(((bufor[i]& 0x0F)> 0x09) ? 0x37 : 0x30);
     	}
    	*ptr_to_char='\0';
    	write_text(bufor1);
     /* ... */
     }
    


    W takim(szesnastkowym) przypadku , nie ma mowy o błędzie , w odczycie ID.

    Piotrek
  • #14 4996069
    smajlas
    Poziom 12  
    Posty: 74
    Pomógł: 1
    Ocena: 2
    Freddie: No tak, formaty... czepiam się kompilatora, a sam kazałem :)
    Ale jeśli:
    Cytat:
    konwertujesz liczbe jednocyfrowa. sila rzeczy - dostajesz jedna cyfre. czyli to co robisz w drugiej linijce jest... kopiowaniem znaku konca stringa: '\0'.

    to dlaczego zadziałało dobrze dla liczb dwucyfrowych?
    A kod
    
    bufor1[i+i]=buforz[0];
    bufor1[i+i+1]=buforz[1];
    

    miał robić tak: skonwertować liczbę, wstawić ją do bufor1 pod 2 razy i, a następną cyfrę z konwersji wstawić na następnej pozycji bufor1. Potem wyświetlić i voila. Skojarzyłem, że jak jest zero, to zajmuje ono tylko jedną pozycję, a potem będzie znak końca linii, więc jednak to co zaproponowałeś jest lepsze, no i działa oczywiście :)
    write_text(bufor1);

    podawanie adresu tablicy do f-cji... tego nie wiedziałem, braki w umiejętnościach, muszę poćwiczyć tablice, nie ma rady.

    Zumek:
    Jak zwykle na miejscu i w obronie słusznego programowania :)
    Wybrałem liczby dziesiętne dla obrazowania tablicy z wartościami dziesiętnymi (takie przynajmniej było założenie). Wiem, że do seriala lepiej zabrać się z szesnastkowym, miałem to później zrobić w miarę postępów z wyświetlaniem "normalnej" tablicy. Teraz, jak już sobie z tym poradziłem, ups, poradziliście :) to zabiorę się za seriala. Jednak to co umieściłeś w kodzie, to... jak dla mnie siekiera! Ty chyba masz wbudowany jakiś moduł przerabiający myślenie na kod w C. Chciałbym to rozgryźć, ale zastanawia mnie, jak Ty to piszesz?? Po prostu szczęka mi opada...
    A może zdradź tajemnicę i powiedz, jak się tego nauczyłeś??
    Dziękuję wszystkim za pomoc i pozdrawiam

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z indeksowaniem i konwersją wartości liczbowych w tablicach w języku C, w kontekście wyświetlania numeru seryjnego urządzenia Dallas na wyświetlaczu LCD. Autor próbował użyć funkcji itoa() do konwersji liczb całkowitych na łańcuchy znaków, aby wyświetlić osiem pierwszych elementów tablicy jako ciąg cyfr. Pojawiły się problemy z interpretacją zwracanej wartości funkcji itoa() (wskaźnik, a nie int) oraz z kopiowaniem wyników konwersji do bufora wyjściowego, szczególnie gdy liczby zawierały zera lub były jednocyfrowe. Wskazano, że itoa() modyfikuje przekazany bufor znakowy i zwraca wskaźnik do niego, a do kopiowania należy używać funkcji strcpy() lub strncpy(), aby poprawnie łączyć łańcuchy znaków. Zwrócono uwagę, że wyświetlanie numeru seryjnego w formacie dziesiętnym jest nieoptymalne i lepiej stosować format szesnastkowy, co eliminuje problemy z zerami i ułatwia interpretację danych. Zaproponowano rozwiązanie polegające na ręcznym konwertowaniu bajtów na znaki szesnastkowe, co pozwala na poprawne wyświetlenie całego numeru seryjnego bez błędów związanych z końcem łańcucha znaków. Omówiono także ograniczenia pamięciowe mikrokontrolera AT90S2313, co wymusza unikanie rozbudowanych funkcji. Wskazano na konieczność stosowania wskaźników i poprawnego zarządzania buforami znakowymi w celu prawidłowego wyświetlania danych na LCD.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA