Ceasar Chiffre mit C < Softwaretechnik+Pro < Praktische Inform. < Hochschule < Informatik < Vorhilfe
|
Aufgabe | Ein einfaches Verschluesselungsverfahren ist die sog. Caesar-Chiffre, welche darauf beruht, dass man
das zu verschluesselnde Zeichen um eine vorgegebene Anzahl anz von Zeichen im Alphabet nach links
bzw. nach rechts verschiebt.
Ueberschreitet man dabei das Ende des Alphabets, faengt man wieder
von vorne an zu zaehlen.
Beispiel:
Mit dem Verschiebeparameter anz = +7 erhaelt man aus dem Klartext Streng geheim die verschluesselte
Zeichenkette Zaylun nlolpt.
Schreiben Sie ein C-Programm caesar.c, mit welchem man beliebige Tastatureingaben bzw. ASCIITextdateien
ver- bzw. entschluesseln kann.
Zum Testen der Entschluesselungsfunktionalitaet koennen Sie die Textdateien aus dem Materialordner
zum aktuellen Uebungsblatt verwenden, welche mit Hilfe der Caesar-Chiffre (und jeweils einem unbekanntem
Parameter anz) verschluesselt worden sind.
Hinweise:
Sie duerfen annehmen, dass jeweils die Großbuchstaben A . . . Z und die Kleinbuchstaben a . . . z
zusammenhaengend kodiert sind (wie z.B. in ASCII-Kodierung), d.h. fuer einen Kleinbuchstaben
bk gilt:
a < bk < z
Es sollen nur die Großbuchstaben A . . . Z und die Kleinbuchstaben a . . . z verschluesselt werden.
Alle anderen Zeichen (Umlaute, Zahlen, Interpunktionszeichen, Sonderzeichen, etc.) sollen unver
aendert uebernommen werden.
Verwenden fuer die Eingabe der Zeichen ein geeignetes Schleifenkonstrukt, welches bei Erreichen
des EOF-Zeichens bzw. bei Betaetigung von <CTRL>-d terminiert. |
Ich habe diese Frage in keinem Forum auf anderen Internetseiten gestellt.
Ich bin nun davon ausgegangen, dass die Buchstaben mit ACSII codiert werden und habe folgenden Ansatz:
#include <stdio.h>
int main(void)
{
int parameter;
char zeichen;
scanf("%d", ¶meter);
while(scanf("%c", &zeichen) != EOF)
{
if(zeichen>96 && zeichen<123) /* Pruefen, ob Kleinbuchstabe */
{
zeichen = zeichen + parameter;
if(zeichen>122)
zeichen = zeichen - 26;
else if(zeichen<97)
zeichen = zeichen + 26;
}
else if(zeichen>64 && zeichen<91) /* Pruefen, ob Grossbuchstabe */
{
zeichen = zeichen + parameter;
if(zeichen>90)
zeichen = zeichen - 26;
else if(zeichen<65)
zeichen = zeichen + 26;
}
printf("%c", zeichen);
}
[mm] printf("%d\n\n", [/mm] parameter);
return 0;
}
Das funktioniert auch schon ganz gut. Nur, wenn der verschluesselte Buchstabe außerhalb des ASCII Bereichs liegt, bekomme ich falsche Ergebnisse. Wenn ich an der Stelle mit dem Kommentar "Pruefen auf Kleinbuchstabe" mittels printf die Werte fuer zeichen und parameter ausgeben lasse, dann stimmen diese. Aber die Summe, die einen Schritt spaeter ausgerechnet wird, liegt dann überraschender Weise im negativen Bereich.
Dies ist der Anfang des zu entschluesselnden Textes, der schon ausreicht, um zu erkennen, ob das Programm richtig funktioniert: "14Quzqy", wobei die 14 der auszulesende Verschiebeparameter ist.
Vielen Dank fuer eure Aufmerksamkeit und Hilfe!
|
|
|
|
Hallo und ,
ersetze doch mal deine Deklaration von "zeichen" durch
unsigned char zeichen;
Ist klar, warum es dann funktioniert?
Gruß
Martin
|
|
|
|
|
Zunächst einmal vielen Dank, es funktioniert!
Ich weiß, wozu "unsigned char" prinzipiell steht. Man erzeugt einen Char und gibt ihm einen Namen. Und mit unsigned sorgt man dafür, dass er nur positive Werte annehmen kann. Aber ich verstehe nicht, warum das an dieser Stelle notwendig war. Ich war davon ausgegangen, dass es automatisch positive Werte verwenden würde. Schließlich entspricht "a" z.B. in ACSII der Dezimalziffer "97".
|
|
|
|
|
Hallo,
das Problem ist ja, dass ein char (signed und unsigned) nur 8 Bits zur Verfügung hat und somit nur 256 Werte annehmen kann.
Unsigned-Variablen haben bekanntlich immer einen nichtnegativen Wert. Wenn man eine größere von einer kleineren Zahl subtrahiert, bekommt man also keinen negativen Wert sondern komt "von oben wieder rein", also z.B.
0 - 1 = 255
0 - 2 = 254
usw.
Falls dir das Wort Zweierkomplement etwas sagt, dann weißt du, dass -1 und 255 dieselbe Darstellung haben. Nur unterscheidet sich die Interpretation des obersten Bits. Hier im Unsigned-Typ hat es keine spezielle Bedeutung. Es wird als ein Stellenwertbit angesehen.
Bei Signed-Typen jedoch ist ca. die Hälfte der 256 Werte negativ. Die Unterscheidung wird hier anhand des obersten Bits getroffen. Ist es 1, dann ist die Zahl negativ, sonst nicht.
Wenn du also den char 't' = 116 = 01110100 (binär) hast, und dazu 12 addierst, dann passiert Folgendes:
01110100 + 00001100 = 10000000
Das oberste Bit wird 1 und der Rechner interpretiert das Ergebnis als negative Zahl (nämlich -128).
Im "nichtarithmetischen Sinne" bekommst du natürlich das Zeichen mit dem ASCII-Wert 128, aber wenn du damit rechnest, erlebst du so manche Überraschung.
Deswegen muss man auch aufpassen, wenn man beispielsweise Werte von einem Datentyp in einen anderen umwandelt. Ein int-Wert von 200 ist ja, wie wir jetzt wissen als (signed) char nicht 200.
Ich hoffe, das Ganze ist jetzt etwas klarer.
Übrigens ist im ISO-C-Standard gar nicht festgelegt, ob der reine char als signed oder unsigned angenommen wird. Das heißt, mit einem anderen Compiler hätte dein Code vielleicht funktioniert. Etwas unschön, nicht wahr?
Gruß
Martin
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 19:27 Mo 03.12.2007 | Autor: | Auron2009 |
Wieder etwas gelernt, bzw. bereits gehörtes an einem praktischen Beispiel angewendet. Vielen Dank. Hier ist dann alles geklärt. :)
|
|
|
|