Ads_700x200

czwartek, 8 sierpnia 2013

ŁAMIGŁÓWKA w C ale pouczająca ;)

Witam,

Dawno już na blogu nie było żadnego konkursu. I tak nagle sobie siedzę ... myślę i wpadło mi coś do głowy. Uwaga! może być trudne więc na wszelki wypadek polecam założyć solidny kask do tej ŁAMI-GŁÓWKI ;) .... ale znając życie i was drodzy czytelnicy ... to i tak podejrzewam, że "chwila moment" i zagadka będzie rozłupana na kawałki. Nic się nie da przed wami ukryć ;) Nie mniej jednak spróbuję. Nadmienię, że sam się nagłowiłem wcześniej o co tu chodzi? jak to działa? co to w ogóle za składnia? Jednym słowem dla mnie także była to spora zagadka. Wypadałoby także zaproponować jakąś ciekawą nagrodę. Nie ma sprawy, proponuję wręcz małą pulę nagród w związku z tym, że może być ciężko. Dlatego dla osoby która spełni wszystkie warunki opisane niżej, proponuję co następuje: komplet książek wydawnictwa Atnel: "Mikrokontrolery AVR Język C Podstawy programowania" oraz "Język C Pasja programowania - mikrokontrolerów 8-bitowych". Ale to nie koniec, do tego pełen komplet programów: MkAvrCalculator, MkBootloader i "Pixel Factory wersja pełna do zastosowań komercyjnych". Pytania będą dwa....



Pierwsze to jaka będzie zawartość tablicy bufor[],

drugie pytanie .... w zasadzie zadanie, to opisać o co tu chodzi i na jakiej zasadzie to wszystko się odbywa ;)

UWAGA! prawidłowe odpowiedzi należy zgłaszać TYLKO i WYŁĄCZNIE na blogu w komentarzach do tego artykułu. Zastrzegam sobie prawo do wyboru zwycięzcy na podstawie najlepiej udzielonej odpowiedzi na dwa pytania - zadania.

Poniżej dziwny kod źródłowy:



życzę miłego łamania głowy albo zabawy w deszyfratora czy tam łamacza tajemnicy enigmy, chociaż powiem wam, że to żaden sposób na szyfrowanie ;) .... ot po prostu fajna ciekawostka w C.


czas start .....

;)

Uwaga! w przypadku jeśli ktoś już posiada wymienione w puli nagród produkty firmy Atnel, to przykro mi ale nie będzie możliwości wymiany ich na inne produkty lub wypłaty równowartości w PLN.

------------------------------------------------
AKTUALIZACJA - po konkursowa ;)

o co chodzi z mechanizmem:

"ABCD"[]

tzn przedstawię swoją wersję wyjaśnienia - wcale nie oceniając innych jako złe czy gorsze.

Otóż normalnie w C mamy do czynienia albo z tablicami np znakowymi do przechowywania tzw C-String'ów albo ze wskaźnikami do C-Stringów. Dlatego poniższe dwa zapisy są "prawie" równoważne:

      char tab1[] = "ATNEL";

      char *tab2 = "ATNEL";

różnica polega TYLKO na tym, że nazwa tab1 nigdy nie będzie mogła być zmieniona arytmetycznie, zawsze musi być wskaźnikiem na pierwszy element C-Stringa. 

Za to tab2 jest wskaźnikiem a zatem dopuszczalna będzie np operacja tab2++;

Co ciekawe (ale to już opisywałem także w Bluebook'u) chcąc np zmienić TRZECI element każdego ze stringów możemy stosować zamiennie zapisy:

      tab1[2] = 'M';

      tab2[2] = 'M'; // pomimo że tab2 to wskaźnik to możemy go traktować tak jak tablicę 

Ok to o czym piszę wyżej to można powiedzieć JAWNE definicje tablic - zgadza się ? W kodzie zagadki widzicie że w ten sposób została zdefiniowana zmienna tablicowa bufor[]. Dokładnie na podobnej zasadzie można byłoby w kodzie zagadki np napisać go w ten sposób z JAWNIE zdefiniowaną tablicą czy tablicami (dla uproszczenia podam tylko pierwszą linię kodu)

      char tablica1[] = "TIMER1V";
      char tablica2[] = "TCCR1A=(1<<COM1A0)";
      char tablica3[] = "AMD";

      int8_t j=0;
      int8_t a1;
      while( (a1=tablica1[j++]) )

            bufor[0] += a1-tablica2[ tablica3[0]-50 ];

zgadza się ? chyba każdy się ze mną zgodzi. Ale teraz zachciało nam się skorzystać z tzw anonimowej i na dodatek wersji in-line tablicy czy tablic.

      int8_t j=0;
      int8_t a1;
      while( (a1="TIMER1V"[j++]) )

            bufor[0] += a1-"TCCR1A=(1<<COM1A0)"[ "AMD"[0]-50 ];

Oba przypadki są PRAWIE IDENTYCZNE. Tzn jeśli chodzi o działanie identyczne, ale jeśli chodzi o możliwości mocno różne. Dlatego że "jawnych" tablic możemy używać w kodzie ile razy zechcemy ponieważ mamy do nich że tak powiem "uchwyt" czyli wskaźnik do pierwszego elementu w postaci zdefiniowanej nazwy: tablica1, tablica2 itp. Za to w drugim przypadku, gdy tablice zostały stworzone w postaci in-line KONIEC, nie da rady użyć ich już ponownie w innej części programu. Jak to działa? to już wiemy z komentarzy na dole ;) Najlepiej i najszerzej opisał to Andrzej Czerwoniec. Chociaż jako drugi podał prawidłowe rozwiązanie. To jednak jeszcze nie jest przesądzone że nie wygrał lub wygrał, to okaże się za chwilę. Wracając do tematu, to co w cudzysłowach "ABCDE" jest przecież C-stringiem. Dodatkowo cudzysłowy zapewniają nam końcowy dodatkowy znak ZERO kończący C-string. A zatem owe cudzysłowy są jednocześnie wskaźnikiem na pierwszy element tej anonimowej tablicy ;) do której nie mamy przecież żadnej nazwy. Ale właśnie - skoro mamy wskaźnik na pierwszy element to z kolei jak słusznie zwracał uwagę w komentarzach kolega OdeOn, możemy się przecież odwołać do poszczególnego elementu tej tablicy w sposób jaki wyżej opisałem przy wskaźniku tab2 !!! ;) Stąd taki przedziwny zapis w C

"ABCD"[4]

Przy okazji Andrzej Czerwoniec na dole w komentarzach podpowiedział również inne możliwości manewrowania takim zapisem

*("ABCD"+2)

;) to wszystko wynika z faktu - że w C praktycznie do wszystkiego co w pamięci można odwołać się przez wskaźnik, a skoro przez wskaźnik to niejako przy okazji możliwość użycia C-Stringa w cudzysłowach z nawiasami kwadratowymi na końcu postaci anonimowej tablicy inline ;)

Ktoś mnie zapytał - no dobrze - ale po co to? do czego? kiedy może się to nam przydać w C?

Moja odpowiedź jest prosta ;) .... przede wszystkim warto wiedzieć, że w ogóle taka możliwość istnieje ponieważ po pierwsze dzięki temu można jeszcze lepiej zrozumieć wskaźniki. Po drugie jak już się zna możliwość a jeszcze nie ma pomysłu na zastosowanie - to nie oznacza, że taki pomysł nagle nie zrodzi się w głowie gdy kiedyś będziemy pisali jakiś swój skomplikowany kod ;)

Ale UWAGA! .... takie inlinowe użycie tablic wcale nie jest optymalne z punktu np gospodarki pamięcią chociażby FLASH. DLACZEGO ??? Ano dlatego że przecież chyba każdy widzi, że tablica jest w RAM bo nie odwołujemy się do niej za pomocą funkcji pgm_read_xxx() ;) prawda ? A skoro tak to przecież MUSI się ona w tej pamięci RAM jakoś pojawić. Jak? Ano tak, że kompilator i tak (sorry za określenie) "wpekluje" nam ją do pamięci FLASH i co więcej, dopisze jeszcze kawałek programu startowego uruchamianego przed odpaleniem głównej funkcji programu main(), który to skopiuje tą tablicę z FLASH do RAM. A zatem stracimy nie tylko ileś bajtów FLASH na samą tablicę ale jeszcze na kod który ją skopiuje do RAM! (są też inne wady takiego inlinowego definiowania tablic - związane z przeportowaniem na inne kompilatory - nie zawsze musi to zadziałać. Na szczęście nasz AVR GCC luzikiem to akceptuje)

O labboga! .... no to skoro jest aż tak źle to po choinkę w ogóle sobie zawracać czymś takim głowę ?

No właśnie tak mogą narzekać tylko malkontenci - bo przecież potrzeby projektu bywają bardzo różne i nie zawsze największą wagę odgrywa zajętość FLASH. Czasem nas to czochra gdy mamy pod maską np 128KB FLASH a cały program i tak zajmuje nam np 20KB ;) .... i szybkość też się aż tak nie liczy

więc co może się liczyć ? ;)

no np wygoda/lenistwo programisty ;) .... aaaa bo np mam kaprys i nie chce mi się klepać tych definicji: tablica1, tablica2, tablica3 - skoro później w kodzie i tak TYLKO raz ich użyję .... a dodatkowo będę musiał przeklepywać i tak ponownie te nazwy. No to po co ? jak jestem leniwy to sobie napiszę tablicę znakową anonimową i inline'wą ;)

Jakieś przykłady praktycznych zastosowań ? hmmm - no np chcielibyśmy mieć w programie jakiś klucz do xorowania jakiegoś stringa czy transmisji i wykorzystujemy to tylko jednokrotnie w kodzie. To znowu zamiast definiować oddzielnie tablicę można użyć anonimowej inlinowej tablicy ;) .... Ale pamiętaj - ma to też swoją wadę - że jeśli to gdzieś będzie w środku kodu mającego 3000 linii, to później gdy będziesz chciał coś zmienić w tej tablicy to będzie trzeba szukać tego w całym pliku ;) ... a gdyby było na początku ładnie zdefiniowane jak się należy to byłoby o wiele łatwiej ;)

Ok nie marudzę już - pokazałem różne "ZA" i "PRZECIW" .... aczkolwiek tych PRZECIW jest moim zdaniem więcej, więc żeby nie było że tym artykułem zachęcam do nagminnego stosowania tej metody.

Tym bardziej, że (na koniec dodam) .... ta metoda to fajny TRICK w C niedostępny zwykle w innych językach ale coś za coś. Za to na pewno jest to o wiele MNIEJ CZYTELNE i może wręcz odstraszać początkujących od języka C ;) .... ale my wszyscy razem się uczymy i sobie pomagamy, poza tym jesteśmy już przeważnie dorosłymi chłopcami i dziewczynkami - więc możemy się tym "pobawić" czasem jak przyjdzie wena twórcza "ala Leniuch" ;)

KONIEC

51 komentarzy:

  1. Bufor[] będzie przechowywał makra
    Fragment kodu wykrywa który z trybów jest ustawiony w makrach jako "używany"
    Przykładowo, gdy ma być włączony TIMER1V to zostanie to wykryte, a do zmiennej J zostanie dodane 1 by zapobiec kolejnym wpisom do bufora. idąc dalej do bufor[0] zostanie wpisane makro które ustawi fusebity włączające ten moduł.

    OdpowiedzUsuń
  2. Zawartość tablicy bufor[] to ATNEL.
    W każdej pętli while() do danej komórki tablicy bufor jest dodawana różnica między zmienną a1 (w której będą zapisywane kolejne znaki podane jako argument pętli while) oraz stałym znakiem ( 65('A') lub 97('a') ).

    OdpowiedzUsuń
  3. Hehe, fajnie, fajnie :)

    Zawartość naszej tablicy bufor to znaki ASCII zkładające się na słowo "ATNEL" :)

    A teraz trochę o rozwiązaniu:
    musimy zauważyć, że stringi to tak na prawdę tablice znaków a te znaki, czyli kody ascii to nic innego jak zmienne liczbowe, więc poddają się operacją arytmetycznym jak zmienne int :>
    Co więc mamy w rezultacie, zacznijmy od końca pierwszej pętli while:
    "AMD"[0] to nic innego jak 'A' czyli wartość 65 w kodach ASCII
    (Pamiętajmy, że tak jak w tablicach, tak i w naszych stringach, liczymy od 0 ;) )
    65 - 50 = 15
    mamy więc:
    "TCCR1A=(1<<COM1A0)"[15] a więc znów literkę 'A' czyli 65 ;]
    Pętla while( (a1="TIMER1V"[j++]) )
    przeskoczy nam po wszystkich elementach tablicy "TIMER1V" automatycznie przypisując wartości do zmiennej a1 (pojawią się więc tam kolejno wartości ASCII: 'T', 'I', 'M' itd. )
    więc przeliczając to na inty otrzymamy:
    84 73 77 69 82 49 86
    wiemy też już, że musimy odjąć od tych wartości 65, otrzymujemy więc:
    19 8 12 4 17 -16 21
    a w pętli następuje sumowanie tych wartości do naszego pola w buforze, co więc będzie kryło się pod bufor[0]?
    A no wartość 65 - czyli nasze wcześniej poznane 'A' ;)

    Dalsze dekodowanie przebiega analogicznie, więc myślę, że nie będę opisywał, mam nadzieję, że udało mi się to jako tako wyjaśnić :)

    Pozdrawiam,
    Andrzej Czerwoniec

    OdpowiedzUsuń
  4. Widzę że szybko poszło :)

    OdpowiedzUsuń
  5. Jeszcze moje krótkie uzupełnienie, przepraszam, że na dwa razy, wcześniej śpieszyłem się do pracy, teraz już odpisuje z pracy bo pomyślałem, że warto to dodać
    mianowicie, jak działa pętla while i czemu się przerywa ;)
    operacja przypisania zwraca wartość przypisywaną, pętla while będzie więc otrzymywać wartości kolejnych znaków ze stringu "TIMER1V".
    Co gdy dojdziemy do końca? wpadnie tam znak końca stringu czyli wartość liczbowa 0, a jak wiemy, w C oznacza to niespełniony warunek więc pętla nam się zakończy :)
    Gdyby były jakieś wątpliwości to mogę jeszcze wyjaśnić ;)

    OdpowiedzUsuń
  6. Udalo mi sie to zrozumiec w pare minut :D Dzieki Andrzej :D ale jeszcze mam takie pytanko odnosnie kolejnosci wykonywania w petli while.
    while((warunek ))
    bufor[0]+=........; //Najpierw wykona sie ta instrukcja a po niej j=0?
    j=0; // Pytam ponieważ nie widzę nawiasów i ciekawi mnie jak to jest :)

    OdpowiedzUsuń
  7. j = 0 wykona się dopiero po zakończeniu całej pętli while :)

    Tak jak zauważyłeś, nie ma nawiasów więc w pętli będzie wykonywała się tylko jedna instrukcja - "bufor[] +=..."

    to tak jak z warunkami if, pętlami for itp.
    np. w takim przypadku:
    if(warunek)
    pierwsza_instrukcja();
    druga_instrukcja();
    if obejmie tylko pierwsza instrukcje, aby objąć obie musimy zapisać to tak:
    if(warunek)
    {
    pierwsza_instrukcja();
    druga_instrukcja();
    }

    OdpowiedzUsuń
    Odpowiedzi
    1. Ja niestety dalej tego nie rozymiem ;(

      Usuń
    2. A czego konkretnie?
      Napisz to postaramy się to wyjaśnić :)

      Usuń
    3. Ogolnie tego liczenia ASCII itd. Nie wiem do czego można to zastosowac

      Usuń
  8. Tzn. liczenia czy zastosowania tego?;)
    Liczenie - trzeba tu zrozumieć, że każdy nasz znak w C (char) to tak na prawdę liczba - 7-bitowy kod ASCII
    http://pl.wikipedia.org/wiki/ASCII

    A dalej, jako, że są to liczby to możemy wykonywać na nich wszelkie operacje arytmetyczne.
    Po co?
    A no np. możemy sprawdzić czy znak jaki gdzieś pobraliśmy jest cyfrą:
    if(c >=48 && c <= 57) { }
    analogicznie dla liter, małych, dużych.
    Możemy np. wykonać zamianę znaku z małej litery na dużą dodając do wartości 32 lub odwrotnie - odejmując,
    to z tych prostszych ćwiczeń a bardziej "hardcorowe" pokazał właśnie dzisiaj Mirek w swojej łamigłówce ;)

    OdpowiedzUsuń
  9. Ładnie ładnie wszystko idzie ;) ja tylko jeszcze czekam kto opisze co to jest za mechanizm

    "ABCD"[]

    z czym to można porównać? z czym to się że tak powiem je? ;) żeby i to było zrozumiałe dla początkujących.

    Bo obliczenia na znakach ASCII to jedna sprawa i tu Andrzej dobrze tłumaczy, ale ten mechanizm że tak go nazwę to ... no właśnie - co to jest ? czekam czekam bo tu jeszcze nie padło takie precyzyjne wyjaśnienie. Widać że są koledzy, którzy wiedzą o co w tym chodzi - ale jeszcze trzeba umieć wytłumaczyć tym którzy dopytują o szczegóły. A ja popatrzę jak to wam idzie ;) .... Na razie prym wiedzie w tym zakresie Andrzej Czerwoniec.

    OdpowiedzUsuń
  10. Serio niesamowite, że można zrobić, np. tak char bufor[sizeof(bufor)] = "eloziomie" i potem w wyswietleniu zrobic bufor[6 co wksaze nam na litere 'm'. Albo po prostu w wyswietleniu walnsc stringa char znak;
    znak = "eloziomie"[6] i wkszac na litere m. Sprytne, ale i logiczne, bo w koncu to nie nazwa ma znaczenie tylko sam bufor. Może jak znajde czas dziś w pracy to sobie przelicze to na spokojnie i podam solutiuons :).

    OdpowiedzUsuń
  11. Hmm, no jest to mechanizm odwoływania się do tablicy tak jak pisałem, tak jak bufor jest tablicą charów tak samo ten string nią jest więc odwołania jest identyczne:
    bufor[0]
    "ABCD"[0]
    czyż nie?

    OdpowiedzUsuń
    Odpowiedzi
    1. Dokładnie tak jak mówisz panie Andrzej ale ja spokojnie poczekam na "jeszcze coś ..." ;) no nie podpowiem na razie... A jeśli nikt tego nie opisze to za jakiś czas oczywiście podam o co mi chodziło.

      Ja przyznam, że gdy sam zobaczyłem pierwszy raz ten mechanizm to byłem w szoku, że tak w ogóle można ;) a tym bardziej że nie jest to jakieś popularne i wszędzie opisane czy też stosowane np w internecie.

      Usuń
    2. Ok ;)
      Nie mam pomysłu co chcesz dokładnie usłyszeć, jak wrócę do domu to pomyślę :D

      Dodam może tylko, że klamerki to skrótowy zapis operacji wyłuskiwania wartości spod wskaźnika
      str[k] == *(str + k)
      oraz, że struktura takiego stringa "ABCD" w pamięci jest identyczna jak tablicy charów (oczywiście przy tablicy definiowanej przez nas nie musimy mieć znaku końca stringu a przy "ABCD" będzie zawsze)

      nad resztą pomyślę po pracy ;)

      Usuń
  12. "ABCD" to tablica znaków a w klamerce [] jest indeks.
    można przypisać tablicę do zmiennej np:
    x = "ABCD"
    i wybierać elementy tablicy po przez indeks w klamerce:
    x[0]

    lub

    nie przypisywać zmiennej i bezpośrednio z tablicy wybierać element:
    "ABCD"[0]

    OdpowiedzUsuń
    Odpowiedzi
    1. Andrzej żebyś tylko źle mnie nie odebrał - mnie już chodzi tylko o drobną uwagę kosmetyczną, a wszystko co mówisz to oczywiście bardzo dobre wyjaśnienia i już widać na czacie na forum, czy w mailach które dostaję, że dzięki twoim wyjaśnieniom wiele osób zaskoczyło o co chodzi w tej łamigłówce. Dlatego mówię - jak na razie jesteś pretendentem do nagrody ;)

      Usuń
  13. Cudzysłów "" zwraca adres pod jakim jest początek napisu.:D?

    OdpowiedzUsuń
  14. To cały zapis po prostu działa jako wskaźnik ;)
    Taki sam myk jak z tablicami, sam zapis bufor to wskaźnik na pierwszy element (b[0]), tak "ABCD" to wskaźnik na 'A' w pamięci :)

    Rozumiem Mirku i nie ma problemu, ja też chce poznać wszelkie tajniki o których mogę nie wiedzieć :)

    OdpowiedzUsuń
  15. Kurka, a pomyśleć że zaczęło się od mojego projektu o RTC :D

    OdpowiedzUsuń
    Odpowiedzi
    1. Jak zobaczyłem pytania w twoim wątku o to co to za mechanizm, to przypomniałem sobie o nim i postanowiłem zbudować taką bombkę-zagadkę, dzięki której, przy okazji, myślę że wiele osób zrozumie dobrze ten mechanizm ;) i jak widać wychodzi.

      Usuń
    2. Mirku, chyba byś się nie obraził jakbym to spróbował wytłumaczyć ? :)

      Usuń
    3. No ale z jakiej racji miałbym się obrazić ? ;) że niby dlaczego ? ;)

      Usuń
  16. Ok, pobawię się tym trochę, zapoznam się z tym mechanizmem i postaram się to jak najjaśniej wyjaśnić :D

    OdpowiedzUsuń
  17. To ja jeszcze dodam ciekawe konstrukcje z tym związane :P
    jako, że taki nasz "ABCD" to wskaźnik na typ char, to zadziałają z nim różne śmieszne kombinacje np.:
    *"ABD"
    *("ABCD" + 3)
    mimo, że początkowo może to wyglądać dziwnie ;)

    OdpowiedzUsuń
  18. Zawartość tablicy == ATNEL :). Już mówię dlaczego tak się dzieje.
    Jest sobie linijka : bufor[0] += a1-"TCCR1A=(1<<COM1A0)"["AMD"[0] - 50];
    Indeks pierwszego stringa będzie równał się „AMD”[0], czyli A(65) - 50 = 15; Czyli w stringu
    TCCR1A=(1<<COM1A0) wskazuje on na literkę A, trzecią od końca :).
    Wracamy do pętli while. Wygląda ona tak : while((a1="TIMER1V"[j++])).
    Czyli ogólnie wykona się ona tyle razy ile jest liter w stringu „TIMER1V". Czyli wykona się ona 7 razy. I za każdym obiegiem zmienna a1 będzie przyjmować wartość aktualnej literki, czyli za pierwszym obiegiem będzie to T :). Wracamy do linijki bufor[0] += a1-"TCCR1A=(1<<COM1A0)"[15]. Pozwoliłem sobie ją skrócić o obliczanie indeksu, wstawiłem tam na stałe 15 aby było łatwiej Wam to interpretować :). Odejmuje ona kod aktualnego znaku od kodu litery A (65). Czyli za pierwszym obiegiem będzie to T(84) – A(65) = 19. Dodajemy to do elementu tablicy o indeksie 0. Czyli ten element równa się już 19. Za drugim obiegiem będzie to wyglądać tak : I(73) – A(65) = 8. Znów dodajemy to do zerowego elementu tablicy. W tym momencie równa się on 8 + 19 czyli 27. Lecimy już 3 obieg pętli. M(77) – A(65) = 12. Dodajemy to do zerowego elementu tablicy. 27+12 = 39. Lecimy 4 obieg. E(69) – A(65) = 4. Dodajemy do elementu tablicy. 39 + 4 = 43. 5 obieg pętli wygląda następująco : R(82) – A(65) = 17. Dodajemy do elementu tablicy. 43+17 = 60.
    Szósty obieg będzie troszeczkę innym obiegiem, ale zaraz wszystko się wyjaśni :). 1(49) – A(65) = -16. Dodajemy do tablicy. 60 + (-16) = 44. Siódmy obieg będzie ostatnim i to on wyjaśni całą sytuację :). V(86) – A(65) = 21. Dodajemy do elementu tablicy : 44 + 21 = 65. I co nam wyszło ? :) Kod 65, czyli literka A, która jest pierwszą literką słowa ATNEL :) Mam nadzieję że moje tłumaczenie wytłumaczyło ten kod do końca :).

    OdpowiedzUsuń
    Odpowiedzi
    1. A co z wyjaśnieniem konstrukcji "ABC"[0]?
      samo rozwiązanie opisałem tak samo dzisiaj rano ;)

      Usuń
    2. "ABC"[0] zwróci nam A, czyli zerowy element tego stringa. To tak samo jak byśmy zrobili na początku pliku tablicę : char String[] ={"ABC"}; i linijka String[0] zwróci nam to samo, czyli A :). "ABC"[1] zwróciłoby nam B, a ABC[2] zwróciłoby C :)

      Usuń
  19. Ja wiem, ale Mirek prosi o coś specjalnego w tym względzie :>

    OdpowiedzUsuń
    Odpowiedzi
    1. Hmm, no to nie wiem, może wyświetlanie na LCD ? :)
      for(uint8_t i = 0; i < sizeof("Tekst") - 1; i++)
      {
      LcdChar("Tekst"[i]);
      }

      Usuń
    2. O wyjaśnienie zasady działania ;]
      Cytuję: "ja tylko jeszcze czekam kto opisze co to jest za mechanizm "ABCD"[] "
      ;>

      Usuń
    3. Ale co tu wyjaśniać ? Próbowałeś te twoje dziwne kombinacje z *("ABCD" + 3) wrzucać w kompilator ? Nie wiem jak twój, ale mój się buntuje przeciwko temu ;)

      Usuń
    4. A co tu jest dziwnego?
      Jeśli działa zapis "ABC"[i] to taki też musi, jak wcześniej pisałem aaa[i] jest tożsame z zapisem *(aaa + i)

      Usuń
    5. Potwierdzam - dokładnie tak to działa również ;)

      Usuń
  20. Witam
    Chyba jeszcze nikt nie podał odpowiedzi na pierwsze pytanie, gdyż bufor[] to tablica znaków i zawiera 6 elementów a zmieści się w niej tylko napis ATNEL, ponieważ ostatnim elementem tablicy znaków jest zawsze znak końca łańcucha \0. Więc w przedstawianym pierwszym pytaniu bufor[] = ATNEL\0
    Na drugie pytanie już padła odpowiedz. Mirek chciał wprowadzić zagnać w ślepą uliczkę wpisując jako ciąg znaków dla mało wtajemniczonych zasłyszane TIMER ADC SPI ... tyle że znając kompilator (kolor niebieski) lub widząc "" chyba łatwo rozpoznać tablice znaków.
    Jako że "" to tablica znaków jednowymiarowa wiec wiadomo ze nawias kwadratowy zawiera indeks do tej tablicy znaków.
    I na koniec przypomnę że tablica znaków musi być zawsze większa o 1 element od długości przechowywanych danych w niej. Ten dodatkowy element to znak końca \0

    Jako, że nie mam konta na blogerze podpisze się loginem z forum Atnel
    Pozdrawiam
    OdeOn

    OdpowiedzUsuń
    Odpowiedzi
    1. Bufor[5] rzeczywiście będzie zerem ale tylko dlatego, że jest to tablica globalna i po prostu w C taką otrzyma wartość - nie ma to związku z tym, że jest to koniec stringu, ta wartość nie jest też nigdzie ustawiana w kodzie Mirka.

      Usuń
    2. No i sama w sobie tablica znaków nie musi być większa od ilości przechowywanych w niej znaków,
      char tab[5] = {'a', 't', 'n', 'e', 'l' };
      jest poprawnie zdefiniowana :>
      Kwestia jest tylko tego, że w rzeczywistości tak zdefiniowana tablica:
      char tab[] = "atnel";
      będzie mieć w rzeczywistości rozmiar 6 a nie 5, jak poprzednio :)

      Usuń
    3. Tablica znaków rożni się od np. tablica liczbowej właśnie tym że zawiera ten ostatni znak \0 inaczej (null) . W jezyku C nie używamy stringów bo ich nie ma są tablice znaków.
      OdeOn

      Usuń
    4. Utwórz w takim razie tablicę jaką podałem w pierwszym przykładzie, tylko nie podawaj jej wielkości:
      char tab[] = {'a', 't', 'n', 'e', 'l'};
      a potem poproś funkcję sizeof o wypisanie jej rozmiaru, przekonasz się ;)

      Usuń
    5. Mirek pytając o "ABCD"[] prawdopodobnie chciał nakierować na wskaźniki bo taki napis to część pamięci przydzielonej przez kompilator gdzie pojedyncze znaki to kolejne bajty pamięci.
      Tablica znaków sama w sobie może przechorowywać o 1 element mniej niż jej wielkość. Przy deklaracji char bufor[6] można zapisać tylko tekst 5 literowy, odwołanie do 6 czy 7 czy 10 elementu tej tablicy jest możliwe ale może powodować nadpisywanie innych zmiennych i w konsekwencji złą nieprzewidywalną pracę programu.
      OdeOn

      Usuń
  21. Ależ co Ty mówisz, tak jak pisałem, można bez obaw zadeklarować tablicę jaką podałem (rozmiar 5 i 5 elementów):
    char tab[5] = {'a', 't', 'n', 'e', 'l'};
    i bez problemu odwoływać się do każdego jej elementu.

    Odwoływanie się poza rozmiar tablicy to zupełnie inna kwestia i wtedy oczywiście problemy mogą się pojawić bo będziemy szperać po pamięci.

    Jedyne co może przynieść problemy przy mojej tablicy, to próba wykorzystania jej np. tak:
    printf(&LCD, "%s", tab);
    bo nie dajemy informacji o końcu naszego napisu i printf wypisze nam wszystko od początku naszego wyrazu aż do napotkania wartości 0 w pamięci ;] .

    OdpowiedzUsuń
  22. PANOWIE na końcu artykułu OPISAŁEM o co mi chodziło tzn jaką ja mam wizję na wyjaśnienie. Jeśli gdzieś popełniłem błąd to proszę mi zwrócić uwagę.

    OdpowiedzUsuń
    Odpowiedzi
    1. To ja mam dwie sprawy:D
      Andrzej Czerwoniec, nie Czerwoński, ale przeżyje to:P
      i pytanie, co rozumiesz pod pojęciem "wersji in-line tablicy"?
      chodzi po prostu o wstawkę czy jakieś "głębsze" znaczenie?

      Usuń
    2. Przede wszystkim bardzo przepraszam za błąd w nazwisku, już poprawiłem.

      Żadnego głębszego znaczenia - już wspominałem że chodzi o jakąś tam kosmetykę bo wszystko pięknie wyklarowałeś w swoich odpowiedziach a nawet więcej ;)

      Wersja in-line tablicy, czyli zdefiniowana w miejscu wywołania. Czy to na pewno dobre określenie też nie wiem. Sam bym chciał zobaczyć coś na ten temat w jakimś źródle.

      Usuń
    3. Rozumiem ;)
      pytałem właśnie ze względu na to, że nigdy nie słyszałem takiego określenia w tym kontekście a i źródła żadnego niestety nie znalazłem ;)

      Usuń
  23. Czas na rozstrzygnięcie KONKURSU ;)

    Niewątpliwie pierwszą osobą, która podała prawidłowe rozwiązanie pierwszej części zagadki ale bardzo skrótowe wyjaśnienie reszty - był kolega: Morastiew

    To jednak moim zdaniem na główną nagrodę zasługuje kolega Andrzej Czerwoniec z uwagi na absolutnie najbardziej wyczerpujące odpowiedzi na każdą część zagadki na nawet lekko ponad plan ;) Dlatego Andrzej jeśli jesteś zainteresowany - zgłoś się do mnie na maila biuro@atnel.pl w sprawie ustalenia odbioru nagrody.

    Pomimo to aby być całkowicie sprawiedliwym uważam, że trzeba ustalić także drugą nagrodę dla kolegi: Morastiew z uwagi na najszybszą reakcję i prawidłową ;) W związku z powyższym proponuję koledze możliwość swobodnego wyboru jednej z dwóch książek a także licencję na program MkAvrCalculator. Dlatego także proszę o kontakt na biuro@atnel.pl w tej sprawie ;)

    OdpowiedzUsuń
  24. To gratuluje zwyciezcom, może kiedyś wreszcie i mi się uda coś wygrać, w końcu lubi się rozkmine i to z wysokiej półki.
    paul dirac

    OdpowiedzUsuń
    Odpowiedzi
    1. Jeśli Mirek wyraziłby zgodę to może już niedługo będzie kolejna szansa na wygranie czegoś i gwarantuję, że również byłaby, jak mówisz, "z wysokiej półki" :)

      Usuń
    2. Andrzej napisz mi na maila co masz za pomysł ;)

      Usuń
    3. Powinien już u Ciebie być tylko na mailu mirekk36@o2.pl bo chciałem się bezpośrednio do Ciebie zwrócić, nie doszedł?

      Usuń