Textcodierer in C

Radhad

Erfahrenes Mitglied
Hallo Tutorials-Gemeinde!

Ich habe mal wieder ein Problem, und zwar mit einem Programm für die Schule...

Infos
Visual C++ 6.0 Compiler
Sprache C

Die Aufgabe
Wir sollen einen Text in einer *.txt Datei codieren und decodieren können mit einem frei wählbarem Codierwort von 80 Zeichen.

Meine Lösungsidee
Ich lese eine Zeile/einen Buchstaben ein, codiere diesen mit dem nun an der Stelle zugehörigem Buchstaben, und zwar mit dem int-Wert, und speicher dies wieder. nun soll die nächste Zeile/der nächste Buchstabe gelesen werden und das Spiel beginnt von vorne.

Meine Probleme
Ich habe immer noch nicht verstanden, wie man eine Zeile vernünftig ausliest, bei mir macht der immer Murks... bzw. wie man einen Buchstaben ausliest
Ich weiß nicht, wie ich an einen Buchstaben herankomme
Wie ich dieses wieder speichern kann


Ich wäre echt für ein paar Tipps mit Beispielen und Kommentaren sehr dankbar!



MfG Radhad
 
versuchen mas mal so:

Code:
char *text, *key, *output;
int i;

text = readText();
key = readKey();
output = malloc(strlen(text)*sizeof(char)+1);

for(i = 0; i < strlen(text); i++) {
    output[i] = text[i] +key[i % strlen(key)];
}

writeOutput(output);
free(text);
free(key);
free(output);

Diese Algoritmus heißt Vignére-Chiffre, er wurde 1586 von Blaise de Vigenére entwickelt.

Bei der dekodierung wendet man das verfahren genau umgekehrt an, dazu tauscht man in dieser Zeile hier:
Code:
    output[i] = text[i] +key[i % strlen(key)];
das + zeichen gegen ein - zeichen aus.
das sieht dann so aus:
Code:
    output[i] = text[i] - key[i % strlen(key)];

Die funktionen readText, readKey und writeOutput sollte eigendlich selbsterklärend sein, sie lesen den text der von der tastatur, aus einer datei oder sonst wo her kommt in einen 0 terminierten C-String ein.

z.B. so:

Code:
char* getText() {
    FILE* fp;
    char* retVal;

    retVal = malloc(1);
    retVal[0] = '\0';
    fp = fopen("textdatei.txt", "rb");

    while(!feof(fp) && !ferror(fp)) {
        retVal = realloc(retVal, strlen(retVal) + 1024);
        fread(&retVal[strlen(retVal)], 1024, 1, fp);
    }
    fclose(fp);
    return realloc(retVal, strlen(retVal)+1);
}

die funktion getKey() funktioniert analog dazu. wenn du von der tastatur lesen will benutzt du einfach stdin anstatt des geöffneten fp.

die funktion writeOutput funktioniert ähnlich, nur öffnet sie die datei mit dem attribut "wb" und schreibt mit fwrite(). das b attribut ist wichtig, da es sich bei der verschlüsselten datei nicht mehr um text sondern um binäre daten handelt,

ACHTUNG: der code sollte nur ein Beispiel sein, und auf keinen fall 1:1 übernommen werden. ein malloc oder realloc kann jederzeit fehlschlagen, und einen NULL pointer zurück geben. entsprechend sind alle pointer nach jedem malloc oder realloc auf NULL zu prüfen.

Des weiteren ist hier der sonderfall eines nullbytes bei der dekodierung nicht berücksichtigt, das ist auf jedenfall noch zu überdenken, aber wenn du mit key im ascii bereich bleibst dürfte es da keine probleme geben, da dieser fall dann nicht eintreten kann.
aufpassen musst du bei ANSI keys welche sondernzeichen aus der erweiterten codepage enthalten (z.B. ÄÖÜ) das kann dann zu problemen führen.
 
Zuletzt bearbeitet:
Danke chibisuke!

ich werde es mal probieren, es so umzusetzen.
achja, wir müssen uns auch in einem ASCII Bereich von 32 bis 126 unsb eschränken, aber ich denke das bekomme ich da auch irgendwie mit rein...

MfG Radhad


Weitere Probleme die ich habe
Ich verstehe nicht, wie ich die einlese Funktion von der Datei schreiben soll, so dass das Programm solange codiert / decodiert, bis die Datei zuende ist und ich nicht städnig einen Dateinamen hin und her übergeben muss...
Außerdem soll die Datei, in der Text dann codiert oder decodiert werden soll, auch eingegeben werden vom Anwender ^^

Am liebsten wäre es, wenn ich das ganze in einer do-while Schleife verarbeiten könnte, halt sowas wie "solange Datei nicht zuende, codiere textzeichen123 mit Codewortzeichen5, wenn noch nicht zuende, codiere extzeichen124 mit Codewortzeichen 6" etc.

Hier folgt nun das Programm, soweit ich es geschrieben habe:

Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

void codierer(codiert2, decodiert2, codewort2)
{
}

void decodierer(codiert2, decodiert2, codewort2)
{
}

void main()
{
	int auswahl;
	char codiert[256], decodiert[256], codewort[80];

	do
	{
		printf("\t\t\tVerschluesselungsprogramm\n");
		printf("\t\t\t-------------------------\n\n\n\n");
		printf("[1] - Codierung\n");
		printf("[2] - Decodierung\n");
		printf("[3] - Beenden\n\n");
		printf("Auswahl: ");
		scanf("%d",&auswahl);
		fflush(stdin);
		system("cls");

		if(auswahl==1)
		{
			printf("\t\t\tVerschluesselungsprogramm\n");
			printf("\t\t\t-------------------------\n\n\n\n");
			printf("Dateiname der Codierten Datei eingeben: ");
			scanf("%s",codiert);
			fflush(stdin);

			printf("Dateiname der Decodierten Datei eingeben: ");
			scanf("%s",decodiert);
			fflush(stdin);

			printf("Codewort: ");
			scanf("%s",codewort);
			fflush(stdin);

			codierer(codiert, decodiert, codewort);
		}
		else if(auswahl==2)
		{
			printf("\t\t\tVerschluesselungsprogramm\n");
			printf("\t\t\t-------------------------\n\n\n\n");
			printf("Dateiname der Codierten Datei eingeben: ");
			scanf("%s",codiert);
			fflush(stdin);

			printf("Dateiname der Decodierten Datei eingeben: ");
			scanf("%s",decodiert);
			fflush(stdin);

			printf("Codewort: ");
			scanf("%s",codewort);
			fflush(stdin);

			decodierer(codiert, decodiert, codewort);
		}
		else if(auswahl==3)
			break;
		else
		{
			printf("Falsche Auswahl");
			printf("Weiter mit [ENTER]");
			getch();
			fflush(stdin);
			system("cls");
		}
	}
	while(auswahl!=3);
}
 
Zuletzt bearbeitet:
Also das stück code schneid ich dir jetzt mal zusammen...

Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int codierer(char *codiert, char *decodiert, char *codewort);
int decodierer(char *codiert, char *decodiert, char *codewort);
void main(int argc, char **argv);

void main(int argc, char **argv)
{
	int auswahl, ergebnis;
	char codiert[256], decodiert[256], codewort[80];

	do
	{
		printf("\t\t\tVerschluesselungsprogramm\n");
		printf("\t\t\t-------------------------\n\n\n\n");
		printf("[1] - Codierung\n");
		printf("[2] - Decodierung\n");
		printf("[3] - Beenden\n\n");
		printf("Auswahl: ");
		scanf("%d",&auswahl);
		fflush(stdin);
		system("cls");
		
		if(auswahl==3) {
			break;
		} else 
		if(auswahl==1 || auswahl == 2) {
			printf("\t\t\tVerschluesselungsprogramm\n");
			printf("\t\t\t-------------------------\n\n\n\n");
			printf("Dateiname der Codierten Datei eingeben: ");
			scanf("%s",codiert);
			fflush(stdin);

			printf("Dateiname der Decodierten Datei eingeben: ");
			scanf("%s",decodiert);
			fflush(stdin);

			printf("Codewort: ");
			scanf("%s",codewort);
			fflush(stdin);
			
			printf("--------------------------------------------\n");

			if(auwahl == 1) ergebnis = codierer(codiert, decodiert, codewort);
			else ergebnis = decodierer(codiert, decodiert, codewort);
			if(ergebnis) printf("Status: Vorgang erfolgreich abgeschlossen\n");
			else printf("Status: Vorgang fehlgeschlagen\n");
			system("pause");
			system("cls");
		}
		else
		{
			printf("Falsche Auswahl");
			printf("Weiter mit [ENTER]");
			getch();
			fflush(stdin);
			system("cls");
		}
	}
	while(auswahl!=3);
}

so ist das ganze schon einmal um einiges kürzer, außerdem hab ich noch n wenig fehlerhandling eingebaut, und n paar Prototypen gesetzt ;-)

und nun zu den funktionen codierer und decodierer, also du musst dort natürich parameter eines typs überlegen, der typ für ein text ist char*

versuch das mal so:
Code:
int codierer(char *codiert, char *decodiert, char *codewort) {
	FILE* fpCodiert, fpDecodiert;
	int i, j;

	fpCodiert = fopen(codiert, "w");   //dateien öffnen
	fpDecodiert = fopen(decodiert, "r");

	if(!fpCodiert || !fpDecodiert) return 0; //öffnen der datei fehlgeschlagen?

	for(i = 0; !feof(fpDecodiert); i++) {  //codierung
		j = fgetc(fpDecodiert) + codewort[i % strlen(codewort)];
		if( j >= 128) j -= 128;
		fputc(j , fpCodiert);
	}
	fclose(fpDecodiert); //dateien wieder schließen
	fclose(fpCodiert);
	return 1; //erfolg melden
}

int decodierer(char *codiert, char *decodiert, char *codewort) {
	FILE* fpCodiert, fpDecodiert;
	int i, j;

	fpCodiert = fopen(codiert, "r");
	fpDecodiert = fopen(decodiert, "w");

	if(!fpCodiert || !fpDecodiert) return 0; //öffnen der dateien fehlgeschlagen?

	for(i = 0; !feof(fpDecodiert); i++) { //decodieren
		j = fgetc(fpCodiert) - codewort[i % strlen(codewort)];
		if( j <= 0) j += 128;
		fputc(j , fpDecodiert);
	}
	fclose(fpCodiert);
	fclose(fpDecodiert);
	return 1; //erfolg melden
}

Die routine beschreibt einen bereich von 0 - 127, und bleibt damit im ASCII standart, wenn du steuerzeichen vermeiden willst, so bleibt dir nichts anderes übrig als den bereich in dem das passwort und der text sein darf noch weiter einzuschränken, und den algoritmus entsprechend anzupassen, wie es prinziell funktioniert sieht man hier. wenn du aber erweitertes ASCII haben willst, dann musst du alle 256 zeichen eines bytes zulassen...
 
Hi chibisuke!

Deine Funktionen verstehe ich jetzt, allerdings bekomme ich das Programm nicht lauffähig, wenn ich beide Teile zusammenfüge kommen nur noch Errors.

Hast du evtl. eine Bibliothek verwendet, die oben noch nicht mit angegeben wurde?

Und noch eine Frage...
Was bedeuten die Variabeln in diesem Funktionsaufruf? Etwas mit zwei ** habe ich noch nicht kennengelernt...
void main(int argc, char **argv)
 
Zuletzt bearbeitet:
hmm Error? nicht das ich wüsste.. ich test es selbst mal...

Ok da waren 3 oder 4 schreibfehler drin, und außerdem fehlte string.h
Hab noch n paar kleinere semantik Fehler korrigiert, die sonst zu unschönen Ergebnissen geführt hätten. das Ergebnis hängt n stück weiter unten.

Zur erklärung der Änderungen... trim() nach benutzereingaben schadet nicht, weil man damit Zeilenumbrüche, leerzeichen, tabulatoren und ähnliches am ende abschneiden kann. Außerdem hab ich noch eingebaut das er verhindert das er das EOF zeichen mitcodiert, das haste sonst nämlich am ende ziemlich unschön dran hängen.

Was den Funktionskopf von main betrifft
Der Funktionskopf von main heißt vollständig

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

Das argc ist die Anzahl der dem Programm übergebenen Komandozeilen Parameter, und argv ist ein array aus Zeichenketten das die Parameter beinhaltet.
Das ** heißt das es ein Zeiger ist der seinerseits wieder auf einen Zeiger zeigt, die benutzt man wenn man entweder einen Zeigen von anderer Stelle bearbeiten will, oder aber wenn man Arrays aus Zeigern hatt.
Ein char*[] oder char[][] würde zu einem char** werden, ein char[][][] wird zum char*** und so weiter.

Also den code gibts als Dateianhang, und die exe dazu, ich dachte mir so ists bequemer ;-)
 

Anhänge

Zuletzt bearbeitet:
Es funktioniert, vielen Dank!

Außer mit der Einschränkung der ASCII Zeichen, aber das werd ich schon noch herausfinden!
 
Zuletzt bearbeitet:
äh, wenn du Binär dateien oder erweitertes ASCI oder ANSI haben willst, dann musst du einfach nur in diesen zeilen:

if( j >= 128) j -= 128;
if( j <= 0) j += 128;

das 128 durch 256 ersetzen.
das ergebnis ist dann allerdings auch eine Binärdatei...
 
Ich habe das nun auch geändert, und er codiert nun nach einem Fehler ausmerzen meinerseits sogar richtig. Vielen Dank nochmal!
 
Zurück