[C++] Problem z szyfrogramem używającym XOR

Witam :slight_smile:

Tak z nudów chciałem napisać króciutki szyfrogram, który pobiera SZYFR oraz CIĄG do zaszyfrowania. Funkcja szyfrowanie zwraca wskaźnik na zaszyfrowany ciąg. Nie wiem czemu (może popełniłem błąd z tym wskaźnikiem, może powinienem był inaczej to rozwiązać?), cokolwiek się nie wpisze do szyfru i ciągu, zawsze pojawiać się będzie to samo.

Oto kod programu:

#include 

#include 


using namespace std;


char *szyfrowanie(char szyfr[], char ciag[])

{

     char szyfrowany[20];

     for(int i=0, j=0; i
             {

                  if(szyfr[j]=='0')

                                   {

                                       j=0;

                                       szyfrowany[i]=(ciag[i]^szyfr[j]);

                                   }

                  else

                                   szyfrowany[i]=(ciag[i]^szyfr[j]);

             }

     return szyfrowany;

}


int main(int argc, char *argv[])

{

    char szyfr[10]={0};

    char ciag[20];


    cout<<"Podaj kod szyfrujacy: ";

    cin.getline(szyfr, 10);

    cout<
    cin.getline(ciag, 20);


    cout<

    system("PAUSE");

    return EXIT_SUCCESS;

}

Pozdrawiam,

Aranha

EDIT:

Zrobiłem już kiedyś ten program inaczej (funkcja nie zajmowała się całym ciągiem, tylko pojedynczymi znakami), jednak teraz chciałem utrudnić funkcję, a jak najprzejrzyściej napisać main’a.

Pisałeś kiedykolwiek coś w c++?

...

{

     char szyfrowany[20];

     ...

     return szyfrowany;

}

...

Tworzysz lokalna zmienną, a na koniec zwracasz wskaźnik na nią. W momencie zakończenia wywołania funkcji wszystkie zmienne lokalne są niszczone razem ze stosem. Użyj alokacji na stercie. Alternatywnie możesz przekazać wskaźnik, na lokalną tablicę widzianą w zasięgu maina.

Mogłeś sobie podarować pytanie

  • to nie jest zbyt miłe, a ja Tobie nic nie zrobiłem. Teraz ja zadam pytanie Tobie - jaki miałeś cel zadając mi takie pytanie? Bo odpowiedź jest w moim poście, a więc chcesz być po prostu niemiły (zauważyłem już na pierwszym roku studiów informatyki, że ludzie się tacy stają momentalnie… też pewnie do takich należałeś).

W każdym razie dziękuję za odpowiedź, poprawię program.

Pozdrawiam

PS:

reszta programu dobrze?

Jeśli poczułeś się dotknięty to przepraszam. Zapytałem, bo twój pierwszy post zabrzmiał jak szukanie rozwiązania pracy domowej. Błąd jest typowym, który popełniają ci, którzy 5 minut temu przesiedli się z php czy javy (tablica jest obiektem i jest deafultowo alokowana na stercie) na c, z mojego punktu widzenia jakbyś pytał czemu 3 + 2 nie daje 7. Gdybyś napisał w kolejnym poście ze faktycznie, ściemniałeś mam całkiem dobre materiały do c++ jeszcze z czasów studiowania. Plus mógłbym polecić jakąś literaturę, gdzie wszystko nie jest opisane jakby ktoś chciał utrudnić zrozumienie meritum. Reszta programu jest dobra chyba, nie rozumiem po co ten fragment:

if(szyfr[j]=='0')

                                   {

                                       j=0;

                                       szyfrowany[i]=(ciag[i]^szyfr[j]);

                                   }

Tzn domyślam się, że jeśli ciąg do zaszyfrowania będzie dłuższy niż ciąg którym szyfrujem, to używać tego drugiego od początku, po osiągnięciu końca napisu. Tylko, że koniec napisu jest zakończony znakiem ‘\0’.

W takim razie również przepraszam za moją reakcję. Otóż param się C++ od października - od początku studiów :). Mało nam mówili o stosie, w sumie tyle, co nic - jedynie, że istnieje. Sam też jeszcze do tego nie doszedłem w podręczniku u Grębosza. Zadanie z szyfrogramem wyszło z laboratoriów w tym semestrze i zrobiłem je zupełnie inaczej - funkcja wyglądała tak: char

funkcja(char a, char b, char c)

{

c=a^b;

return c;

}

ale chciałem, jak już napisałem, uprościć main maksymalnie. Swoją drogą nie zauważyłeś czegoś, co MI się przypomniało akurat - wystarczy, że podzielisz te ostateczne COUT’y na osobne linijki i będzie program lepiej działał (w końcu on czyta od prawej do lewej…). Fragment kodu, który wskazałeś służy do tego, że jeśli ciąg jest dłuższy od szyfru, to ten szyfr musi lecieć od początku. Np ciąg: qwerty, szyfr: abc - wtedy on powinien zaszyfrować moje “qwerty” za pomocą “abcabc”. Gorzej teraz z odwrotną sytuacją, gdy ciąg jest krótszy od szyfru - pojawiają się wzorki, tak jakby wyświetlanie dotyczyło też tych losowych śmieci z tablicy. Kod:

#include 

#include 


using namespace std;


char *szyfrowanie(char szyfr[], char ciag[], char szyfrowany[])

{

     for(int i=0, j=0; i
             {

                  if(szyfr[j]=='0')

                                   {

                                       j=0;

                                       szyfrowany[i]=(ciag[i]^szyfr[j]);

                                   }

                  else

                                   szyfrowany[i]=(ciag[i]^szyfr[j]);

             }

             return szyfrowany;

}


int main(int argc, char *argv[])

{

    char szyfr[10]={0};

    char ciag[20];

    char zaszyfrowany[20];


    cout<<"Podaj kod szyfrujacy: ";

    cin.getline(szyfr, 10);

    cout<
    cin.getline(ciag, 20);


    cout<
    cout<<"\n2\tciag\t\t"<
    cout<<"\n3\tszyfrowany\t"<
    cout<<"\n4\todszyfrowany\t"<

    system("PAUSE");

    return EXIT_SUCCESS;

}

Więc nadal nie wiem w czym problem :confused:

Pozdrawiam i jeszcze raz przepraszam za moją reakcję :slight_smile:

Aranha

Przeklejam mój edit, bo dodałem go jeszcze przed twoim postem (nim go zobaczyłem).

Tzn domyślam się, że jeśli ciąg do zaszyfrowania będzie dłuższy niż ciąg którym szyfrujem, to używać tego drugiego od początku, po osiągnięciu końca napisu. Tylko, że koniec napisu jest zakończony znakiem ‘\0’, który możemy zrzutować nie jawne przez 0, w żadnym przypadku nie jest to ‘0’, bo ono nie jest zerem w sensie bitowym, to będzie chyba 48, ale strzelam teraz z pamięci :P.

Dodane 30.01.2012 (Pn) 19:16

Dodatkowo jak nad tym myśle, to jeśli w szyfrze ‘a’ i w ciagu do szyfrowania trafimy na ‘a’ ich XOR zwróci 0 co jest końcem napisu, np. szyfr: a ciąg: abc, mimo ze się zaszyfruje to nie wyświetli się nic ze względu na to, że wypisywanie uzna 0 za flagę ‘\0’ - koniec napisu.

Rozwiązałbym to, przez pamiętanie długości napisu i wświetlanie np. znak po znaku tylko już nie strumieniem tylko czymś szybszym ?putchar?

Dodane 30.01.2012 (Pn) 19:26

A dodatkowe znaki biorą się z tego ze napisy co prawda wczytujesz ze znakiem końca napisu (cin go dodaje), ale kodowanie już go nie zawiera i leci sobie dalej aż znajdzie flagę gdzieś tam. Alternatywnie jak wyzerujesz wszystkie tablice i nie będziesz robił re-using’u to teoretycznie będzie ok, oczywiście to zamiatanie problemu pod dywan, ale jest dość szybkie implementacyjnie dla jednego testu :P.

zaraz się zajmę zmianami :slight_smile:

Co do problemu z ‘\0’ i ‘0’ - wiem o co Ci chodzi, chciałem być po prostu sprytny i po to wyzerowałem tablicę, żeby jak ją w części wypełnię, to kolejny element będzie tym zerem (które ustawiłem już deklarując tablicę). Ale zrobię, jak mówisz, to wydaje się o wiele bardziej naturalne :).

Co do a^a - ciekawy jestem kiedy ja zacznę myśleć w ten sposób i brać pod uwagę te wszystkie możliwości… Putchar nie znam, ale zaraz poznam i sprawdzę jak będzie działać.

Te dodatkowe znaki też się postaram zaraz usunąć.

Dzięki ponownie! Jak coś będę miał znowu, to zedytuję.

EDIT:

Jedyne co teraz nie działa, to opcja, gdy wpisuję pierwszą literę ciągu i szyfru taką samą - inne mogą być identyczne, ale gdy pierwsze są identyczne, znowu ślaczki wychodzą. Jedyny błąd, który pozostał chyba.

#include 

#include 


using namespace std;


char *szyfrowanie(char szyfr[], char ciag[], char szyfrowany[])

{

     for(int i=0, j=0; i
             {

                  if(szyfr[j])

                                   {

                                       j=0;

                                       szyfrowany[i]=(ciag[i]^szyfr[j]);

                                   }

                  else

                                   szyfrowany[i]=(ciag[i]^szyfr[j]);

             }

             return szyfrowany;

}


int main(int argc, char *argv[])

{

    char szyfr[10]={0};

    char ciag[20];

    char zaszyfrowany[20];

    int dlugosc_ciag;


    cout<<"Podaj kod szyfrujacy: ";

    cin.getline(szyfr, 10);

    cout<
    cin.getline(ciag, 20);


    dlugosc_ciag=strlen(ciag);


    cout<
    cout<<"\n2\tciag\t\t"<
    szyfrowanie(szyfr, ciag, zaszyfrowany);

    cout<<"\n3\tszyfrowany\t";

    for(int i=0; i
            cout<

    cout<<"\n4\todszyfrowany\t";

    szyfrowanie(szyfr, szyfrowanie(szyfr, ciag, zaszyfrowany), zaszyfrowany);

    for(int i=0; i
            cout<
    cout<

    system("PAUSE");

    return EXIT_SUCCESS;

}

Mógłbyś podać kilka przykładowych danych wejściowych, które tworzą ci krzaki. Nie wiem też czy gdzieś uwzględniłeś z mojego poprzedniego postu to, że potrzebujesz długości napisu w funkcji. Strlen, też działa tak, że dla niego napis to wszystko do czasu wystąpienia 0 bitowego (flagi końca napisu). Jeśli po drodze istnieje możliwość wystąpienia 0 w sensie bitowym musisz iterować nie tym co podaje strlen, tylko długością napisu, pobraną przed szyfrowaniem. Wszystko jest okey przy kodowaniu, ale przy odkodowywaniu, kiedy ciąg może po drodze zawierać ‘\0’ zaczyna się sypać odkodowywanie przez strlen.

Ok, wszystko już działa dobrze, tak jak powinno. Dziękuję Ci za pomoc - tak przy okazji skorzystam z propozycji, którą dałeś chyba w swoim drugim poście odnośnie literatury C++. Od 13 lutego zaczynam programowanie obiektowe - czy mógłbyś polecić jakieś pozycje? Do tego szukam czegoś ciekawego o programowaniu sieciowym, znalazłoby się coś godne polecenia? W internecie znalazłem odnośnie tego sieciowego coś, ale zbyt ogólnikowe wg mnie.

Pozdrawiam i dziękuję za pomoc

Aranha

U mnie, żeby pokazać podstawy programowania obiektowego w C++ sprawdziła się :

http://helion.pl/ksiazki/c-zadania-z-programowania-z-przykladowymi-rozwiazaniami-miroslaw-j-kubiak,cppzad.htm

Jednak nie jest to całkowicie wyczerpująca książka a, jak napisałem ukazuje podstawy

class pole_p{

....

};

Jak i metod wywoływanych w danej klasie.

Pozdro :smiley:

Ja polecam Thinking in C++ Bruce’a Eckela. Wprawdzie nie wiem jak wygląda przekład na język polski, bo czytałem ją tylko w języku angielskim (i polecam ją właśnie w oryginale, jeśli język nie jest dla ciebie barierą), ale miejmy nadzieję, że tłumacz nie popełnił zbyt wielu gaf. Wersję angielską elektroniczną można pobrać za darmo stąd http://www.mindview.net/Books/DownloadSites jednak wersja papierowa jest niewątpliwie przyjaźniejsza dla wzroku. Ponad to gdzieś wcześniej stwierdziłeś, że nie znasz putchar (zakładam, więc że C jest ci raczej obce). Polecam jednakowoż podszkolić się w C, bo niektóre rzeczy szczególnie, gdy chcemy bardzo optymalizować wykonanie algorytmów mogą się przydać. Jeśli chodzi o podstawy sieciowe godna polecenia będzie książka A Top-Down Approach Featuring the Internet autorstwa Kurosa i Rossa. Wprawdzie wszystkie przykłady są napisane w javie, ale moim zdaniem jest to idealny język do nauki podstaw sieci, gdyż nie wymaga wymyślania koła na nowo, są klasy socketów, datagramy, itp. Z drugiej strony nie pozwalają napisać jakiś prostych komunikatorów, proxy itp. w kilku linijkach jak niektóre języki skryptowe. Dlatego uważam, że to całkiem dobry język by poznać jak co działa w miarę dokładnie, a nie dostać frustracji i zniechęcić się na samym początku. Oczywiście nic nie stoi na przeszkodzie, aby przykłady pominąć i poznać tylko teorię n/t budowy sieci, warstwy, routing, itp.