Skocz do zawartości

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

Gość Qn`ik

Programowanie

Polecane posty

Reavenn >> Generalnie widze dwie drogi:

Najpierw naucz sie C++. Symfonia C++ pana J.Grebosza. Potem tego samego autora Pasja C++. Kiedy juz opanujesz ten jezyk tak ze na pierwszy rzut oka bedziesz wiedzial co to jest i do czego sluzy:

const float (*GetData)(const float const * arg);

Wtedy warto zainteresowac sie asemblerem, a nastepnie Java.

Druga droga zaczyna sie od Javy. Potem C++.Na koncu asembler.

Oczywiscie istnieje wiele innych jezykow, ktore warto poznac: visual basic, python, perl, ruby, php itd. Jednak sa one, ze tak powiem "mniej istotne".

Fora zadnego Ci nie polece. Po pierwsze ksiazki sa o wiele lepsze do nauki. Po drugie sa google.

Link do komentarza
Udostępnij na innych stronach

Mam do napisania prosty program w C. Program służy do szyfrowania tekstu wpisanego z klawiatury. Po prostu zamienia litery np. ‘a’ na ‘g’. Wszystko ładnie działa jeżeli zostanie wprowadzony ciąg znaków bez spacji, bo gdy kompilator napotka spację to wtedy kończy w tym miejscu pracę. Czy wiek ktoś jaka jest tego przyczyna i jak można ominąć ten problem?

Link do komentarza
Udostępnij na innych stronach

Wszystko ładnie działa jeżeli zostanie wprowadzony ciąg znaków bez spacji, bo gdy kompilator napotka spację to wtedy kończy w tym miejscu pracę. Czy wiek ktoś jaka jest tego przyczyna i jak można ominąć ten problem?
Kompilator C konczy prace po napotkaniu spacji :?: No bez jaj.

Prawdopodobnie cos dziwnego wstawiles w switch'u w default, ale daj kod to Ci powiem napewno.

Link do komentarza
Udostępnij na innych stronach

Program ma być napisany z użyciem wskaźników, jak na razie wygląda to tak:

#include<stdio.h>



int x;



void wczytaj_metoda_wsk (char *);

void szyfruj_metoda_wsk (char *);



int main ()



{

char tab [81];

char *wsk=&tab[0];



wczytaj_metoda_wsk (wsk);

szyfruj_metoda_wsk (wsk);

printf("Tekst po zaszyfrowaniu: %sn", wsk);



return 0;

}



void wczytaj_metoda_wsk (char *wsk)



{

printf("Wpisz tekst: ");

scanf("%s",wsk);

}





void szyfruj_metoda_wsk (char *wsk)



{

for (x=0;x<81;x++,wsk++)

    {

    if (*wsk=='a' || *wsk=='A') *wsk='G';

    else if (*wsk=='g' || *wsk=='G') *wsk='A';



    else if (*wsk=='d' || *wsk=='D') *wsk='E';

    else if (*wsk=='e' || *wsk=='E') *wsk='D';



    else if (*wsk=='r' || *wsk=='R') *wsk='Y';

    else if (*wsk=='y' || *wsk=='Y') *wsk='R';



    else if (*wsk=='p' || *wsk=='P') *wsk='O';

    else if (*wsk=='o' || *wsk=='O') *wsk='P';



    else if (*wsk=='l' || *wsk=='L') *wsk='U';

    else if (*wsk=='u' || *wsk=='U') *wsk='L';



    else if (*wsk=='k' || *wsk=='K') *wsk='I';

    else if (*wsk=='i' || *wsk=='I') *wsk='K';

    }

}

Link do komentarza
Udostępnij na innych stronach

Troszke sie popastwie nad Twoim kodem :)

int x;

Nie uzywaj zmiennych globalnych. Bo to bardzo nie ladny zwyczaj. Zwlaszcza ze tak naprawde uzywasz jej lokalnie tylko w jednej funkcji.

void wczytaj_metoda_wsk (char *);

void szyfruj_metoda_wsk (char *);

Nie rob szumu informacyjnego, kazdy widzi co funkcja przyjmuje za argument i nie ma potrzeby umieszczac tego w jej nazwie. Poza tym to z cala pewnoscia nie sa metody, tylko procedury. Uzywaj nazw ktore opisuja co dana rzecz robi, a nie czym jest. No chyba, ze Ci ktos narzucil taka idiotyczna konwencje.

int main ()

{

char tab [81];

char *wsk=&tab[0];

char *wsk = tab; o wiele czytelniej. Poza tym zmienna wsk jest Ci tu do niczego nie potrzebna. tab jest wskaznikiem :)

void szyfruj_metoda_wsk (char *wsk)

{

for (x=0;x<81;x++,wsk++)

    {

    if (*wsk=='a' || *wsk=='A') *wsk='G';

    else if ...

...

}

W takich sytuacjach uzywa sie switch'a. Petla for tez wydaje mi sie kiepskim pomyslem.

void szyfruj_metoda_wsk(char *wsk)

{

    while (0 != *wsk)

    {

        switch (*wsk)

        {

        case 'a':

            *wsk = 'A';

            break;

        case 'g':

            *wsk = 'G';

            break;

        

        ...

            

        default: break;

        ++wsk;

    }

}

W c/c++ lancuchy znakowe to tzw. null terminated string. Koncza sie zerem, dlatego while (0 != *wsk) wykona sie dla kazdego znaku w pobranym stringu. 0 w stringu znajduje sie zawsze za ostatnim znakiem. Jesli podasz scanf taki tekst: "test" to w tab znajdzie sie cos takiego {'t' 'e' 's' 't' '0' } a pozostale 76 znakow to jakies smieci. Dlatego nie for, a while :)

Switch jest czytelniejszy niz if else if else if else if itd.

Twoj problem polega na tym, ze scanf wczytuje tekst do pierwszego bialego znaku. Sprobuj uzyc gets. To powinno rozwiazac problem.

Link do komentarza
Udostępnij na innych stronach

Dzięki za cenne wskazówki, użycie gets pomogło.

Nie rob szumu informacyjnego, kazdy widzi co funkcja przyjmuje za argument i nie ma potrzeby umieszczac tego w jej nazwie.

Nazwałem tak funkcje ponieważ program ma być wykonany metodą tablicową i wskaźnikową. Te nazwy wydawały mi się logiczne.

Teraz wygląda to tak:

#include<stdio.h>



void wczytaj (char *);

void szyfruj (char *);



int main ()



{

char tab [81];



printf("Metoda wskaznikowa:n");

wczytaj (tab);

szyfruj (tab);

printf("Tekst po zaszyfrowaniu: %sn", tab);



return 0;

}



void wczytaj (char *wsk)



{

printf("Wpisz tekst: ");

gets (wsk);

}





void szyfruj (char *wsk)



{

while (*wsk!=0)

{

    switch (*wsk)

    {

      case 'g':

      case 'G':

          *wsk = 'A';

          break;

      case 'a':

      case 'A':

          *wsk = 'G';

          break;

      …  

         default: break;

    }

    wsk++;

}

}

Rzeczywiście lepiej użyć tutaj pętli while, ale czy aby na pewno switch jest w tym wypadku czytelniejszy od if else? Patrząc na ten kod mam co do tego wątpliwości, w tym wypadku jest to chyba bez różnicy.

Link do komentarza
Udostępnij na innych stronach

Nazwałem tak funkcje ponieważ program ma być wykonany metodą tablicową i wskaźnikową. Te nazwy wydawały mi się logiczne.
Bardzo podobaja mi sie te okreslenia metoda tablicowa, metoda wskaznikowa :) Sa kompletnie nie na miejscu :)

Tablica i wskaznik w c/c++ to to samo.

Mianem metody zwyklo sie okreslac realizacje funkcji interfejsu/abstrakcji (java/c++). Wzielo sie to pewnie z faktu ze metod realizacji jakiejs funkcji jest wiele. Czyli jesli przedefiniowujemy funkcje wirtualne przodka w dziedziczacej klasie to mamy metody. Te Twoje to procedury. Pewnie wiekszosc stwierdzilaby, ze szukam dziury w calym, ale dla ludzi ktorzy czuja roznice, takie haslo jest mylace. Ty mowisz metoda, a ktos zaczyna myslec o dziedziczeniu, polimorfizmie itd. W efekcie wasze toki myslowe przebiegaja zupelnie innymi torami i komunikacja staje sie niezwykle utrudniona.

Switch'a poprostu latwiej sie czyta niz takie zagniezdzone else if'y. Switch ma tylko jeden poziom, sprawa jest oczywista. W przypadku if'ow moze byc wiecej niz jeden poziom zagniezdzenia. Konieczne jest przeanalizowanie linijki po linijce. Oczywiscie odpowiednie formatowanie potrafi to bardzo ulatwic, ale nigdy do konca nie wiadomo.

Link do komentarza
Udostępnij na innych stronach

Tablica i wskaznik w c/c++ to to samo.

No nie do końca. Nazwa tablicy to wskaźnik (adres) na początek tablicy i tylko tyle.

Te Twoje to procedury.

Tu też się nie zgodze. W C nie ma procedur, są tylko funkcje. I będę się przy tym upierał, patrząc na to, co napisał Woody.

A metody, to po prostu funkcje w klasie.

Woody -> Dodawaj sobie choćby zdawkowe komentarze, bo jak spojrzysz na kod za rok, to nie będziesz wiedział co i jak= stracisz czas na zapoznawanie się z kodem, zamiast zobaczyć i wiedzieć :-) Troszkę może przesadzam, ale jest to istotne przy większych programach.

Link do komentarza
Udostępnij na innych stronach

No nie do końca. Nazwa tablicy to wskaźnik (adres) na początek tablicy i tylko tyle.
Dobrze, tablica to staly wskaznik na zaalokowany fragment pamieci. I kompilator jest odpowiedzialny za jego zwolnienie. Piszac, ze tablica i wskaznik to to samo, mialem na mysli przedewszystkim fakt, ze na obu mozna wykorzystac te operatory: * []. Co powoduje, ze korzystanie z obu jest takie samo. Zreszta jak mialoby byc inne skoro jedno i drugie to wskaznik.
Tu też się nie zgodze. W C nie ma procedur, są tylko funkcje.
Moglbys to rozwinac, bo za chiny nie rozumiem jak udalo Ci sie dojsc do takiego wniosku. Funkcja zwraca wartosc, a procedura nie. Jezeli masz void wczytaj i void szyfruj, to to z cala pewnoscia sa procedury. Fakt, ze roznica w kodzie jest niewielka, raptem 3 instrukcje (dwie instrukcje na zwrocenie wartosci i jedna na jej odebranie), ale jest.

Co do komentarzy, to nie ma co namawiac ludzi do ich robienia. Nikt ich nie bedzie robil dopoki, nie doswiadczy jak fajnie byloby gdyby takie cos stworzyl. Poza tym robienie komentarzy wcale nie jest takie proste, a poleganie na tworzonych adhoc czesto pogarsza sytuacje jeszcze bardziej. Dlatego najwazniejsze moim zdaniem jest dbanie o to aby kod byl tak czytelny jak to mozliwe i samokomentujacy (uzywac znaczacych nazw). Komentowac nalezy tylko jakies bardzo skomplikowane miejsca i naglowki funckji. Dlatego zamiast

fun(char *a, const char *b) {

//kopiowanie

while (*a++=*b++); }

strcpy(char *dest, const char *src)

{

   while (0 != src)

   {

      *dest = *src;

      dest++;

      src++;

   }

}

Kompilator i tak to zoptymalizuje do tego samego.

Link do komentarza
Udostępnij na innych stronach

Dobrze, tablica to staly wskaznik na zaalokowany fragment pamieci.

No właśnie nie... Robisz

int tab[5];

tab[3]=7;

i jest ok. A jak zrobisz

int *wsk;

wsk[3]=7;

to program się spytnie, bo nie zaalokowałeś pamięci, dobrze o tym wiesz.

Jak dla mnie wskaźnik wskazuje na początek bloku w pamięci, a tablica jest tym blokiem pamięci, a nazwa tablicy jest wskaźnikiem na początek bloku.

Moglbys to rozwinac, bo za chiny nie rozumiem jak udalo Ci sie dojsc do takiego wniosku.

Cytując za książką "Język ANSI C", strona 300: "Funkcja może zwracać wartość typu arytmetycznego, strukturę, unię, wskaźnik lub void, natomiast nie może zwrócić funkcji ani tablicy". Z resztą rzuć w google "procedury w c" i znajdziesz parę stron mówiących to samo co ja.

A co do przykładowego kodu, to zwięzły zapis bardziej mi się podoba i jest nawet bardziej czytelny niż ten rozwinięty. Mnie takiego zapisu uczyli, więc rzut oka mówi mi, co to jest. Poza tym zasugerowałem komentarze z zaznaczeniem, że szczególnie przydają się przy większych programach. Osobiście więcej mi powie tekst "Funkcja robi xyz, pobiera coś i coś2, a zwraca ble" niż dwa ekrany dobrze wyglądającego kodu, bo dzięki komentarzowi w ogóle nie muszę zagłębiać się w kod i go analizować.

Link do komentarza
Udostępnij na innych stronach

Dobrze, tablica to staly wskaznik na zaalokowany fragment pamieci.

No właśnie nie... Robisz

No jak nie, jak tak :) A jak napisze
char *wsk = new char[8];

To wsk bedzie nazwa tablicy, czy wskaznikiem :?: No i czym bedzie te zaalokowane 8 charow, tablica :?: A kiedy zrobimy

double *wsk2 = (double *) wsk;

, to nadal nia bedzie, czy moze zmieni sie w liczbe zmiennoprzecinkowa :?: A gdybysmy nagle postanowili zrobic takie cudo

void (*wsk3)(int &a, const char *b) = wsk;

To czym bylyby wsk3 i nasza liczba zmiennoprzecinkowa :?: A czy po

double **wsk4 = wsk

nasze 8 bajtow niestanie sie wskaznikiem do liczby zmiennoprzecinkowej :?: (ktory notabene powinien miec 4 bajty) Czym jest wiec tabela 8 znakow i czym rozni sie od wskaznika do doubla :?:

No niby pisza to co pisza, ale jednak jest roznica. Bo jak nic nie zwracasz, to masz 3 instrukcje mniej. Chocbys wlazl pod stol, stanal na glowie i zaczal podskakiwac niczym kuleczka pingpongowa wydajac z siebie dzwiek gumowej kaczuszki nie przekonasz mnie, ze to nic nie znaczacy drobiazg. Z powodu tego drobiazgu pozostane przy rozroznianiu tych nazw i bede namawial do tego innych. Bo inaczej to tak jakbym niezauwazal roznicy miedzy dachowcem i tygrysem.

zwięzły zapis bardziej mi się podoba i jest nawet bardziej czytelny niż ten rozwinięty.
Hm, to moze cos takiego bedzie bardziej wymowne
*a[b[c].second[d]->e(f,g->h[i])] += j().().()->data;

A deklaracje zmiennych sa kilkadziesiat lini wyzej, bynajmniej nie na samym poczatku pliku. Oczywiscie typedef'y dla ich typow sa gdzies w pliku naglowkowym, wlaczanym przez inny plik naglowkowy. I nawet najlepsze IDE nie jest w stanie Ci podpowiedziec z czym masz doczynienia. Proba skomentowania tego cuda zajmie wiecej czasu i miejsca niz cala funkcja, w ktorej sie znajduje. Dlatego odpowiednie rozbicie kodu i dobrze dobrane nazwy sa tak istotne.

Oczywiscie, co juz napisalem wczesniej, zgadzam sie, ze funkcje nalezy komentowac zaraz obok jej naglowka. Jednak nawet najlepszy opis, nie pozwoli od zaraz zabrac sie konserwacje funkcji. W duzych projektach, bo przeciez o takich mowimy, ja pisze kod, jakis japonczyk z niego korzysta, a Tobie po kilku latach przypada w udziale poprawienie moich bledow, ew. aktualizacje mojego kodu. Wtedy bedziesz mnie blogoslawil za nie stosowanie takich perelek, a przeklinal za kazdy skrot. Jedna z miar jakosci kodu jest wtfpm, czyli ilosc ocb na minute podczas rewizji kodu (siadaja 3 osoby z zespolu i czytaja Twoj kod). Im mniej tym lepiej.

Link do komentarza
Udostępnij na innych stronach

Trochę poczytałem i wnioski:

Pomiędzy wskaźnikiem a tablicą jest różnica.

Spróbuj zrobić

int tab[10];

tab++;

Nie przejdzie. Ze wskaźnikiem się uda.

Wskaźnik jest zmienną, nazwa tablicy stałą.

No niby pisza to co pisza (...)

Heh. Pozwolisz, że uznam autorów książki za większy autorytet od Ciebie w dziedzinie programowania i zostanę przy swoim.

O Twoim wymyślnym kodzie: odniosłem się do konkretnego, krótkiego przykładu, gdzie dodatkowo od razu widać co jest czym. Poza tym jest to konstrukcja, którą chyba wszystkich uczą.

Jeśli ja napiszę

*a++=*b++;

a idąc za Twoim przykładem "deklaracje zmiennych sa kilkadziesiat lini wyzej, bynajmniej nie na samym poczatku pliku. Oczywiscie typedef'y dla ich typow sa gdzies w pliku naglowkowym, wlaczanym przez inny plik naglowkowy", to o moim kawałku będziesz mógł powiedzieć równie dużo co ja o Twoim. Ja kopiuję coś spod jednego adresu pod drugi, a Ty wartość spod jakiegoś adresu zwiększasz o coś.

Link do komentarza
Udostępnij na innych stronach

Trochę poczytałem i wnioski:

Pomiędzy wskaźnikiem a tablicą jest różnica.

Spróbuj zrobić

int tab[10];

tab++;

Nie przejdzie. Ze wskaźnikiem się uda.

Wskaźnik jest zmienną, nazwa tablicy stałą.

Juhu :!: Zmierzamy do celu :) Tak jak napisalem wczesniej, typowa tablica zadeklarowana w typowy sposob
char tab[8];

Jest stalym wskaznikiem. W gruncie rzeczy to jest rownowazna

char const * tab = new char[8];

...

delete tab;

Ma tylko jedna przewage, moze zostac odlozona na stosie, jako zmienna lokalna funkcji, dzieki czemu unikamy alokacji i dealokacji pamieci. Czy tak sie dzieje nie wiem, az taki madry nie jestem, ale to teoretycznie mozliwe.

Heh. Pozwolisz, że uznam autorów książki za większy autorytet od Ciebie w dziedzinie programowania i zostanę przy swoim.
Nie wierz we wszystko co napisane :) Przykladowy kod. Bardzo prosty, kod c wraz z disassemblerem. Eclipse, cdt, gcc. Istotne sa linijki zaznaczylem. To one stanowia roznice pomiedzy jednym i drugim. W tym przykladzie sa tylko dwie, bo zwracamy wartosc, gdyby to byla referencja to powinno byc o jedna wiecej, czyli 3.

int main(int argc, char **argv) {

0x080483fe <main>:    lea   0x4(%esp),%ecx

0x08048402 <main+4>:  and   $0xfffffff0,%esp

0x08048405 <main+7>:  pushl 0xfffffffc(%ecx)

0x08048408 <main+10>: push  %ebp

0x08048409 <main+11>: mov   %esp,%ebp

0x0804840b <main+13>: push  %ecx

0x0804840c <main+14>: sub   $0x18,%esp

    proc(5,6);

0x0804840f <main+17>: movl  $0x6,0x4(%esp)

0x08048417 <main+25>: movl  $0x5,(%esp)

0x0804841e <main+32>: call  0x80483e4 <_Z4procii>

    int c = fun(5,6);

0x08048423 <main+37>: movl  $0x6,0x4(%esp)

0x0804842b <main+45>: movl  $0x5,(%esp)

0x08048432 <main+52>: call  0x80483f0 <_Z3funii>

0x08048437 <main+57>: mov   %eax,0xfffffff8(%ebp)  <***** tutaj

    return 0;

0x0804843a <main+60>: mov   $0x0,%eax

}

void proc(int a, int b)

0x080483e4 <_Z4procii>:    push %ebp

0x080483e5 <_Z4procii+1>:  mov  %esp,%ebp

{

    a += b;

0x080483e7 <_Z4procii+3>:  mov  0xc(%ebp),%eax

0x080483ea <_Z4procii+6>:  add  %eax,0x8(%ebp)

    return;

}

0x080483ed <_Z4procii+9>:  pop  %ebp

0x080483ee <_Z4procii+10>: ret

int fun(int a, int b)

0x080483f0 <_Z3funii>:    push %ebp

0x080483f1 <_Z3funii+1>:  mov  %esp,%ebp

{

    a += b;

0x080483f3 <_Z3funii+3>:  mov  0xc(%ebp),%eax

0x080483f6 <_Z3funii+6>:  add  %eax,0x8(%ebp)

    return a;

0x080483f9 <_Z3funii+9>:  mov  0x8(%ebp),%eax  <***** tutaj

}

0x080483fc <_Z3funii+12>: pop  %ebp

0x080483fd <_Z3funii+13>: ret

to o moim kawałku będziesz mógł powiedzieć równie dużo co ja o Twoim. Ja kopiuję coś spod jednego adresu pod drugi, a Ty wartość spod jakiegoś adresu zwiększasz o coś.
Dokladnie, jest kompletnie nie czytelny. Poza tym co robimy, bo akurat operator jest tu oczywisty (a wcale nie musi tak byc), nie widac nic. Taki byl cel mojego przykladu. Rozbicie go na poszczegolne operacje i wprowadzenie odpowiednich nazw znacznie ulatwiloby Ci jego analize. Moglbys sie na przyklad dowiedziec, ze nie zwiekszamy wartosci. Stringi maja przedefiniowany +=. Dobre nazwy i przejzysty kod, to podstawa :)
Link do komentarza
Udostępnij na innych stronach

Ma tylko jedna przewage, moze zostac odlozona na stosie, jako zmienna lokalna funkcji, dzieki czemu unikamy alokacji i dealokacji pamieci.

Czyli potwierdzasz, że różnica występuje. C.N.D. :P

Nie wierz we wszystko co napisane :)

Tyle że my się tu o nazewnictwo spieramy, a nie o realizację. Nawet bez listingu ja Ci wierzę, że jest jak mówisz. Chodzi mi o to, że autorzy mówią "wszystko to funkcje, nie ma procedur". Więc niech wszystko się nazywa funkcją, nawet jeśli w istocie działa jak procedura.

Dokladnie, jest kompletnie nie czytelny.(...)

Tyle że w odniesieniu do Twojego pierwszego przykładu

fun(char *a, const char *b) { 

while (*a++=*b++); }

ta wersja mi bardziej odpowiada. Jest mała, zgrabna i nie ma tgo o czym pisałeś - wszystkie typy itd są widoczne. No ale uznajmy, że to kwestia gustu :-)

Link do komentarza
Udostępnij na innych stronach

Czyli potwierdzasz, że różnica występuje. C.N.D. :P
Powiedzialem tylko, ze to teoretycznie mozliwe. Nie wiem, czy jakikolwiek kompilator tak robi. W praktyce mogloby sie okazac to niebezpieczne, poniewaz dosyc latwo byolby uzyskac ogromny stos.

Poza tym tablice w c/c++ nie istnieja. Nie da sie napisac

char[8] tab

Nawet operator [x] jest tylko ladniejsza forma zapisu *(wsk + x). Istnieje tylko interpretacja pamieci jako ulozone jeden za drugim elementy tablicy danego typu.

Tyle że my się tu o nazewnictwo spieramy, a nie o realizację.
Jesli cos wyglada jak zebra, pachnie jak zebra, zachowuje sie jak zebra i ma zebrowate dzieci, to nie mowisz, ze to wieloryb. Czemu, wiec cos co dziala jak procedura nazywac funkcja :?:
Link do komentarza
Udostępnij na innych stronach

Poza tym tablice w c/c++ nie istnieja.

I w tym miejscu uznaję, że w zasadzie dalsza dyskusja nie ma sensu. Po pierwsze dlatego, że nie jesteś w stanie mnie przekonać, a ja Ciebie. A po drugie zaraz by wyszło, że skoro tablice nie istnieją, to język c i c++ tak na prawdę też nie istnieje, bo w sumie to taka nakładka na asembler.

Czemu, wiec cos co dziala jak procedura nazywac funkcja :?:

Bo z wyjątkiem Ciebie, nie spotkałem nikogo, kto twierdziłby to samo co Ty.

Link do komentarza
Udostępnij na innych stronach

Poza tym tablice w c/c++ nie istnieja.
I w tym miejscu uznaję, że w zasadzie dalsza dyskusja nie ma sensu. Po pierwsze dlatego, że nie jesteś w stanie mnie przekonać, a ja Ciebie. A po drugie zaraz by wyszło, że skoro tablice nie istnieją, to język c i c++ tak na prawdę też nie istnieje, bo w sumie to taka nakładka na asembler.
A czy tak wlasnie nie jest :?: Ostatecznie wszystkie jezyki sa tylko taka nakladka. Kwestia tylko jak bardzo Cie ograniczaja i co daja w zamian.

Ale nie w tym rzecz. W takiej Javie na przyklad mozna napisac

char[8] tab;

Bo w Javie tablice sa typem, a w C/C++ nie. STL dostarcza Vector'ow, ktore sa odpowiednikiem tablic Java. Vector jest typem. Vector nawet w przyblizeniu nie jest wskaznikiem.

Link do komentarza
Udostępnij na innych stronach

Mam pytanie odnośnie funkcji goto w języku C. Podobno powinno się jak najbardziej ograniczać użycie tej funkcji, gdyż mogą pojawić się problemy podczas kompilacji. Miałem do napisania program do grania w kółko i krzyżyk. Jeżeli gracz wpisał błędne pole do wstawienia krzyżyka to funkcja goto dokonywała skoku, dzięki czemu gracz mógł ponownie wpisać odpowiednie pole. Nie stwierdziłem żadnych problemów w działaniu programu, ale mam pytanie w jaki sposób można ominąć tutaj użycie goto i czy jest to w ogóle potrzebne?

Link do komentarza
Udostępnij na innych stronach

Pamiętam, że na pierwszym semestrze, prowadzący pokazał nam wykres obrazujący wiedzę programisty w zależności od ilości instrukcji goto:

69612.jpeg

Funkcja nie powoduje problemów z kompilacją. Chodzi o to, że jej używanie znacznie zaciemnia kod oraz może prowadzić do nieprzewidywanego działania programu, dlateog funkcji goto powinno się w zasadzie nie używać.

Spokojnie można ją zastąpić za pomocą pętli, np. while.

Po prostu całe pytanie o pole oraz testowanie wprowadzonego znaku robisz w pętli, a jeśli test wyjdzie niepomyślnie (wpisano zły znak), to program wróci na początek pętli i znów spyta o znak. Dodatkowo możesz wywoływać jakąś funkcję wyświetlającą aktualny stan planszy itd.

Gdybyś chciał ułatwić sobie życie, mogę Ci podrzucić kawalek kodu opartego na WinApi, który realizauje funkcję gotoxy(), czyli ustawienie kursora na wybraną pozycję w okienku konsoli. Może to być bardzo przydatne, szczególnie jeśli zależy Ci na wyglądzie programu.

Kiedyś też pisałem konsolowe kółko i krzyżyk, tyle że w pascalu, chyba najwięcej zabawy miałem ze sprawdzaniem, czy nastąpiła wygrana (bo program pozwalał na wybór wielkości planszy).

Link do komentarza
Udostępnij na innych stronach

Rzeczywiście da się tutaj w prosty sposób ominąć goto. Po prostu ta funkcja wydaje się prostym i logicznym rozwiązaniem, no ale patrząc na ten wykres to nie mam zamiaru się do niej przyzwyczajać :D.

Na razie napisałem program ze standardowym rozmiarem planszy 3x3, w tym wypadku jest tylko osiem możliwości wygranych, więc nie ma zbyt dużego problemu ze sprawdzaniem. Więcej zabawy miałem z tym, aby grając z komputerem, ten nie wpisywał kółka w pierwsze wolne miejsce, ale w takie, które da mu możliwość wygranej lub zablokuje pole, dzięki któremu gracz mógłby wygrać.

Link do komentarza
Udostępnij na innych stronach

Widzę, że zamierzasz robić sztuczną inteligencję - ja nie byłem taki ambitny i zrobiłem grę dla dwóch graczy:-)

Natomiast jeśli Ci zależy, to na google znajdziesz porady, jak zrobić SI dla kółka i krzyżyka - po co wyważać otwarte drzwi :-).

Link do komentarza
Udostępnij na innych stronach

Wszedzie tam, gdzie goto, wydaje sie najrozsadniejszym rozwiazaniem, warto zastanowic sie nad break i continue.

Oba slowka powoduja przerwanie petli. Z tym, ze break konczy petle definitywnie, a continue powoduje zakonczenie aktualnego przebiegu.

Link do komentarza
Udostępnij na innych stronach

Gość
Temat jest zablokowany i nie można w nim pisać.


  • Kto przegląda   0 użytkowników

    • Brak zalogowanych użytkowników przeglądających tę stronę.

×
×
  • Utwórz nowe...