Problem bei einer Aufgabe in C

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Mr GS
Beiträge: 5
Registriert: Di Jan 12, 2021 5:38 pm

Problem bei einer Aufgabe in C

Beitrag von Mr GS » Do Jan 14, 2021 8:16 pm

Guten Abend,

bin derzeit am Studieren, in der Richtung Informatik.
Beim Programmieren hab ich derzeit keine Probleme gehabt, nur diese Aufgabe lässt mich einfach nicht los.
Das bereits geschriebene Programm funktioniert, nur es gibt einen Fehler den ich einfach nicht lösen kann, entweder denk ich zu kompliziert oder übersehe etwas.

Nun genug davon, hier die Aufgabe:
Es geht um die Programmierung einer Skytale.
Was eine Skytale ist: http://www.mathe.tu-freiberg.de/~hebisc ... ytale.html

Hier die Main Funktion die Vorgegeben ist:

Code: Alles auswählen

void skytale(char * in, int n, char * out);

int main() {
  char s1[1000] = "DIESERKLARTEXTISTJETZTZUVERSCHLUESSELN12",
  s2[1000]="***bereits*verwendete*zeichenkette*mit*inhalt***", // Verschlüsseln hier hinein
  s3[1000]; // Entschlüsseln in diese Variable
  int n = 3, l = strlen(s1);
  printf("%s\n", s1);
  printf("Laenge: %d\n", l);
  skytale(s1, n, s2); // Chiffriere s1 zu s2 mit 8 Buchstaben pro Umdrehung
  printf("%s\n", s2);
  if (l % n == 0) {
    skytale(s2, l / n , s3); // Chiffriere zurueck
    printf("%s\n", s3);
    if (!strcmp(s1, s3)) {
      printf("In diesem Fall OK\n");
    }
    else {
      printf("Problem!\n");
    }
  }
  return 0;
}
Und hier was ich derzeit gemacht habe:

Code: Alles auswählen

void skytale(char * in, int n, char * out) {

int l = strlen(in);
int index = 0;
int i, j;
int mod = l%n;

	if (mod == 0){

		for (j = 0; j < n; j++){					//Hier wird Der zu verschlüsselnde Text eingelesen und wieder ausgelesen
		
										//l ist hierbei die Länge vom eingegebenen Wert in
										
			for (i = 0; i < (l/n); i++){				//Index wird benötigt um zuerst bei out auf sie Stelle 0 zu kommen
										//und dann byte für byte den Text einlesen
				
				if(j == 0){					//Wird nur einmal ausgeführt damit der erste Wert im 
										//String ausgelesen werden kann
				
					out[index] = in [i*n];
					index++;
					//printf("In = %s\n", in);
					//printf("Out = %s\n", out);
					
				}else{
					out[index] = in [i*n+j];
					index++;
				}
			}
		}
	}else{
		
		for (j = 0; j < n; j++){

			for (i = 0; i < (l/n); i++){
				
				if(j == 0){	
					out[index] = in [i*n];
					index++;
					
				}else{
					out[index] = in [i*n+j];
					index++;
				}
			}
		}
		
	}
	out [l] = '\0';

}
Zu meinem Problem und zum Code:
nur ganze Zahlen werden mit einander berechnen, deswegen "int" Werte
"n" ist der Schüssel der Skytale und der Durchmesser.
"s1" ist "in"
"s2" ist "out"
"s3" wird dann mit "out" beschrieben in der Main Funktion für das Ergebnis.
"l" ist die String länge von "in" also 40
"mod" ist die modulo Rechnung von "l" und "n"

Das Programm liest den String "in" ein und schreibt in direkt in "out".
Dies wird gemacht bei den 2 "for" Schleifen.

Der erste Block mit den 2 "for" Schleifen macht bisher das selbe wie der zweite unter "else". Nur beim ersten werden die Strings durchgegangen wenn l%n=0 ist.
Im zweiten Block sollte dann der Andere Fall auftreten, wenn l%n =! 0 ist.


Nun das Problem:
Bei l%n=0 läuft das Programm problemlos und gibt die richtigen Ausgaben.
Folgende Ausgabe bei n=2:
DIESERKLARTEXTISTJETZTZUVERSCHLUESSELN12
Laenge: 40
DEEKATXITEZZVRCLESL1ISRLRETSJTTUESHUSEN2
DIESERKLARTEXTISTJETZTZUVERSCHLUESSELN12
In diesem Fall OK


Nun die Ausgabe für n=3:
DIESERKLARTEXTISTJETZTZUVERSCHLUESSELN12
Laenge: 40
DSKRXSETVSLSLIELTTTTZECUSNERAEIJZURHEE1i


Wie man sieht steht nun hinten ein "i", was der Fehler ist.
Es ist ein Rundungsfehler.
Bei n=3 wird folgendes berechnet:
40/3=13,33...
40%3=1 und genau die Ausgabe des mod rechners gibt dann die Anzahl der Buchstaben die Falsch sind.
Z.B. bei n=9 werden l%n viele Fehler auftreten also 4 Fehler.

Nochmal zu n=3:
Die richtige Ausgabe hierbei wäre -> "DSKRXSETVSLSL" und dann die 2 also "DSKRXSETVSLSL2..."
Also der 14te Wert soll die 2 sein.
Nun wie bekomme ich z.B. die 2 (bei n=3), bei dem ersten Durchlaufen der Schleifen auf den 14ten platz?


Ich weis es ist meine Aufgabe dies zu lösen und ich habe jegliches versucht und ich komme einfach nicht drauf.
Vielleicht übersehe ich etwas oder habe einen Fehler eingebaut.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Problem bei einer Aufgabe in C

Beitrag von Xin » Fr Jan 15, 2021 11:50 am

Moin

Als erstmal habe ich mir Deine Funktion angeguckt und bin da etwas verzweifelt... weil ich lange gesucht habe, wonach Du eigentlich unterscheidest. Wenn in if und else das gleiche drin steht... reicht's, wenn man einmal schreibt. Das gilt auch für die Verschachtelungen. Ich habe das dann mal was zusammengekürzt, denn kürzerer Quelltext ist leichter zu verstehen:

Code: Alles auswählen

void skytale(char * in, int n, char * out) 
{
    int l = strlen(in);
    int index = 0;
    int i, j;
    int mod = l%n;

    for (j = 0; j < n; j++)
    {                             
        for (i = 0; i < (l/n); i++)
        {				   
            out[index] = in [i*n+j];
            index++;
        }
    }
    out [l] = '\0';
}
Okay... also das i ist nicht überschrieben worden, es wurde also nur eine Länge von 40/3*3 Zeichen bearbeitet. 40/3 sind 13 und 13*3 sind 39. Da fehlt also eins, also wurde das letzte Zeichen nicht überschrieben. Das Nullbyte hingegen setzt Du richtig an die Position am Ende der Länge des ursprünglichen Strings. Also dürfte index < l sein.

Ich glaube, dein Fall ist in der Beschreibung so nicht definiert, denn das dürfte bei Dir so aussehen:

Code: Alles auswählen

DIE
SER
KLA
RTE
XTI
STJ
ETZ
TZU
VER
SCH
LUE
SSE
LN1
2*
..und an dem Sternchen müsste jetzt erstmal geklärt sein, wie es hier weitergeht. Du musst also eine Zeichenkette haben, bei der höchstens der letzte Buchstabe fehlt. Ansonsten musst Du auffüllen, damit der verschlüsselte Text nicht in sich verrutscht. Hier ist das Problem meiner Meinung nach gar nicht klar definiert, ergo muss für den Fall erst eine Lösung definiert werden.

Das Problem hast Du bei n=2 nicht, denn die Reihen sind immer vollständig oder es fehlt maximal der letzte Buchstabe (was Dein Algorithmus aber so noch nicht berücksichtigt).
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Mr GS
Beiträge: 5
Registriert: Di Jan 12, 2021 5:38 pm

Re: Problem bei einer Aufgabe in C

Beitrag von Mr GS » Fr Jan 15, 2021 12:45 pm

Erstmal vielen Dank für dein Antwort.
Hat mir geholfen.
Ich habe das dann mal was zusammengekürzt,...
Ja stimmt redundanz bei Verzweigungen benötigt man nicht, hab ich komplett ausgeblendet. Danke dafür :D

..und an dem Sternchen müsste jetzt erstmal geklärt sein, wie es hier weitergeht.
Du musst also eine Zeichenkette haben, bei der höchstens der letzte Buchstabe fehlt. Ansonsten musst Du auffüllen...
Als ich alles mehrmals durchgegangen bin, auch handschriftlich, vermute ich das es ein Rundungsfehler ist.
Da eben 40/3*3 nur 39 ergibt.
Bin die ganze Zeit schon am überlegen wie man das letzte byte nehmen kann.
Mit "auffüllen" meinst damit das man angibt das man zum letzten byte gehen soll?

Also so gedacht:
DIESERKLARTEXTISTJETZTZUVERSCHLUESSELN12
DSKRXSETVSLSLIELTTTTZECUSNERAEIJZURHEE1i
Das "L" kommt an diese Stelle, nun müsste ich aber eines weiter laufen um die "2" zu bekommen.
3 Schritte weiter und ich bin bei 2 die dann hinter das "L" geschrieben wird.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Problem bei einer Aufgabe in C

Beitrag von nufan » Fr Jan 15, 2021 1:04 pm

Hallo :)
Mr GS hat geschrieben:
Fr Jan 15, 2021 12:45 pm
Bin die ganze Zeit schon am überlegen wie man das letzte byte nehmen kann.
Du lässt die innere Schleife einen Schritt weiter laufen:

Code: Alles auswählen

i < (l/n) + 1
Gleichzeitig musst du dann aber überprüfen, ob dein Index i*n+j die Länge l auch nicht überschreitet. Ansonsten greifst du auf Daten außerhalb deiner Arrays zu.

Mit dieser Variante komme ich auf die Lösung von hier:
https://kryptografie.de/kryptografie/ch ... kytale.htm
DSKRXSETVSLSL2IELTTTTZECUSNERAEIJZURHEE1

Mr GS
Beiträge: 5
Registriert: Di Jan 12, 2021 5:38 pm

Re: Problem bei einer Aufgabe in C

Beitrag von Mr GS » Fr Jan 15, 2021 3:19 pm

Du lässt die innere Schleife einen Schritt weiter laufen
Manchmal steht man echt auf dem Schlauch.
Danke dafür, habe vieles ausprobiert doch genau an dieser Stelle habe ich bisher noch nix ausprobiert.
Aber aus Fehlern lernt man.

Nun hab ich dennoch eine Ausgabe die ich jetzt nicht ganz verstehe:
DSKRXSETVSLSL2IELTTTTZECUSN
Also die äußerste Schleife wird nur 2 mal ausgeführt und kein drittes mal.
Habe den Wert mal hochgestellt, aber genau nach 2 mal wird abgebrochen.

Kann es daran liegen das ich beim 2ten durchführen dann außerhalb des "in" arrays komme und somit abgebrochen wird?
Beim zweiten Durchlauf kommt das Programm dann zum 41ten Wert und der ist ein Leerer Wert.
Wenn dem so sei muss ich nochmal in die Unterlagen schauen, da gab es mal ein Beispiel dazu.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Problem bei einer Aufgabe in C

Beitrag von Xin » Fr Jan 15, 2021 3:51 pm

Mr GS hat geschrieben:
Fr Jan 15, 2021 3:19 pm
Nun hab ich dennoch eine Ausgabe die ich jetzt nicht ganz verstehe:
DSKRXSETVSLSL2IELTTTTZECUSN
Also die äußerste Schleife wird nur 2 mal ausgeführt und kein drittes mal.
Habe den Wert mal hochgestellt, aber genau nach 2 mal wird abgebrochen.

Kann es daran liegen das ich beim 2ten durchführen dann außerhalb des "in" arrays komme und somit abgebrochen wird?
C bricht normalerweise erst ab, wenn der Algorithmus oder vorgibt oder das OS das Programm abschießt.
Wenn Dein Programm also nicht abschmiert, wohl eher nicht.

Lass mich raten: Die Schleife wird dreimal ausgeführt, aber Du greifst Du Zeichen 40 zu, wobei der Text nur von 0 bis 39 geht. Also kopierst Du Dir das Nullbyte mitten in den Zielstring, weswegen der dann kürzer ist.

Aber ohne Code.... keine Ahnung.
Mr GS hat geschrieben:
Fr Jan 15, 2021 3:19 pm
Beim zweiten Durchlauf kommt das Programm dann zum 41ten Wert und der ist ein Leerer Wert.
Wenn dem so sei muss ich nochmal in die Unterlagen schauen, da gab es mal ein Beispiel dazu.
Ich bin mir nicht sicher, wie er dahin kommt, aber das klingt, als wäre da was kaputt...
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Mr GS
Beiträge: 5
Registriert: Di Jan 12, 2021 5:38 pm

Re: Problem bei einer Aufgabe in C

Beitrag von Mr GS » Fr Jan 15, 2021 4:40 pm

Ich versuch es mal besser dar zu stellen.

Also:
Beim 2ten Schleifen durchlauf gelange ich zu folgende Werte.
j = 2
i = 0
Stelle in "In" = 0*3+2 also kommt man auf den Wert 2 (im Array dann auf 1, 2ter byte (Element))
Dann geht man immer 3 Schritte weiter und der 3te Wert auf den man dann trifft ist dann 5. 5-1 ist dann der Eigentliche Wert im Array, da ein Array von 0 beginnt, somit 4.
0 Handel ich als 1, lässt sich besser mit rechnen.
Statt 0-39 -> 1-40

Die Werte die man anspringt sind dann folgende am Ende:
...; 35; 38 und dann eben die 41, da aber 41 nicht mehr beschrieben ist in "in/s1" hat man somit ein Leeres Element.
Im Normalfall müsste das Programm dann weiter machen und zum dritten durchlauf gehen. Der erste Wert dabei wäre dann 3tes Element, im Array dann Feld 2, usw.

Nun läuft es aber nicht mehr weiter nach dem zweiten Durchlauf und beendet die Schleife.

Schleifen:

Code: Alles auswählen

for (j = 0; j < n; j++){		                             
for (i = 0; i < (l/n)+1; i++){
Von "in" nach "Out" schreiben:

Code: Alles auswählen

out[index] = in [i*n+j];
index++;

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Problem bei einer Aufgabe in C

Beitrag von Xin » Fr Jan 15, 2021 5:08 pm

Mr GS hat geschrieben:
Fr Jan 15, 2021 4:40 pm

Code: Alles auswählen

for (i = 0; i < (l/n)+1; i++){
l ist 38, l/3 ist 12, 12+1 sind 13. // korrekt
l ist 39, l/3 ist 13, 13+1 sind 14. // falsch, hier sind es aber nur 13 Reihen.
l ist 40, l/3 ist 13, 13+1 sind 14. // korrekt

Versuch mal das:

Code: Alles auswählen

int getRows( int l, int n )
{
    return ( l%n ) ? l/n + 1 : l/n;
}

void skytale(char * in, int n, char * out) 
{
    int l = strlen(in);
    int index = 0;
    int i, j;
    int mod = l%n;

    int rows = getRows( l, n );
    for (j = 0; j < n; j++)
        for (i = 0; i < rows; i++, index++)
            out[index] = in[i*n+j];
}
Den Aufruf packst Du auch beim Dechiffrieren rein:

Code: Alles auswählen

    skytale(s2, getRows(l,n) , s3); // Chiffriere zurueck
Es bleibt das oben beschriebene Problem: Wenn das zu verschlüsselnde Wort zu nicht passt, ist das Problem meiner Meinung nach nicht ausreichend definiert.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Mr GS
Beiträge: 5
Registriert: Di Jan 12, 2021 5:38 pm

Re: Problem bei einer Aufgabe in C

Beitrag von Mr GS » Fr Jan 15, 2021 5:43 pm

Habs jetzt.
Durch die Ratschläge hab ich es geschafft das Programm so auf zu bauen das es funktioniert.

Vielen Dank für die Hilfe :)
Hat länger gebraucht als gedacht, aber wie heißt es so schön, der Weg ist das Ziel.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8859
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Problem bei einer Aufgabe in C

Beitrag von Xin » Fr Jan 15, 2021 6:26 pm

Mr GS hat geschrieben:
Fr Jan 15, 2021 5:43 pm
Hat länger gebraucht als gedacht, aber wie heißt es so schön, der Weg ist das Ziel.
Programmieren lernt man nicht durch Programmieren, sondern durch Debuggen.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Antworten