[C++] Szyfr Vigenere'a


(Ravenravenpl) #1

Witam. Chciałem napisać program, który po wpisaniu tekstu jawnego i klucza wyświetli tekst zaszyfrowany sposobem Vinegere'a. Napotkałem jednak na problem. Oto mój kod:

#include "stdafx.h"

#include 

#include 

#include 

using namespace std;


int main () {

	string alfabet[26][26]; //tablica wg. której szyfrujemy (dwuwymiarowa)

	string klucz;

	string klucz2;

	string jawny;

	string szyfr;

	int liczba;


	for (int y=0; y<26 ;y++) { 

		liczba=65+y;

		for (int x=0; x<26; x++) { 

			if (liczba==91) liczba=65; 

			alfabet[x][y]=char(liczba);

			liczba++;

		}

	}


	cout<<"Podaj tekst jawny: "<
	getline(cin, jawny);

	szyfr=jawny;

	klucz2=jawny;

	cout<
	cin>>klucz;


	int j=0;

	for (int i=0;i
		if (klucz2[i]!=' ') {

			klucz2[i]=klucz[j];

			if (j
			if (j==klucz.size()) j=0;

		}

	}


	int wsp_x;

	int wsp_y;

	string znak;

	string szukany;

	string wynik;

	string s;

	for (int i=0;i
		for (int x=0;x<26;x++) {

			znak=jawny[i];

			szukany=alfabet[x][0];

			if (znak==szukany) wsp_x=x;

		}

		for (int y=0;y<26;y++) {

			znak=klucz[i];

			szukany=alfabet[0][y];

			if (znak==szukany) wsp_y=y;

		}

	wynik=alfabet[wsp_x][wsp_y];

	szyfr[i]=wynik;

	}


	cout<
	system("pause");


	return 0;

}

Przy próbie kompilacji dostaję takie oto komunikaty:

1>d:\dokumenty\c++\visual\vinegre\vinegre\vinegre.cpp(34): warning C4018: '<' : signed/unsigned mismatch

1>d:\dokumenty\c++\visual\vinegre\vinegre\vinegre.cpp(37): warning C4018: '<' : signed/unsigned mismatch

1>d:\dokumenty\c++\visual\vinegre\vinegre\vinegre.cpp(48): warning C4018: '<' : signed/unsigned mismatch

1>d:\dokumenty\c++\visual\vinegre\vinegre\vinegre.cpp(60): error C2440: '=' : cannot convert from 'std::string' to 'char'

1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

O ile pierwsze 3 warningi chyba są bez znaczenia, tak nie rozumiem, co się dzieje w ostatnim błędzie. Dlaczego nie mogę w ten sposób umieścić litery w tablicy? Jest jakiś sposób, by to ominąć?

Mój system operacyjny: Windows 7 32bit

Środowisko, w którym piszę: Microsoft Visual C++ 2010 Express


(Sawyer47) #2

Zadeklarowałeś wynik jak std::string, nie możesz przypisać ot tak std::string do zmiennej char. Zmienna wynik wydaje się zupełnie zbędna, robisz tylko zbędne (i błędne) przypisania.

wynik=alfabet[wsp_x][wsp_y];

   szyfr[i]=wynik;

(Ravenravenpl) #3

No tak, prawda.

Z drugiej strony, jeśli zmienię typ zmiennej wynik na char to nie mogę do niej przypisać litery z tablicy alfabet. Jak do zmiennej wynik (typu char) przypisać element z tablicy alfabet o współrzędnych wsp_x i wsp_y? Trzeba by jakoś rzutować?

Bo takie coś:

szyfr[i]=alfabet[wsp_x][wsp_y]

nie działa (kompilator mówi, że nie można dokonać konwersji z std::string na char, dlatego też zacząłem kombinowanie z przypisywaniem.


(Sawyer47) #4

Może zamiast używać wszędzie std::string, tam gdzie chodzi Ci o pojedynczą literkę użyjesz char?

Tak na marginesie, można ten szyfr zaimplementować o wiele prościej.


(Martini M) #5

Witam,

Trochę namieszałeś.

Zacznij od tego:

a)

#define ILE_LITER 26

przyda się zamiast wpisywać ciągle 26 jak będziesz chciał zmienić ilość znaków to tylko w jednym miejscu poprawka; b) tablicę szyfrującą zrób typu

char tab[ILE_LITER][ILE_LITER];

c) wystarczy tylko jedna zmienna klucz typu std::string d) jedna zmienna wyjściowa typu std::string gdzie zapiszesz wynik szyfrowania e) wypełnij tablicę szyfrującą; najlepiej w dwóch pętlach: obie zrób na zmiennych typu int (chociaż byte też wystarczy). Pierwsza niech leci od int('A') do int('A') + ILE_LITER, a druga niech leci od obecnego licznika pierwszej pętli do obecny_licznik+ILE_LITER. Będzie to tak wyglądało:

int pocz = (int)('A');

for(int a= pocz; a
{

  for(int b=a;b
  {

    int y = b%ILE_LITER;

    tab[a][y] = ('A'+y);

  }

}

[/code]


Szyfrowanie możesz zrobić podobnie. Wystarczy do tego jedna pętla biegnąca po wszystkich znakach tekstu jawnego. Zakładając, że tekst jawny masz w zmiennej std::string t, a klucz w zmiennej std::string k (wynik będzie w std::string w), będzie to wyglądało mniej więcej tak:

[code] int len_txt = t.length(); //zeby tylko raz odczytac dlugosc tekstu int len_key = k.length(); int x =0, y=0;//zmienne do wyliczenia współrzędnych w tablicy szyfrującej for(int i=0;i { x = t[i] - 'A'; y = k[i%len_k] - 'A'; w.append(tab[x][y]); }

Taki zapis 'A' będzie interpretowany jako kod ASCII dużej litery A, czyli 65. Jak w tekście jawnym będzie litera A (czyli 65) - A (czyli 65) to x = 0, B-A = 1 itd...

Nie kompilowałem tego to jest tylko zarys idei. Musisz dopracować szczegóły. Z grubsza powinno działać.

Powodzenia.

P.S.

Koncept zakłada, że wprowadzany tekst jest tylko wielkimi literami i bez spacji. Nie mogą wystąpić żadne inne znaki niż A-Z wielki alfabet.


(Ravenravenpl) #6

No tak, trzeba było deklarować tablicę alfabet jako typ char a nie string! Dziękuję za pomoc.

Dodatkowo w kilku miejscach wprowadziłem kilka usprawnień, bo algorytm do końca nie działał jak trzeba. Aktualnie wygląda to tak, może kiedyś komuś się przyda:

#include "stdafx.h"

#include 

#include 

#include 

using namespace std;


int main () {

	char alfabet[26][26];

	string klucz;

	string klucz2;

	string jawny;

	string szyfr;

	int liczba;


	for (int y=0; y<26 ;y++) { 

		liczba=65+y;

		for (int x=0; x<26; x++) { 

			if (liczba==91) liczba=65;

			alfabet[x][y]=char(liczba);

			liczba++;

		}

	}


	cout<<"Podaj tekst jawny: "<
	getline(cin, jawny);

	szyfr=jawny;

	klucz2=jawny;

	cout<
	cin>>klucz;


	int j=0;

	for (int i=0;i
		if (klucz2[i]!=' ') {

			klucz2[i]=klucz[j];

			if (j
			if (j==klucz.size()) j=0;

		}

	}


	int wsp_x;

	int wsp_y;

	string znak;

	string szukany;

	char wynik;

	string s;

	for (int i=0;i
		for (int x=0;x<26;x++) {

			znak=jawny[i];

			if (znak[0]!=32) {

				szukany=alfabet[x][0];

				if (znak==szukany) wsp_x=x;

			}

		}

		for (int y=0;y<26;y++) {

			znak=klucz2[i];

			if (znak[0]!=32) {

				szukany=alfabet[0][y];

				if (znak==szukany) wsp_y=y;

			}

		}

	wynik=alfabet[wsp_x][wsp_y];

	if (jawny[i]!=' ') szyfr[i]=wynik;



	}


	cout<
	system("pause");


	return 0;

}

A co do prostszej implementacji... nie jestem jakimś wielkim mózgiem w dziedzinie algorytmiki, jeśli chodzi o programowanie to poziom też prezentuję b. niski (choć idzie nieustannie do góry :slight_smile: ), cieszę się, że udało mi się choćby coś takiego napisać :).

EDIT: O, nie zauważyłem tej odpowiedzi nad moim postem. Dziękuję bardzo za cenne wskazówki! Spróbuję jeszcze ten algorytm przebudować wg. Twoich porad. Dzięki, dzięki wielkie za pomoc! Miło, że na świecie są jeszcze ludzie gotowi bezinteresownie poświęcić swój czas dla innych.

Wygląda na to, że problem rozwiązany.