[C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

wegen von hinten vs. von vorne (A4B3C8DEAB3D8):
von hinten muss ich erst das leerzeichen um 6 verschieben -> 1
dann die 7 restlichen D's schreiben (dabei die 8 überschreiben)
dann diese 8 D's 1 nach hinten schieben um platz für die B's zu machen -> 1+8 verschiebungen = 9
die 2 B's schreiben (die 3 dabei überschreiben)
A, E und D müssen nich verschoben werden
dann 8 D's, 3 B's, A, E und D 7 nach hinten schieben, um den C's platz zu machen -> 9+8+3+1+1+1 = 23
die 7 C's schreiben (die 8 dabei überschreiben)
dann 8 D's, 3 B's, A, E, D und 8 C's 1 nach hinten schieben, um den B's platz zu machen -> 23+8+3+1+1+1+8 = 45
die 2 B's schreiben (die 3 dabei überschreiben)
und zu guter letzt 8 D's, 3 B's, A, E, D, 8 C's und 3 B's um 2 verschieben für die A's -> 45+8+3+1+1+1+8+3 = 70

wir haben also von hinten her 70 verschiebungen durchzuführen (bei diesem winzigen schnipsel - an ne komplette datei will ich garnich denken :P). jetz mal, wenn man von vorne an die sache ran geht (wieder A4B3C8DEAB3D8):
B3C8DEAB3D8\0 um 2 nach hinten verschieben -> 12 verschiebungen
C8DEAB3D8\0 um 1 nach hinten verschieben -> 12+10 = 22
DEAB3D8\0 um 6 nach hinten verschieben -> 22+8 = 30
für DEA -> brauch nix verschoben zu werden
D8\0 um 1 nach hinten verschieben -> 30+3 = 33

fertig. nun kann man noch die \0 am ende ignorieren und erst am ende schreiben, da spart man beim ersten bsp eine verschiebung - also bleiben 69 - und beim 2. spart man sich 4 - reduziert sich also auf 29. stehen also 69 verschiebungen 29 gegenüber. ne reduktion um gerademal 100-(29*100/69) = rund 58% ;) performancegewinn in der region is glaube nich zu verachten :P
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Ok, jetzt glaub ich's dir (:fresse: :D), aber mir ist das dann doch zu kompliziert mit der Pointer-Herumzeigerei und Verschieberei beim von-vorne-Anfangen (ohne, dass ich was überschreibe, das ich erst noch auswerten muss). ;)

Habe jetzt meine Decodier-Funktion noch einmal neu geschrieben und auch den restlichen Code optimiert. Bin jetzt auch zu 99 % fertig. Mir bleibt nur ein kleines Problem: Ich komme beim von-hinten-Ansatz vorne um 1 über die Feldgrenze hinaus (für's allererste A), deswegen meckert er (quasi "Index -1"). Das muss ich noch lösen ...

Capture.JPG

[EDIT]
Hab's! Das j in der Schleife hat zu viel Druck gemacht von hinten (<-- was für eine Ausdrucksweise). :D
j=0; j<count; j++ und alles passt.
Code:
#include <stdio.h>

int checkLength(char *s) {
    int length=0;

    while (*(s+length)!='\0') {
        length++;
    }

    return length;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, count=0, length=checkLength(s);
    double ratio=0.0;

    [COLOR=seagreen]/* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                *(s+k+1)=(char)(j-count)+48; [COLOR=seagreen]/* ... und füge immer einen Index weiter das berechnete Vorkommen ein. */                k+=2; [COLOR=seagreen]/* Dann springe 2 Felder weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                count=j;
                ratio=(double)k; [COLOR=seagreen]/* ratio enthält am Ende der Schleife die Länge der Codierung. */                *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */            }            
        }
        i++;
        j++;
    }

    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, count=0, length=0;

    [COLOR=seagreen]/* Ermittle Länge des originalen Strings: */    while (*(s+i)!='\0') {
        if (*(s+i+1)>=50 && *(s+i+1)<=57) {
            count=(*(s+i+1)-48);
            i+=2;
            length+=count;
        } else {
            i++;
            length++;
        }
    }
    
    [COLOR=seagreen]/* Decodieren des codierten Strings: */    i=checkLength(s);
    count=0;
    *(s+length)='\0';
    while (i>0) {
        if (*(s+i)>=50 && *(s+i)<=57) {
            count=(*(s+i)-48);
            for (j=0; j<count; j++) {
                *(s+(length-j))=*(s+(i-1));
            }
            length-=count;
            i-=2;
        } else {
            *(s+(length-1))=*(s+i);
            length--;
            i--;
        }
    }
    
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */ 

    return 0;
}

int main(void) {
    char s[] = "AAAABBBCCCCCCCCDEABBBBDDDDDDDD";
    int i=0;

   [COLOR=seagreen] /* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
Jetzt kommt die Feuerprobe für den Code: Muss das Ganze jetzt noch schnell auf "Parameter-an-main-übergeben" (argc, *argv[]) umschreiben und dann werden wir sehen, ob's wirklich für jeden String (mit Buchstabenvorkommen zwischen 0 und 9) geht. :)

[EDIT2]
Habe gerade noch einen kleinen Fehler bei den einzelnen Buchstaben entdeckt. Der muss noch raus ...
So, jetzt passt's:
Code:
*(s+length)=*(s+i);
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

** FERTIG **

Und es funktioniert tatsächlich für alles im Rahmen von 0 bis 9. :daumen:
Code:
#include <stdio.h>

int checkLength(char *s) {
    int length=0;

    while (*(s+length)!='\0') {
        length++;
    }

    return length;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, count=0, length=checkLength(s);
    double ratio=0.0;

    [COLOR=seagreen]/* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                *(s+k+1)=(char)(j-count)+48; [COLOR=seagreen]/* ... und füge immer einen Index weiter das berechnete Vorkommen ein. */                k+=2; [COLOR=seagreen]/* Dann springe 2 Felder weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                count=j;
                ratio=(double)k; [COLOR=seagreen]/* ratio enthält am Ende der Schleife die Länge der Codierung. */                *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */            }            
        }
        i++;
        j++;
    }

    printf("%s", s);[COLOR=seagreen] /* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, count=0, length=0;

   [COLOR=seagreen] /* Ermittle Länge des originalen Strings: */    while (*(s+i)!='\0') {
        if (*(s+i+1)>=50 && *(s+i+1)<=57) {
            count=(*(s+i+1)-48);
            i+=2;
            length+=count;
        } else {
            i++;
            length++;
        }
    }
    
    [COLOR=seagreen]/* Decodieren des codierten Strings: */    i=checkLength(s); [COLOR=seagreen]/* i = Länge des codierten Strings. */    count=0;
    *(s+length)='\0';[COLOR=seagreen] /* length = Länge des Original-Strings. */    while (i>0) { [COLOR=seagreen]/* Es muss von hinten mit dem Überschreiben begonnen werden, um nicht was zu überschreiben, das noch ausgewertet werden muss. */        if (*(s+i)>=50 && *(s+i)<=57) { [COLOR=seagreen]/* Überprüfen auf Zahlen. */            count=(*(s+i)-48); [COLOR=seagreen]/* Wenn gefunden, wird Zahl in count gespeichert. */            for (j=0; j<count; j++) {
                *(s+(length-j))=*(s+(i-1));[COLOR=seagreen] /* Überschreiben der Feldelements mit dem ersten von hinten gefundenen Buchstaben entsprechend seiner Anzahl. */            }
            length-=count; [COLOR=seagreen]/* Länge reduziert sich um Anzahl der geschriebenen Buchstaben (bei Mehrfachvorkommen) */            i-=2; [COLOR=seagreen]/* Ein Buchstabe und seine Zahl wurde ausgewertet; überspringe sie also. */        } else {
            *(s+length)=*(s+i); [COLOR=seagreen]/* Bei Einfachvorkommen, einfache Zuweisung des Buchstabens. */            length--;[COLOR=seagreen] /* Länge und Zähler reduzieren sich um 1. */            i--;
        }
    }
    
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(int argc, char *argv[]) {
    char *s = argv[1];
    int i=0;

   [COLOR=seagreen] /* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
^^ Witzig nur, dass jetzt argv[1] eigentlich wieder in *s (man beachte den Stern) gespeichert wird und wir dann trotzdem problemlos damit arbeiten können.

-------------------------------
Bleibt nur noch eine allerletzte Aufgabe, dann hätten wir alles durchprogrammiert, was ich an Übungs-Material hier habe ... ;)

Capture.JPG

^^ Hier das Problem, dass ich mit der Imaginärzahl, oder wie auch immer i in Mathe heißt, gar nichts anfangen kann. Das stand wohl nicht auf dem Lehrplan des Gymnasiums, das ich vor Jahren besucht habe?!
Und wenn mit Datenstruktur "typedef struct {} Name;" gemeint ist, dann meine Frage: für was? Soll ich Werte einlesen und da rein speichern, oder ist das dann für die Rechenergebnisse der Funktionen?

PS: Werde selber erst morgen mit dem neuen Beispiel anfangen, also heute bloß kein Stress mehr. :D
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Zu komplexen Zahlen allgemein: Komplexe Zahl
Die Rechenregeln werden für dich interessant sein, wenn du die implementieren sollst.

Zur Struktur: Da eine komplexe Zahl im wesentlich aus zwei Komponenten besteht (Real- und Imaginärteil), macht es Sinn diese zusammen in einer Struktur zu speichern. Eine Variable vom Typ dieser Struktur entspricht dann genau einer komplexen Zahl. Damit kannst du dan rumrechnen oder sonstwas machen ^^
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Bin gerade dabei, mich da einzulesen. Ich habe auch schon vorsichtig angefangen, das Grundgerüst für die Aufgabe zu erstellen, allerdings habe ich starke Zweifel, dass die "entsprechende Datenstruktur" (wenn sie denn überhaupt so ausschauen soll, wie bei mir) global deklariert werden muss. Mache ich es allerdings lokal in der main, unterwellt er mir im VS komplex_t *k rot ...
Code:
#include <stdio.h>

[COLOR=royalblue][B]typedef struct komplex_t {
    double a;
    double b;
};[/B]
void print_komplex(komplex_t *k) {

}

komplex_t add_k(komplex_t *k1, komplex_t *k2) {

}

komplex_t sub_k(komplex_t *k1, komplex_t *k2) {

}

komplex_t mul_k(komplex_t *k1, komplex_t *k2) {

}

komplex_t div_k(komplex_t *k1, komplex_t *k2) {

}

int main(void) {

    return 0;
}
In der main()-Funktion sollen verschiedene komplexe Zahlen (z.B. 0 0, 1.23 0, 0 3.14, -2.34 1, -3 4, 1
3, 1 1) definiert und damit die geschriebenen Funktionen getestet werden.
Ob das jetzt heißen soll, dass ich in der main 7 structs mit dem jeweiligen Zahlenpaar als Inhalt anlegen soll, bin ich mir auch noch nicht sicher ...

Der Zeiger *k zeigt auf ein Element aus dem Inhalt von komplex_t (das ein struct sein soll?!) und nicht auf das ganze struct, oder? Habe noch nie mit sowas gearbeitet, also sorry, wenn die Fragen aus eurer Sicht dumm klingen.
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Da du mit dem struct einen neuen Datentyp einführen willst, musst du das schon mehr oder weniger "global" bekannt machen.

Code:
/* ist jetzt ohne typedef, mit typedef sparst du dir das "struct" wenn du eine Variable anlegen wills */
struct MyStruct
{
    int v1;
    int v2;
    double v3;
};

void fillStruct(struct MyStruct *ps)
{
    ps->v1 = 10;
    ps->v2 = 100;
    ps->v3 = -0.5f;
}

int main(int argc, char *argv[])
{
    /* Variablen anlegen */
    struct MyStruct s1, s2;
   
    fillStruct(&s1);
    fillStruct(&s2);

    return 0;
}
Ist jetzt nicht so ein mega sinnvolles Beispiel ^^
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Habe jetzt mal ein Bischen recherchiert und dabei rausgefunden, dass das Befüllen des structs komplex_t auch einfach mit dem . oder dem -> Operator gehen müsste. Was ich halt nicht verstehe, ist, auf was genau der Zeiger *k zeigen soll ...

[EDIT]
Gerade rausgefunden: Die Wertzuweisung und Ausgabe würde so funktionieren:
Code:
#include <stdio.h>

typedef struct {
    double a;
    double b;
} komplex_t;

void print_komplex(komplex_t *k) {
    printf("( %.2lf %.2lf )\n", *k, *k);
}

komplex_t add_k(komplex_t *k1, komplex_t *k2) {

}

komplex_t sub_k(komplex_t *k1, komplex_t *k2) {

}

komplex_t mul_k(komplex_t *k1, komplex_t *k2) {
    
}

komplex_t div_k(komplex_t *k1, komplex_t *k2) {

}

int main(void) {
    komplex_t *k;
    komplex_t komplex_1 = { 1.23, 0.0 };
    k=&komplex_1;

    print_komplex(k);

    return 0;
}
Jetzt bin ich aber noch mehr verwirrt: Der Zeiger *k müsste jetzt eigentlich auf die gesamte Struktur komplex_1 (ist ja vom Aufbau ident mit komplex_t) zeigen. Wieso muss ich dann aber im printf 2 mal den Zeiger einsetzen, um den gesamten Strukturinhalt ausgeben zu lassen? Und v.a.: Wieso bekomme ich die 2 verschiedenen Werte über den selben Zeiger (der ja nach meiner Logik ohnehin auf das gesamte struct zeigen sollte)? :huh:
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

na deine struct is nen selbst geschriebener datentyp wie int zum bsp. du kannst nun also variablen vom typ deines structs anlegen. und auf genau diese zeigt dann der zeiger.
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Habe vor 3 Minuten eben genau das rausgefunden (siehe aktualisierter Code im vorigen Posting). Dass der Zeiger auf die erstellte Variable (die ja vom Aufbau wie das struct ausschauen müsste) zeigen sollte, hätte auch ich mir erwartet, aber anscheinend zeigt er auf alle Werte im struct (anstatt auf das gesamte struct)?! --> bitte auch meine Fragen im vorigen Posting beachten ...

[EDIT]
So geht's wohl auch:
Code:
void print_komplex(komplex_t *k) {
    printf("( %.2lf %.2lf )\n", *k);
}
Nur wenn der eine Zeiger *k wirklich auf das gesamte struct zeigt, wie soll ich dann anhand von *k zwischen den beiden Werten unterscheiden? Ich muss ja beispielsweise eine Überprüfen einbauen, ob der Real- od. der Imaginärteil gleich 0 ist. Nur if (*(k+0)==0 || *(k+1)==0) { spielt's nicht. Da meckert der Compiler ...

BTW: Die 4 Rechenfunktionen habe alle 2 Zeiger in der Parameterdeklarationsliste. Nur, wenn eh jeder der beiden Zeiger auf das gesamte struct zeigt, wofür brauche ich dann 2?
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Habe vor 3 Minuten eben genau das rausgefunden (siehe aktualisierter Code im vorigen Posting). Dass der Zeiger auf die erstellte Variable (die ja vom Aufbau wie das struct ausschauen müsste) zeigen sollte, hätte auch ich mir erwartet, aber anscheinend zeigt er auf alle Werte im struct (anstatt auf das gesamte struct)?! --> bitte auch meine Fragen im vorigen Posting beachten ...

[EDIT]
So geht's wohl auch:
Code:
void print_komplex(komplex_t *k) {
    printf("( %.2lf %.2lf )\n", *k);
}
Nur wenn der eine Zeiger *k wirklich auf das gesamte struct zeigt, wie soll ich dann anhand von *k zwischen den beiden Werten unterscheiden? Ich muss ja beispielsweise eine Überprüfen einbauen, ob der Real- od. der Imaginärteil gleich 0 ist. Nur if (*(k+0)==0 || *(k+1)==0) { spielt's nicht. Da meckert der Compiler ...

BTW: Die 4 Rechenfunktionen habe alle 2 Zeiger in der Parameterdeklarationsliste. Nur, wenn eh jeder der beiden Zeiger auf das gesamte struct zeigt, wofür brauche ich dann 2?

Ich glaube, du solltest dir erstmal das hier Galileo Computing :: C von A bis Z – 15 Strukturen (bzw halt was ähnliches) durchlesen - hier structs zu erklären würde dann doch den Rahmen sprengen...

Und falls das
Code:
printf("( %.2lf %.2lf )\n", *k);
wirklich funktioniert (was ich nichteinmal komplett bestreiten möchte), dann bezweifle ich, dass es das tut was du vermutest das es tut - aufjedenfall ist das ganz arg doll böse und das solltest vermeiden.
Richtig wäre sowas in der Art (*k).real oder (schöner) k->real (-> dereferenziert erst und greift dann auf das angegebene Element zu, steht aber alles in obigem Link). Andererseits meine ich, dass ich mir damit schön das ganze Programm abschiesse - printf erwartet eben zwei Argumente. In diesem Kontext ist übrigens auch das http://en.wikipedia.org/wiki/Stdarg.h interessant, falls nicht bekannt.
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Den Galileo Computing Artikel habe ich gestern schon überflogen (brauche ja erst einmal nur die korrekte Syntax. An die Semantik geht's wenn alle nötigen Variablen definiert sind).

Ja, das printf, das du zitierst, hatte wirklich genau das gemacht, was ich mir erwartet habe: Der Zeiger *k zeigt auf struct komplex_t, dessen beide Werte direkt hintereinander im Speicher liegen und somit "glücklicherweise" auch hintereinander ausgegeben wurden. ;)
Dass das "doll böse" ist, glaube ich dir aber sofort.

Habe jetzt die Ausgabe so umgeschrieben:
Code:
printf("( %.2lf %.2lf )\n", (*k).a, (*k).b);
Ich glaube jetzt auch, verstanden zu haben, warum die Rechenfunktionen 2 Zeiger brauchen, mit denen ich ja auf insg. 4 Elemente zugreifen kann: Ich habe nämlich ursprünglich angenommen, dass 0 und 0, oder 1.23 und 0 usw. bereits jeweils ein Zahlenpaar ist, mit dem ich rechnen soll. Es dürfte aber vielmehr so sein, dass z.B. 0 und 0 eine komplexe Zahl darstellt, wobei der erste 0er der Real- und der zweite der Imaginärteil ist. Diese komplexe Zahl soll dann mit einer anderen, z.B. 1.23 0, addiert/subtrahiert/whatever werden. --> Also brauche ich im Endeffekt 2 structs und jedes davon bekommt 2 Variablen. --> 2 Zeiger, jeder zeigt auf ein struct ...

^^ Habe ich die Angabe jetzt endlich gecheckt, oder nur auf eine ganz neue Art falsch interpretiert? :ugly: ;)

Wenn meine Annahme hier stimmt, müsste jedenfalls sowas in die Richtung hinkommen:
Code:
int main(void) {
    komplex_t *k1, *k2;
    komplex_t komplex_1 = { 1.23, 0 };
    komplex_t komplex_2 = { 0, 0 };
    k1=&komplex_1;
    k2=&komplex_2;

    print_komplex(k1);

    return 0;
}
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Aber so greift man doch net auf structs zu :ugly: Dafür gibt es den Punkt- bzw. Pfeil-Operator.

Code:
/* normale Variable (kein Zeiger) */
komplex_t k1;

k1.a = 1.0f;
k1.b = 0.0f;

/* Zeiger auf k1 */
komplex_t k2 = &k1;
k2->a = 2.0f;
k2->b = 1.0f;

/* k1 enthält jetzt a = 2.0f und b = 1.0f */
printf("a = %f, b = %f\n", k1.a, k1.b);
printf("a = %f, b = %f\n", k2->a, k2->b);
Zum Thema Zeiger: Ein Zeiger zeigt auf einen Speicherbereich, genauer gesagt meist auf dessen Startadresse. Dein komplex struct besteht aus zwei Feldern, die irgendwo im Speicher liegen. In aktuellen Fall ist es (wahrscheinlich!) sogar so, dass die beiden Felder a und b direkt hintereinander liegen (kommt später). Ein Zeiger komplex_t *k zeigt also auf den Beginn deines structs (erstes byte von a), und wenn die Felder alle direkt hintereinander liegen, kann man den Zeiger auch wie ein array abarbeiten, um an die einzelnen Elemente zu kommem. Schön ist das nicht, aber es funktioniert unter Umständen (siehe dein printf mit *k).

Kommen wir nun zu dem möglichen Problem. Wie ich sagte, müssen die Felder nicht zusammenliegen. Das kommt daher, dass der Compiler - sofern man es ihm nicht verbietet - die Felder im struct so anordnet, dass sie für die CPU "günstig" liegen. Dazu fügt er ggf. sogenannte padding bytes zwischen den einzelnen Feldern ein, dein struct wird also größer. Das hat den Hintergrund, dass die CPU bestimmte Speicheradressen sehr schnell ansprechen kann (bspw. vielfaches von 4 Byte, also alles was durch 4 glatt teilbar ist). Was nicht auf dieser Byte boundary liegt, dauert viel länger. Es soll sogar Architekturen gegeben haben (oder noch geben), bei denen das genau so funktionieren MUSS. Wenn dann eine Adresse angefordert wird, die nicht auf einer byte boundary liegt, semmelt dir das Program einfach ab!

Das ist auch der Grund, warum man unbehandelte structs nicht einfach so mittels "full write" z. B. in eine Datei schreiben sollte:
Code:
struct MyStruct bla;
/* so nicht */
fwrite(&bla, sizeof(bla), ...);

/* sondern jedes Feld einzeln oder padding explizit abstellen */
So werden nämlich die ganzen padding bytes, falls welche vorhanden sind, mit in die Datei geschrieben! Und wenn die Datei dann mit einem anderen Programm (anderer Compiler / Einstellungen) gelesen werden soll, knallt es wenn du Pech hast. Wenn dein Programm nur auf einem System laufen soll, kannst du es zwar so machen, aber besonders schön ist das nicht.

Edit:
Wenn du einen Zeiger übergeben musst, kannst du dir das zusätzliche definieren einer Zeigervariable sparen.
Code:
komplex_t k1;

/* Adress-Operator & liefert einen Zeiger */
print_komplex(&k1);
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ich glaube jetzt auch, verstanden zu haben, warum die Rechenfunktionen 2 Zeiger brauchen, mit denen ich ja auf insg. 4 Elemente zugreifen kann: Ich habe nämlich ursprünglich angenommen, dass 0 und 0, oder 1.23 und 0 usw. bereits jeweils ein Zahlenpaar ist, mit dem ich rechnen soll. Es dürfte aber vielmehr so sein, dass z.B. 0 und 0 eine komplexe Zahl darstellt, wobei der erste 0er der Real- und der zweite der Imaginärteil ist. Diese komplexe Zahl soll dann mit einer anderen, z.B. 1.23 0, addiert/subtrahiert/whatever werden. --> Also brauche ich im Endeffekt 2 structs und jedes davon bekommt 2 Variablen. --> 2 Zeiger, jeder zeigt auf ein struct ...
es scheint ja schon am grundlegenden gescheitert zu sein :P kennst du vektoren? ein 2D vektor V, der an der position 2|3 im kooridnatensystem steht, hat also die teile x=2 und y=3. der ganze vektor beinhaltet aber eben beide teile.

Code:
struct myVector {
     double x;
     double y;
}

myVector addVectors(myVector a, myVectorB b) {
      myVector c;
      c.x = a.x + b.x;
      c.y = a.y + b.y;
     return c;
}

double distance(myVector a, myVectorB b) {
      myVector c = addVectors(a, b);
      return sqrt(c.x * c.x + c.y * c.y); // die wurzel der summe der quadrierten einzelteile
}

void main(void) {
      myVector A;
      A.x = 2;
      A.y = 3;
      myVector B;
      A.x = 5;
      A.y = -1;

      printf("distance: %6.2f", distance(A, B));
}
eine normale int variable kann nur eine zahl speichern, für nen vektor brauch man aber eben 2 (oder mehr) variablen, die irgendwie zusammen gehören. dafür gibts structs. da hast du deine ganzen variablen unter einem dach. ein zeiger auf ne struct zeigt dann eben auf das ganze paket. über den zeiger kannste dann wieder auf die einzelteile des pakets zugreifen. oben hab ich mal paar simple rechnungen mit vektoren gebastelt. wie sich das nu im detail bei komplexen zahlen verhält, weis ich jetz auch ned, aber bingo hat ja scho mit links um sich geworfen ^^ damit sollte es eigentlich sehr einfach sein, das ganze dann umzusetzen. variablen vom typ deiner struct erstellen, als zeiger übergeben (& greift auf die adresse einer variablen zu, ergo das, was ein zeiger erwartet) und in den funktionen einfach damit arbeiten (-> operator bla. wurde ja schon schön erklärt ^^). das schlimmste sin dann ggf die rechenoperationen, aber dazu haste ja auch scho nen link erhalten :)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Danke für alle Tipps! :daumen:

Habe jetzt mal die Ausgabefunktion entsprechend der Angabe gestaltet (das mit den Vorzeichen und Blanks fehlt noch, ich weiß) und die ersten 3 Rechenfunktionen gebastelt:
Code:
#include <stdio.h>

typedef struct {
    double real;
    double imaginary;
} komplex_t;

void print_komplex(komplex_t *k) {
    if (k->real==0 && k->imaginary!=0) {
        printf("( %.2lfi )\n", k->imaginary);
    } else if (k->imaginary==0 && k->real!=0) {
        printf("( %.2lf )\n", k->real);
    } else if (k->real==0 && k->imaginary==0) {
        printf("( %.0lf )\n", 0);
    } else if (k->real!=0 && k->imaginary!=0) {
        printf("( %.2lf %.2lfi )\n", k->real, k->imaginary);
    }
}

komplex_t add_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real+k2->real;
    k3->imaginary=k1->imaginary+k2->imaginary;

    return *k3;
}

komplex_t sub_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real-k2->real;
    k3->imaginary=k1->imaginary-k2->imaginary;

    return *k3;
}

komplex_t mul_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real*k2->real-k1->imaginary*k2->imaginary;
    k3->imaginary=k1->real*k2->imaginary+k1->imaginary*k2->real;

    return *k3;
}

komplex_t div_k(komplex_t *k1, komplex_t *k2) {

}

int main(void) {
    komplex_t *k1, *k2, *k3;
    komplex_t komplex_1 = { 1.23, 0 };
    komplex_t komplex_2 = { 0, 0 };
    komplex_t result = { 0, 0 };
    k1=&komplex_1;
    k2=&komplex_2;
    k3=&result;
    
    *k3=add_k(k1, k2);
    print_komplex(k3);
    
    *k3=sub_k(k1, k2);
    print_komplex(k3);

    *k3=mul_k(k1, k2);
    print_komplex(k3);

    return 0;
}
Funktioniert auch bereits, allerdings sieht man es in dem Fall nicht wirklich, weil z.B. 1.23 + 0 ja wieder 1.23 ergibt (ergo, Ausgabe bleibt gleich). Wenn man aber testweise in der main für den Realteil von komplex_2 3 einsetzt, wird wirklich 4.23 ausgegeben. :)

Jetzt geht's an die Multiplikation ...

^^ Wenn das dann auch noch erledigt ist, muss ich mir nur noch was Schlaues überlegen, damit bei vollständigen komplexen Zahlen zwischen den Zahlen und ihren zugehörigen Rechenzeichen jeweils ein Leerzeichen ist. Siehe:
Eine vollständige komplexe Zahl (weder Real- noch Imaginärteil sind 0) sollte wie folgt ausgegeben
werden: ( - 5.34 + 2.30i ) oder ( 2.34 + 1.00i )
[EDIT]
Hätte den Code jetzt soweit fertig, dass die Berechnungen alle ordentlich funktionieren. Habe zum Testen auch brauchbare Zahlen eingesetzt:
Code:
#include <stdio.h>

typedef struct {
    double real;
    double imaginary;
} komplex_t;

void print_komplex(komplex_t *k) {
    if (k->real==0 && k->imaginary!=0) {
        printf("( %.2lfi )\n", k->imaginary);
    } else if (k->imaginary==0 && k->real!=0) {
        printf("( %.2lf )\n", k->real);
    } else if (k->real==0 && k->imaginary==0) {
        printf("( %.0lf )\n", 0);
    } else if (k->real!=0 && k->imaginary!=0) {
        printf("( %.2lf %.2lfi )\n", k->real, k->imaginary);
    }
}

komplex_t add_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real+k2->real;
    k3->imaginary=k1->imaginary+k2->imaginary;

    return *k3;
}

komplex_t sub_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real-k2->real;
    k3->imaginary=k1->imaginary-k2->imaginary;

    return *k3;
}

komplex_t mul_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=k1->real*k2->real-k1->imaginary*k2->imaginary;
    k3->imaginary=k1->real*k2->imaginary+k1->imaginary*k2->real;

    return *k3;
}

komplex_t div_k(komplex_t *k1, komplex_t *k2) {
    komplex_t *k3;
    komplex_t result = { 0, 0 };
    k3=&result;

    k3->real=((k1->real*k2->real+k1->imaginary*k2->imaginary)/(k2->real*k2->real+k2->imaginary*k2->imaginary));
    k3->imaginary=((k1->imaginary*k2->real-k1->real*k2->imaginary)/(k2->real*k2->real+k2->imaginary*k2->imaginary));

    return *k3;
}

int main(void) {
    komplex_t *k1, *k2, *k3;
    komplex_t komplex_1 = { 1.23, 2 };
    komplex_t komplex_2 = { 1, 3.1 };
    komplex_t result = { 0, 0 };
    k1=&komplex_1;
    k2=&komplex_2;
    k3=&result;
    
    *k3=add_k(k1, k2);
    print_komplex(k3);
    
    *k3=sub_k(k1, k2);
    print_komplex(k3);

    *k3=mul_k(k1, k2);
    print_komplex(k3);

    *k3=div_k(k1, k2);
    print_komplex(k3);

    return 0;
}
Jetzt halt noch das mit den Leerzeichen ...
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

So, die Ausgabe entspricht jetzt den Vorgaben, nur ob's der Code auch tut?! :fresse: --> Siehe void print ...
^^ Erfüllt mein Ansatz die Vorgaben, oder hätte das ...
(achte auch auf die konkrete Verwendung von Blanks!)
... anders realisiert werden müssen?
Code:
#include <stdio.h>

typedef struct {
    float real;
    float imaginary;
} komplex_t;

void print_komplex(komplex_t *k) {
    if (k->real==0 && k->imaginary!=0) {
        printf("( %.2fi )\n", k->imaginary);
    } else if (k->imaginary==0 && k->real!=0) {
        printf("( %.2f )\n", k->real);
    } else if (k->real==0 && k->imaginary==0) {
        printf("( %.0f )\n", 0);
    } else if (k->real!=0 && k->imaginary!=0) {
       [COLOR=royalblue][B] if (k->real>0 && k->imaginary>0) {[/B][COLOR=seagreen] /* + + */[B]
            printf("( %.2f + %.2fi )\n", k->real, k->imaginary);
        } else if (k->real<0 && k->imaginary<0) { [/B][COLOR=seagreen]/* - - */
           [COLOR=royalblue][B] k->real*=-1;[/B][B]
            k->imaginary*=-1;
            printf("( - %.2f - %.2fi )\n", k->real, k->imaginary); 
        } else if (k->real<0 && k->imaginary>0) { [/B][COLOR=seagreen]/* - + */[B]
            k->real*=-1;
            printf("( - %.2f + %.2fi )\n", k->real, k->imaginary);
        } else if (k->real>0 && k->imaginary<0) { [/B][COLOR=seagreen]/* + - */[B]
            k->imaginary*=-1;
            printf("( %.2f - %.2fi )\n", k->real, k->imaginary);
        }[/B]    }
}

komplex_t add_k(komplex_t *k1, komplex_t *k2) {
    komplex_t res = { k1->real+k2->real, k1->imaginary+k2->imaginary };

    return res;
}

komplex_t sub_k(komplex_t *k1, komplex_t *k2) {
    komplex_t res = { k1->real-k2->real, k1->imaginary-k2->imaginary };

    return res;
}

komplex_t mul_k(komplex_t *k1, komplex_t *k2) {    
    komplex_t res = { k1->real*k2->real-k1->imaginary*k2->imaginary, k1->real*k2->imaginary+k1->imaginary*k2->real };

    return res;
}
komplex_t div_k(komplex_t *k1, komplex_t *k2) {
    komplex_t res = { (k1->real*k2->real+k1->imaginary*k2->imaginary)/(k2->real*k2->real+k2->imaginary*k2->imaginary), 
                      (k1->imaginary*k2->real-k1->real*k2->imaginary)/(k2->real*k2->real+k2->imaginary*k2->imaginary) };

    return res;
}

int main(void) {
    komplex_t *res;
    komplex_t komplex_1 = { 0, 0 };
    komplex_t komplex_2 = { 1.23, 0 };
    komplex_t komplex_3 = { 0, 3.14 };
    komplex_t komplex_4 = { -2.34, 1 };
    komplex_t komplex_5 = { -3, 4 };
    komplex_t komplex_6 = { 1, 3 };
    komplex_t komplex_7 = { 1, 1 };
    komplex_t result = { 0, 0 };
    res=&result;
    
    [COLOR=seagreen]/* Additionen */    *res=add_k(&komplex_1, &komplex_2);
    print_komplex(res);
    *res=add_k(&komplex_3, &komplex_4);
    print_komplex(res);
    
    [COLOR=seagreen]/* Subtraktionen */    *res=sub_k(&komplex_3, &komplex_4);
    print_komplex(res);
    *res=sub_k(&komplex_5, &komplex_6);
    print_komplex(res);

    [COLOR=seagreen]/* Multiplikationen */    *res=mul_k(&komplex_5, &komplex_7);
    print_komplex(res);
    *res=mul_k(&komplex_6, &komplex_7);
    print_komplex(res);

    [COLOR=seagreen]/* Divisionen */    *res=div_k(&komplex_1, &komplex_2);
    print_komplex(res);
    *res=div_k(&komplex_4, &komplex_6);
    print_komplex(res);

    return 0;
}
BTW: Es heißt ja auch, man soll das Programm mit allen in der Angabe angegebenen komplexen Zahlen testen. Dann hätte ich ja so eine lange ^^ main. Oder geht das auch kürzer?

Habe schon alles wegoptimiert, was mir unnötig vorkam. Geht noch mehr?
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Die Fragen im letzten Posting bezgl. der korrekten Umsetzung der Vorgaben aus der Angabe gelten immer noch ...

Jetzt gerade bräuchte ich aber schnell den Hinweis, warum folgendes Programm auch bei Schaltjahren sagt, dass ein Februar mit 29 Tagen ungültig ist:
Code:
#include <stdio.h>

int isLeapYear(short year) {
    if (year%4==0 && year%400==0 && year%100!=0) {
        return 1;
    }

    return 0;
}

int checkDate(short day, short month, short year) {
    if (day<=15 && month<=10 && year<=1582) { [COLOR=seagreen]/* Gregorianische Zeitrechnung: Datum muss nach diesem Tag sein. */        return 0;
    } else if (month<1 || month>12) { [COLOR=seagreen]/* Es gibt nur 12 Monate. */        return 0;
    } else if ((month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) && (day<1 || day>31)) { [COLOR=seagreen]/* All diese Monate müssen zwischen 1 und 31 Tage haben. */        return 0;
    } else if ((month==4 || month==6 || month==9 || month==11) && (day<1 || day>30)) { [COLOR=seagreen]/* All diese Monate müssen zwischen 1 und 30 Tage haben. */        return 0;
    } [COLOR=royalblue][B]else if (month==2 && isLeapYear(year)==0 && (day<1 || day>28)) { [/B][COLOR=seagreen]/* Ein Februar in einem Nicht-Schaltjahr muss zwischen 1 und 28 Tage haben. */[B]
        return 0;
    } else if (month==2 && isLeapYear(year)==1 && (day<1 || day>29)) { [/B][COLOR=seagreen]/* Ein Februar in einem Schaltjahr muss zwischen 1 und 29 Tage haben. */[B]
        return 0;
    }[/B]
    return 1;
}

int main(void) {
    short day=0, month=0, year=0;

    printf("Please enter a day, a month and a year: ");
    scanf("%hu %hu %hu", &day, &month, &year); 
    if (checkDate(day, month, year)==1) {
        printf("The date you entered is valid.\n");
    } else {
        printf("You entered an invalid date!\n");
    }

    return 0;
}
Ich bin schon seit 2 Stunden am Durchprobieren aller möglichen else-if Varianten und &&- bzw. ||-Verknüpfungen, aber ich komme einfach nicht drauf. Es läuft immer darauf hinaus, dass eben ein Schaltjahr-Februar mit 29 Tagen ungültig ist, oder jeder Februar mit x-beliebig vielen Tagen gütlig ist. Bei mir im Kopf dreht sich schon alles. Höchstwahrscheinlich handelt es sich eh nur um was Banales, aber ich seh's einfach nicht ...

[EDIT]
Hab's schon rausgefunden. Der Fehler lag nicht, wie zuerst vermutet, in den else-if in der Funktion checkDate(), sondern in isLeapYear(). So funktioniert's:
Code:
int isLeapYear(short year) {
    if [COLOR=royalblue][B]((year%4==0 && year%100!=0) || (year%100!=0 && year%400==0))[/B] {
        return 1;
    }

    return 0;
}
Wer Zeit und Lust hat, dem wäre ich sehr dankbar, wenn wir noch klären könnten, ob ich das mit den Leerzeichen im Komplexe-Zahlen-Beispiel richtig gemacht habe. :)
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Habe jetzt mal aus Interesse probiert, das Lauflängencodierungs-Programm so umzuschreiben, dass es für beliebig viele gleiche Buchstaben hintereinander funktioniert.

[EDIT]
Okay, die Längenermittlung habe ich jetzt in eine eigene Funktion gepackt. Somit kann ich Zahlen verdrehen so viel ich will und die Länge wird trotzdem richtig ermittelt, wenn nur der Funktionsaufruf an der richtigen Stelle erfolgt (was er bei mir ja jetzt tut). :)

Jetzt müsste ich es nur noch schaffen, den 16er und den 12er zu verdrehen, dann könnte ich endlich decodieren. Kann mir da bitte jemand verraten, warum mir nur der 104er verdreht wird, aber dann keine Zahlen >9 mehr (siehe blau markierte Schleife)?
Code:
#include <stdio.h>
#include <math.h>

[COLOR=seagreen]/* Längenermittlung für Strings. */int checkLength(char *s) {
    int i=0, j=0, k=0, count1=0, count2=0, length=0;

    while (*(s+i)!='\0') {
        if (*(s+i+1)>=48 && *(s+i+1)<=57) {[COLOR=seagreen] /* Solange Zahlen gefunden werden, ... */            count1++;[COLOR=seagreen] /* ... erhöhe Zähler. */            for (j=count1, k=(j-1); j>=0; j--, k--) {
                count2+=(k*(int)pow(10., j)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            }
            i+=count2;
            length+=count2; [COLOR=seagreen]/* ... addiere sie zu length. Sonst, ... */        } else {
            i++;
            length++; [COLOR=seagreen]/* ... zähle nur 1 dazu für jeweils einen Buchstaben. */        }
    }

    return length;
}

[COLOR=seagreen]/* 
Funktion calc nötig, um Zahlenstellen in der richtigen Reihenfolge ausgeben lassen zu können 
durch verkleinern der entsprechenden Indexe von *s anhand des Rückgabewertes. 
*/int calcSteps(int num) {
    int temp1=num, temp2=0, count=0;

    while (temp1>0) {
        temp2=temp1%10;
        temp1/=10;
        count++; [COLOR=seagreen]/* Ermittle Anzahl der nötigen Rechenschritte und somit auch die Anzahl der Stellen der Zahl. */    }

    return count;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, temp1=0, temp2=0, count1=0, count2=1, length=checkLength(s);
    double ratio=0.0;

    [COLOR=seagreen]/* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count1)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i);[COLOR=seagreen] /* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count1=j;
            } else {[COLOR=seagreen] /* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben. */                if ((j-count1)>9) { [COLOR=seagreen]/* Vorkommen größer als 9: */                    temp1=(j-count1);
                    while (temp1>0) { [COLOR=seagreen]/* Zerlege (An)Zahl in ihre einzelnen Stellen. */                        temp2=temp1%10;
                        temp1/=10;
                        count2++; [COLOR=seagreen]/* Zähle Rechenschritte mit um Anzahl der nötigen Stellen und somit Indexe zu ermitteln. */                        *(s+k+(calcSteps(temp1)+1))=(char)(temp2+48);[COLOR=seagreen] /* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */                    }
                    k+=count2; [COLOR=seagreen]/* Dann springe entsprechend viele Indexe weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                    count1=j;
                    count2=1;
                } else {[COLOR=seagreen] /* Vorkommen bis 9: */                    *(s+k+1)=(char)((j-count1)+48);
                    k+=2;[COLOR=seagreen] /* Ein Buchstabe und seine Zahl wurden geschrieben. Springe daher 2 Indexe weiter. */                    count1=j;
                }
            }            
        }
        i++;
        j++;
    }
    ratio=(double)k; [COLOR=seagreen]/* ratio enthält am Ende der Schleife die Länge der Codierung. */    *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, temp1=0, temp2=0, count1=0, count2=0, length=checkLength(s);

    [COLOR=seagreen]/* Verdrehen der Zahlen >9, da String später von hinten beginnend ausgewertet wird: */  [COLOR=royalblue][B]  while (*(s+i)!='\0') {
        if (*(s+i+1)>=48 && *(s+i+1)<=57) { 
            j++;
            count1=(*(s+i+1)-48); 
            count2+=(count1*(int)pow(10., j-1)); [/B][COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */[B]
            if ((count2/10)>0) {
                temp1=count2;
            }
            while (temp1>0) { [/B][COLOR=seagreen]/* Zerlege int-Zahl in ihre einzelnen Stellen. */[B]
                temp2=temp1%10;
                temp1/=10;
                *(s+i+(calcSteps(temp1))-1)=(char)(temp2+48); [/B][COLOR=seagreen]/* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */[B]
            }
            i+=count2;
        } else {
            i++;
        }
    }[/B]
    [COLOR=seagreen]/* Decodiere String: */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(void) {
[COLOR=seagreen]//int main(int argc, char *argv[]) {    [COLOR=seagreen]//char *s = argv[1];    char s[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCCCCCCCCCCCCCCCCDEABBBBDDDDDDDDDDDD";
    int i=0;

    /* Kleinbuchstaben in Großbuchstaben umwandeln */
    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
^^ Ich vermute, dass es irgendwie mit dem i+=count2 zusammenhängt. count2 wird ja eine so große Zahl, die weit über der Nullterminierung liegen würde und somit hört die Schleife einfach auf. Für meine Logik müsste ja i+=j, oder von mir aus auch i+=(j+1) hinkommen, aber beide Versionen liefern nur Blödsinn und überschreiben meine Buchstaben ... :ugly:

j zählt jedenfalls, wie viele Ziffern hintereinander stehen bevor wieder ein Buchstabe kommt, und genau so weit müsste ich doch im codierten String weiterspringen?!
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Keiner eine Idee?

[EDIT]
Man staune, aber es ist wahr: Die ganze Invertiererei ist völlig für'n A****, weil durch das Berechnen der int-Gesamtzahl automatisch immer die Stellen verdreht werden! Und um das rauszufinden, habe ich 6 h gebraucht. :klatsch: :D

Bsp: Der Compiler kommt von hinten an die Werte heran und liest --> 2 1, bevor er auf einen Buchstaben trifft. Jetzt sollte man meinen, dass die beiden chars 2 und 1 in einen int-21er umgerechnet werden, den ich dann drehen müsste, um meinen 12er zu erhalten. Aber nein! Die beiden chars werden bereits beim Umrechnen verdreht und raus kommt mein int-12er. :schief:

Tja, jetzt brauche ich also nur die Decodier-Funktion neu zu schreiben. Bin auch schon dabei, aber ein Bisschen hapert es noch. Mal neu überlegen, das Ganze. Tipps auf jeden Fall erwünscht!
Code:
#include <stdio.h>
#include <math.h>

[COLOR=seagreen]/* Längenermittlung für Strings. */int checkLength(char *s) {
    int i=0, j=0, k=0, count1=0, count2=0, length=0;

    while (*(s+i)!='\0') {
        if (*(s+i+1)>=48 && *(s+i+1)<=57) { [COLOR=seagreen]/* Solange Zahlen gefunden werden, ... */            count1++;[COLOR=seagreen] /* ... erhöhe Zähler. */            for (j=count1, k=(j-1); j>=0; j--, k--) {
                count2+=(k*(int)pow(10., j)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            }
            i+=count2;
            length+=count2; [COLOR=seagreen]/* ... addiere sie zu length. Sonst, ... */        } else {
            i++;
            length++; [COLOR=seagreen]/* ... zähle nur 1 dazu für jeweils einen Buchstaben. */        }
    }

    return length;
}

[COLOR=seagreen]/* 
Funktion calc nötig, um Zahlenstellen in der richtigen Reihenfolge ausgeben lassen zu können 
durch verkleinern der entsprechenden Indexe von *s anhand des Rückgabewertes. 
*/int calcSteps(int num) {
    int temp1=num, temp2=0, count=0;

    while (temp1>0) {
        temp2=temp1%10;
        temp1/=10;
        count++; [COLOR=seagreen]/* Ermittle Anzahl der nötigen Rechenschritte und somit auch die Anzahl der Stellen der Zahl. */    }

    return count;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, temp1=0, temp2=0, count1=0, count2=1, length=checkLength(s);
    double ratio=0.0;

   [COLOR=seagreen] /* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count1)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count1=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben. */                if ((j-count1)>9) {[COLOR=seagreen] /* Vorkommen größer als 9: */                    temp1=(j-count1);
                    while (temp1>0) { [COLOR=seagreen]/* Zerlege (An)Zahl in ihre einzelnen Stellen. */                        temp2=temp1%10;
                        temp1/=10;
                        count2++; [COLOR=seagreen]/* Zähle Rechenschritte mit um Anzahl der nötigen Stellen und somit Indexe zu ermitteln. */                        *(s+k+(calcSteps(temp1)+1))=(char)(temp2+48); [COLOR=seagreen]/* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */                    }
                    k+=count2; [COLOR=seagreen]/* Dann springe entsprechend viele Indexe weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                    count1=j;
                    count2=1;
                } else {[COLOR=seagreen] /* Vorkommen bis 9: */                    *(s+k+1)=(char)((j-count1)+48);
                    k+=2; [COLOR=seagreen]/* Ein Buchstabe und seine Zahl wurden geschrieben. Springe daher 2 Indexe weiter. */                    count1=j;
                }
            }            
        }
        i++;
        j++;
    }
    ratio=(double)k;[COLOR=seagreen] /* ratio enthält am Ende der Schleife die Länge der Codierung. */    *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, temp1=0, temp2=0, count1=0, count2=0, length1=checkLength(s), length2=0;
    
    while (*(s+length2)!='\0') {
        length2++;
    }
    
   [COLOR=seagreen] /* Decodiere String: */[COLOR=royalblue][B]
    *(s+length1)='\0'; 
    i=length1;[/B][COLOR=seagreen] /* length1 = Originallänge des Strings. */[B]
    j=length2; [/B][COLOR=seagreen]/* length2 = Länge des codierten Strings. */[B]
    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [/B][COLOR=seagreen]/* Zahl gefunden: */[B]
            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [/B][COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */[B]
            temp1=count2;
            if ((temp1/10)>0) {
                while (temp1>0) { [/B][COLOR=seagreen]/* ... gib überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */[B]
                    *(s+i)=*(s+j-k+1);
                    temp1--;
                }
            }
        } else if (*(s+j)>=65 && *(s+j)<=90) { [/B][COLOR=seagreen]/* Buchstabe gefunden: */[B]
            break;
        }
        i--;
        j--;
    }
[/B]    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(void) {
[COLOR=seagreen]//int main(int argc, char *argv[]) {   [COLOR=seagreen] //char *s = argv[1];    char s[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCCCCCCCCCCCCCCCCDEABBBBDDDDDDDDDDDD";
    int i=0;

    [COLOR=seagreen]/* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
Was ich noch nicht durchschaut habe: Wieso ergibt das ...
Code:
[COLOR=seagreen]/* Decodiere String: */    *(s+length1)='\0'; 
    i=length1; [COLOR=seagreen]/* length1 = Originallänge des Strings. */    j=length2; [COLOR=seagreen]/* length2 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [COLOR=seagreen]/* Zahl gefunden: */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            temp1=count2;
            temp2=count2;
            if ((temp1/10)>0) {
                while (temp1>0) {[COLOR=seagreen] /* ... gib überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                    *(s+i)=*(s+j-k+1);
                    temp1--;
                }
            }
           [COLOR=royalblue][B] i-=temp2;
            j-=k;[/B]        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden: */            *(s+i)=*(s+j);
          [COLOR=royalblue][B]  i--;
            j--;[/B]        }
    }
... keine Ausgabe? Endlosschleife? Wenn ja, warum? Liegt's an den Dekrementen? Irgendwie muss ich verringern um im Feld nach vorne zu kommen ...

Wir haben es ja früher in der Version mit Buchstaben bis 9 auch nicht anders gemacht. Bei Einmalvorkommenden nur Zähler--, weil wir ja nur um 1 Index weiter nach vorne müssen, sonst eben Zähler-=8 (zum Beispiel), wenn acht gleiche Buchstaben nebeneinander geschrieben werden mussten. Jetzt kann's halt auch schon mal Zähler-=25 oder so heißen und temp2 speichert ja nun den großen Wert?! Warum funktioniert das Nachvornespringen jetzt nicht mehr ordentlich?

[EDIT2]

2 Dinge konnte ich noch rausfinden: Bei j muss es eigentlich immer j-- heißen, weil wir ja von char Ziffer zu char Ziffer weiterspringen müssen, um aus den Ziffern die int-Gesamtzahl zu berechnen. Wir haben ja nicht von Anfang an eine mehrstellige gesamte Zahl, die wir überspringen könnten um das Element davor anzuschauen.
Und ich habe mir mal testweise den Inhalt von temp1 ausgeben lassen: Man sieht, dass darin immer die aktuelle gefundene char Ziffer gespeichert wird, aber nicht der berechnete int-Gesamtwert, den ich darin haben will. Da müssen wir irgendwie ansetzen ...

Capture.JPG

^^ Zumindest die 2 1, die 4, die 6 1, die 3 und die 4 0 1 in temp1 machen Sinn. Daraus müssen ja die int-Gesamtzahlen 12, 16 und 104 berechnet bzw. 4 und 3 erkannt werden und das möchte ich dann in temp1 haben. Was die ganzen anderen Zahlen in temp1 sein sollen, weiß ich genausowenig, wie warum dann in char *s sowas komisches gespeichert (und bis zur '\0' ausgegeben wird).

Obige Ausgabe erreicht mit folgendem Code:
Code:
[COLOR=seagreen]/* Decodiere String: */
   [COLOR=black] *(s+length1)='\0'; 
    i=length1;[COLOR=seagreen] /* length1 = Originallänge des Strings. */    j=length2;[COLOR=seagreen] /* length2 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [COLOR=seagreen]/* Zahl gefunden: */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            temp1=count2;
            temp2=count2;
            printf("temp1 = %d\n", temp1);
            if ((temp1/10)>0) {
                while (temp1>0) { [COLOR=seagreen]/* ... gib überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                    *(s+i)=*(s+j-k+1);
                    temp1--;
                }
            }        
            i-=temp2;
            count1=0;
            count2=0;
            k=0;
        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden: */            *(s+i)=*(s+j);
            i--;
        }
        j--;
    }
Wie bekomme ich die int-Gesamtzahlen anstelle der char Ziffern in temp1 rein?

[EDIT3]
So ganz langsam sehe ich die Fehler:
1. count2 rechnet richtig, summiert die Ergebnisse aber nicht auf.
2. Der erste 4er von hinten betrachtet fließt auch in die Rechnung ein, obwohl zwischen dem 2 1 und dem 4er ein D steht.
3. Die Schleife wird dann scheinbar verlassen und der 3er, der 16er und der 104er werden nicht mehr berechnet.

Capture.JPG

^^ Die 3 Fehler müssen wir beheben. Dann hätten wir's fast/ganz geschafft.
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

So, Zeit für ein neues Posting. ^^ Oben würde ich wahrscheinlich eh bald an's Zeichenlimit kommen ...

@ Topic
Das Aufsummieren in count2 habe ich auch noch hinbekommen (man beachte den 12er in count2):

Capture.JPG

Code für copy/paste, falls wer testen möchte:
Code:
#include <stdio.h>
#include <math.h>

[COLOR=seagreen]/* Längenermittlung für codierten String. */int checkLength(char *s) {
    int i=0, j=0, k=0, count1=0, count2=0, length=0;

    while (*(s+i)!='\0') {
        if (*(s+i+1)>=48 && *(s+i+1)<=57) { [COLOR=seagreen]/* Solange Zahlen gefunden werden, ... */            count1++; [COLOR=seagreen]/* ... erhöhe Zähler. */            for (j=count1, k=(j-1); j>=0; j--, k--) {
                count2+=(k*(int)pow(10., j)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            }
            i+=count2;
            length+=count2; [COLOR=seagreen]/* ... addiere sie zu length. Sonst, ... */        } else {
            i++;
            length++; [COLOR=seagreen]/* ... zähle nur 1 dazu für jeweils einen Buchstaben. */        }
    }

    return length;
}

[COLOR=seagreen]/* 
Funktion calc nötig, um Zahlenstellen in der richtigen Reihenfolge ausgeben lassen zu können 
durch verkleinern der entsprechenden Indexe von *s anhand des Rückgabewertes. 
*/int calcSteps(int num) {
    int temp1=num, temp2=0, count=0;

    while (temp1>0) {
        temp2=temp1%10;
        temp1/=10;
        count++;[COLOR=seagreen] /* Ermittle Anzahl der nötigen Rechenschritte und somit auch die Anzahl der Stellen der Zahl bzw. nötigen Indexe im Feld. */    }

    return count;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, temp1=0, temp2=0, count1=0, count2=1, length=checkLength(s);
    double ratio=0.0;

   [COLOR=seagreen] /* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count1)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count1=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben. */                if ((j-count1)>9) { [COLOR=seagreen]/* Vorkommen größer als 9: */                    temp1=(j-count1);
                    while (temp1>0) {[COLOR=seagreen] /* Zerlege (An)Zahl in ihre einzelnen Stellen. */                        temp2=temp1%10;
                        temp1/=10;
                        count2++;[COLOR=seagreen] /* Zähle Rechenschritte mit um Anzahl der nötigen Stellen und somit Indexe zu ermitteln. */                        *(s+k+(calcSteps(temp1)+1))=(char)(temp2+48); [COLOR=seagreen]/* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */                    }
                    k+=count2; [COLOR=seagreen]/* Dann springe entsprechend viele Indexe weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                    count1=j;
                    count2=1;
                } else { [COLOR=seagreen]/* Vorkommen bis 9: */                    *(s+k+1)=(char)((j-count1)+48);
                    k+=2; [COLOR=seagreen]/* Ein Buchstabe und seine Zahl wurden geschrieben. Springe daher 2 Indexe weiter. */                    count1=j;
                }
            }            
        }
        i++;
        j++;
    }
    ratio=(double)k; [COLOR=seagreen]/* ratio enthält am Ende der Schleife die Länge der Codierung. */    *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, temp1=0, temp2=0, count1=0, count2=0, length1=checkLength(s), length2=0;
    
    while (*(s+length2)!='\0') {
        length2++;
    }
    
    [COLOR=seagreen]/* Decodiere String: */    [COLOR=royalblue][B]*(s+length1)='\0'; 
    i=length1; [/B][COLOR=seagreen]/* length1 = Originallänge des Strings. */[B]
    j=length2;[/B][COLOR=seagreen] /* length2 = Länge des codierten Strings. */[B]
    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [/B][COLOR=seagreen]/* Zahl gefunden: */[B]
            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [/B][COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */[B]
            printf("count2: %d | k: %d\n", count2, k);
            temp1=count2;
            temp2=count2;
            while (temp1>0) { [/B][COLOR=seagreen]/* ... überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */[B]
                *(s+i)=*(s+j-calcSteps(temp2)+1);
                temp1--;
            }        
            i-=temp2;
        } else if (*(s+j)>=65 && *(s+j)<=90) { [/B][COLOR=seagreen]/* Buchstabe gefunden: */[B]
            *(s+i)=*(s+j);
            i--;
        }
        j--;
    }[/B]
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(void) {
[COLOR=seagreen]//int main(int argc, char *argv[]) {  [COLOR=seagreen]  //char *s = argv[1];    char s[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCCCCCCCCCCCCCCCCDEABBBBDDDDDDDDDDDD";
    int i=0;

    [COLOR=seagreen]/* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
Bleibt nur noch zu klären, warum er den 4er in die Berechnung mit dazu nimmt, obwohl zwischen 2 1 und 4 ja wie gesagt ein D steht, und zwischen Zahlen und Buchstaben sollte mein Code unterscheiden können. Habe ja die jeweiligen ASCII-Bereiche in den beiden ifs angegeben. Und dann eben noch, warum er nur den 12er berechnet und nicht alle Zahlen im codierten String. Dann hätten wir's.

Bitte helft noch schnell! Sitze seit 3 Tagen und 2 Nächten dran und würde das wirklich sehr gerne noch heute fertig bringen. :)

[EDIT]
Hab's geschafft, dass er jetzt immer die richtigen Werte in count2 hat und danach zu rechen aufhört, bis er wieder mit einer Zahl neu beginnt. Also 12, 4, 16, 3, 104 und die ersten Rechenschritte bei mehrstelligen Zahlen. Sobald die Schleife auf einen Buchstaben trifft, muss man die Speichervariablen für die Zahlen auf 0 setzen, damit die eben auf 0 sind, sobald wieder eine Zahl berechnet werden muss. Klingt jetzt vielleicht seltsam, ist aber total logisch, wenn man sich's im Debugger anschaut.

Capture.JPG
Code:
    [COLOR=seagreen]/* Decodiere String: */    *(s+length1)='\0'; 
    i=length1; [COLOR=seagreen]/* length1 = Originallänge des Strings. */    j=length2; [COLOR=seagreen]/* length2 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [COLOR=seagreen]/* Zahl gefunden: */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            printf("count2: %d | k: %d\n", count2, k);
            temp1=count2;
            temp2=count2;
            while (temp1>0) { [COLOR=seagreen]/* ... überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                *(s+i)=*(s+j-calcSteps(temp2)+1);
                temp1--;
            }        
            i-=temp2;
        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden: */            *(s+i)=*(s+j);
            i--;
           [COLOR=royalblue][B] count2=0;
            k=0;[/B]        }
        j--;
    }
^^ Jetzt müssen wir nur noch ersten Rechenschritte (z.B. den 2er für den 12er) wegbekommen und die korrekte Ausgabe anhand der final errechneten Anzahlen (z.B. 12) hinbekommen ...

Er überschreibt mir den codierten Inhalt nämlich noch nicht mit dem Decodierten. Warum?

[EDIT2]
Zu einer Ausgabe käme ich auch schon, das Überschreiben funktioniert also schon (musste nur das i-- mit in die innere Schleife reinnehmen). Nur die Werte sind noch kompletter Blödsinn und der Fehler liegt höchstwahrscheinlich im blau markierten Code-Teil. Und die nicht erwünschten Rechenergebnisse habe ich auch noch nicht weg, aber jetzt komme ich der Sache wirklich schon verdammt nahe ...

Capture.JPG

Code:
[COLOR=seagreen]/* Decodiere String: */    *(s+length1)='\0'; 
    i=length1; [COLOR=seagreen]/* length1 = Originallänge des Strings. */    j=length2;[COLOR=seagreen] /* length2 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [COLOR=seagreen]/* Zahl gefunden: */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            temp1=count2;
            temp2=count2;
            printf("temp1: %d\n", temp1);
            while (temp1>0) { [COLOR=seagreen]/* ... überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                *(s+i)=[COLOR=royalblue][B]*(s+j-calcSteps(temp2)+1)[/B];
                temp1--;
                i--;
            }        
        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden: */            *(s+i)=*(s+j);
            i--;
            count2=0;
            k=0;
        }
        j--;
    }
Wenn ich in der blauen Zeile hinten +2 statt +1 schreibe, sieht die Ausgabe schon wirklich brauchbar aus, nur komme ich dann über ein Stringende, vermutlich das untere (geht ja von hinten/oben nach vorne/unten).

Capture.JPG

[EDIT3]
So, die Rechenschritte vor dem finalen Ergebnis konnte ich zwar nicht entfernen, aber immerhin wird dafür jetzt nur 0 in temp1 gespeichert. Das müsste das Problem auch lösen, weil er für while (0>0) nie in die Schleifen geht, oder?! Somit müssten nach meiner Logik nur mehr die finalen Rechenergebnisse in der Schleife landen.

Bezüglich Ausgabe hätte ich es jetzt so weit gebracht:

Capture.JPG

^^ Er gibt noch 1 A zu viel aus, alles andere stimmt bereits. Und hinten kommt er mir über die Nullterminierung, was ich insofern gar nicht verstehe, dass ich mich ja von hinten nach vorne durch's Feld ackere! Halleluja, ich werd' hier noch verrückt! :what:

Ah, Moment! Kann es sein, dass er mir durch das eine A zuviel hinten die von mir gesetzte '\0' überschreibt und deswegen noch ein paar seltsame Zeichen bis zur nächsten 0 im Speicher ausgibt? Jetzt bin ich gespannt, was passiert, sobald ich das mit dem A gerichtet habe ... :gruebel:

[EDIT4]
Ok, für den einen String funktioniert's jetzt, für andere wieder nicht! Wie gibt's denn das jetzt?

Habe ich wohl beim Entfernen des 1 zuvielen A geschummelt?! Immer für die erste Buchstabenreihe (war ja ursprünglich die A-Kette) gibt er nämlich jetzt Blödsinn aus (bei anderen strings). Alles danach stimmt.

Capture1.JPG Capture2.JPG Capture3.JPG

Sieht jemand den Fehler? Bevor ich hier noch durchdrehe ...

Hier der Code:
Code:
#include <stdio.h>
#include <math.h>

[COLOR=seagreen]/* Längenermittlung für codierten String. */int checkLength(char *s) {
    int i=0, j=0, k=0, count1=0, count2=0, length=0;

    while (*(s+i)!='\0') {
        if (*(s+i+1)>=48 && *(s+i+1)<=57) { [COLOR=seagreen]/* Solange Zahlen gefunden werden, ... */            count1++; [COLOR=seagreen]/* ... erhöhe Zähler. */            for (j=count1, k=(j-1); j>=0; j--, k--) {
                count2+=(k*(int)pow(10., j)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            }
            i+=count2;
            length+=count2; [COLOR=seagreen]/* ... addiere sie zu length. Sonst, ... */        } else {
            i++;
            length++; [COLOR=seagreen]/* ... zähle nur 1 dazu für jeweils einen Buchstaben. */        }
    }

    return length;
}

[COLOR=seagreen]/* 
Funktion calc nötig, um Zahlenstellen in der richtigen Reihenfolge ausgeben lassen zu können 
durch verkleinern der entsprechenden Indexe von *s anhand des Rückgabewertes. 
*/int calcSteps(int num) {
    int temp1=num, temp2=0, count=0;

    while (temp1>0) {
        temp2=temp1%10;
        temp1/=10;
        count++; [COLOR=seagreen]/* Ermittle Anzahl der nötigen Rechenschritte und somit auch die Anzahl der Stellen der Zahl bzw. nötigen Indexe im Feld. */    }

    return count;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, temp1=0, temp2=0, count1=0, count2=1, length=checkLength(s);
    double ratio=0.0;

    [COLOR=seagreen]/* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count1)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count1=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben. */                if ((j-count1)>9) { [COLOR=seagreen]/* Vorkommen größer als 9: */                    temp1=(j-count1);
                    while (temp1>0) { [COLOR=seagreen]/* Zerlege (An)Zahl in ihre einzelnen Stellen. */                        temp2=temp1%10;
                        temp1/=10;
                        count2++; [COLOR=seagreen]/* Zähle Rechenschritte mit um Anzahl der nötigen Stellen und somit Indexe zu ermitteln. */                        *(s+k+(calcSteps(temp1)+1))=(char)(temp2+48); [COLOR=seagreen]/* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */                    }
                    k+=count2; [COLOR=seagreen]/* Dann springe entsprechend viele Indexe weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                    count1=j;
                    count2=1;
                } else { [COLOR=seagreen]/* Vorkommen bis 9: */                    *(s+k+1)=(char)((j-count1)+48);
                    k+=2; [COLOR=seagreen]/* Ein Buchstabe und seine Zahl wurden geschrieben. Springe daher 2 Indexe weiter. */                    count1=j;
                }
            }            
        }
        i++;
        j++;
    }
    ratio=(double)k;[COLOR=seagreen] /* ratio enthält am Ende der Schleife die Länge der Codierung. */    *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, temp1=0, temp2=0, count1=0, count2=0, length1=checkLength(s), length2=0;
    
    while (*(s+length2)!='\0') {
        length2++;
    }
    
   [COLOR=seagreen] /* Decodiere String: */    
    i=length1; [COLOR=seagreen]/* length1 = Originallänge des Strings. */    j=length2+1; [COLOR=seagreen]/* length2+1 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) { [COLOR=seagreen]/* Zahl gefunden. */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            if (*(s+j-1)>=65 && *(s+j-1)<=90) {
                temp1=(count2-1);
                temp2=count2;
            }
            while (temp1>0) { [COLOR=seagreen]/* ... überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                *(s+i)=*(s+j-calcSteps(temp2)+(k-1));
                temp1--;
                i--;
            }        
        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden. */            *(s+i)=*(s+j);
            i--;
            count2=0;
            k=0;
        }
        j--;
    }
    *(s+length1)='\0'; [COLOR=seagreen]/* Hänge an die Decodierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(void) {
[COLOR=seagreen]//int main(int argc, char *argv[]) {    [COLOR=seagreen]//char *s = argv[1];    char s[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBCCCCCCCCCCCCCCCCDEABBBBDDDDDDDDDDDDGGGGGGGGGGGGGG";
    int i=0;

    [COLOR=seagreen]/* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
^^ Hm, wenn man sich die Ausgaben so anschaut, fällt auf, dass immer die Anzahl der A nach den unerwünschten Buchstaben stimmt. Er fängt offenbar irgendwo draußen hinter dem Feld zu schreiben an und kommt dann nur bis irgendwo in der Mitte. Wie genau soll ich das ändern?

Gerade gemerkt: Wenn mind. 1 Buchstabe >100 mal vorkommt, stimmt alles. Nur, wenn kein Buchstabe >100 Mal vorkommt, kommt die fehlerhafte Ausgabe ... :huh:

[EDIT5]
Fehler gefunden: Die Funktion checkLength liefert nicht die korrekte Länge zurück. Ich hätte es jetzt so umgeschrieben, aber ganz stimmt's immer noch nicht:
Code:
int checkLength(char *s) {
    int i=0, k=0, temp1=0, count1=0, count2=0, length1=0, length2=0;

    while (*(s+length1)!='\0') {
        length1++;
    }

    i=length1;
    while (i>0) {
        if (*(s+i)>=48 && *(s+i)<=57) { [COLOR=seagreen]/* Zahl gefunden. */            k++;
            count1=(*(s+i)-48); 
            count2+=(count1*(int)pow(10., k-1));
            if (*(s+i-1)>=65 && *(s+i-1)<=90) {
                temp1=count2;
                count2=0;
                k=0;
            }
            i-=calcSteps(temp1);
            length2+=temp1;
        } else if (*(s+i)>=65 && *(s+i)<=90) { [COLOR=seagreen]/* Buchstabe gefunden */            length2++;
            count2=0;
        }
        i--;
        
    }

    return length2;
}
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

So, habe den Code jetzt zu 95 % fertig und er liefert für nahezu alle Strings das richtige Ergebnis. Nur beim Decodieren von so ganz kurzem Zeug wie ABB, oder nur Einfachvorkommen, wie ABC wird alles um eine Stelle verschoben ausgegeben. Ergo habe ich den ersten Buchstaben doppelt und der letzte wird abgeschnitten. Das würde ich noch gerne lösen.

Irgendwie hängt's mit i=length1; in decode_runlength() zusammen. Ich schreibe ich nämlich i=length1-1;, stimmen alle kurzen Ketten, dafür sind die langen wieder um eins zu weit nach links verschoben. Das muss sich doch irgendwie beides machen lassen?! Kann ja nicht sein, dass ich mich zwischen korrekten langen Ketten und korrekten kurzen Ketten entscheiden muss ...
Code:
#include <stdio.h>
#include <math.h>

int checkLength(char *s) {
    int i=0, j=0, k=0, temp1=0, count1=0, count2=0, length1=0, length2=0;

    while (*(s+length1)!='\0') {
        length1++;
    }

    i=length1; [COLOR=seagreen]/* length1 = Länge des codierten Strings. */    while (i>0) { [COLOR=seagreen]/* Es muss von hinten begonnen werden, weil nur so die char Ziffern bei der int-Berechnung die richtigen Stellenwerte erhalten. */        if (*(s+i)>=48 && *(s+i)<=57) { [COLOR=seagreen]/* Zahl gefunden. */            k++;
            count1=(*(s+i)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer. */            if (*(s+i-1)>=65 && *(s+i-1)<=90) {
                length2+=count2;
                length2--;[COLOR=seagreen] /* Zahlen geben bereits Vorkommen des jeweiligen Buchstabens an. Dieser darf nicht auch noch dazugezählt werden. */            }
        } else if (*(s+i)>=65 && *(s+i)<=90) { [COLOR=seagreen]/* Buchstabe gefunden. */            length2++;
            count2=0;
            k=0;
        }
        i--;
    }

    return (length2-temp1+1);
}

[COLOR=seagreen]/* 
Funktion calc nötig, um Zahlenstellen in der richtigen Reihenfolge ausgeben lassen zu können 
durch verkleinern der entsprechenden Indexe von *s anhand des Rückgabewertes. 
*/int calcSteps(int num) {
    int temp1=num, temp2=0, count=0;

    while (temp1>0) {
        temp2=temp1%10;
        temp1/=10;
        count++; [COLOR=seagreen]/* Ermittle Anzahl der nötigen Rechenschritte und somit auch die Anzahl der Stellen der Zahl bzw. nötigen Indexe im Feld. */    }

    return count;
}

double encode_runlength(char *s) {
    int i=0, j=1, k=0, temp1=0, temp2=0, count1=0, count2=1, length=0;
    double ratio=0.0;

    while (*(s+length)!='\0') {
        length++;
    }

[COLOR=seagreen]    /* Codieren des Original-Strings: */    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) { [COLOR=seagreen]/* Sobald Buchstabe nicht mehr gleich seinem Nachfolger ist, prüfe: */            if ((j-count1)==1) { [COLOR=seagreen]/* Einmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben ... */                k++; [COLOR=seagreen]/* ... und springe im Index um 1 weiter. */                count1=j;
            } else { [COLOR=seagreen]/* Mehrmaliges Vorkommen? */                *(s+k)=*(s+i); [COLOR=seagreen]/* Überschreibe Feld von vorne beginnend mit Buchstaben. */                if ((j-count1)>9) { [COLOR=seagreen]/* Vorkommen größer als 9: */                    temp1=(j-count1);
                    while (temp1>0) { [COLOR=seagreen]/* Zerlege (An)Zahl in ihre einzelnen Stellen. */                        temp2=temp1%10;
                        temp1/=10;
                        count2++;[COLOR=seagreen] /* Zähle Rechenschritte mit um Anzahl der nötigen Stellen und somit Indexe zu ermitteln. */                        *(s+k+(calcSteps(temp1)+1))=(char)(temp2+48); [COLOR=seagreen]/* Überschreibe entsprechend viele Feldelemente mit den Stellen der Vorkommenszahl. */                    }
                    k+=count2; [COLOR=seagreen]/* Dann springe entsprechend viele Indexe weiter, um an die nächste zu überschreibende Stelle zu gelangen. */                    count1=j;
                    count2=1;
                } else {[COLOR=seagreen] /* Vorkommen bis 9: */                    *(s+k+1)=(char)((j-count1)+48);
                    k+=2; [COLOR=seagreen]/* Ein Buchstabe und seine Zahl wurden geschrieben. Springe daher 2 Indexe weiter. */                    count1=j;
                }
            }            
        }
        i++;
        j++;
    }
    ratio=(double)k; [COLOR=seagreen]/* ratio enthält am Ende der Schleife die Länge der Codierung. */    *(s+(int)ratio)='\0'; [COLOR=seagreen]/* Hänge an die Codierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Codierter String */
    return ((ratio*100)/(double)length);
}

int decode_runlength(char *s) {
    int i=0, j=0, k=0, temp1=0, temp2=0, count1=0, count2=0, length1=0, length2=0;
    
    while (*(s+length2)!='\0') {
        length2++;
    }
    
   [COLOR=seagreen] /* Decodiere String: */    
    length1=checkLength(s);
    [COLOR=royalblue][B]i=length1-1;[/B] [COLOR=seagreen]/* length1 = Originallänge des Strings. */    j=length2+1;[COLOR=seagreen] /* length2+1 = Länge des codierten Strings. */    while (i>0) {
        if (*(s+j)>=48 && *(s+j)<=57) {[COLOR=seagreen] /* Zahl gefunden. */            k++;
            count1=(*(s+j)-48); 
            count2+=(count1*(int)pow(10., k-1)); [COLOR=seagreen]/* Berechne Gesamtzahl als integer und ... */            if (*(s+j-1)>=65 && *(s+j-1)<=90) {
                temp1=(count2-1);
                temp2=count2;
            }
            while (temp1>0) {[COLOR=seagreen] /* ... überschreibe Feld von hinten beginnend gemäß dieser Anzahl mit dem zugehörigen Buchstaben. */                *(s+i)=*(s+j-calcSteps(temp2)+(k-1));
                temp1--;
                i--;
            }        
        } else if (*(s+j)>=65 && *(s+j)<=90) { [COLOR=seagreen]/* Buchstabe gefunden. */            *(s+i)=*(s+j);
            i--;
            count2=0;
            k=0;
        }
        j--;
    }
    *(s+length1)='\0';[COLOR=seagreen] /* Hänge an die Decodierung noch eine Nullterminierung an. */
    printf("%s", s); [COLOR=seagreen]/* Ausgabe: Decodierter String */
    return 0;
}

int main(void) {
[COLOR=seagreen]//int main(int argc, char *argv[]) {  [COLOR=seagreen]  //char *s = argv[1];    char s[] = "AB";
    int i=0;

    [COLOR=seagreen]/* Kleinbuchstaben in Großbuchstaben umwandeln */    while (*(s+i)!='\0') {
        if (*(s+i)>=97 && *(s+i)<=122) {
            *(s+i)-=32;
        }
        i++;
    }

    printf("Original:   %s", s);
    printf("\nCodiert:    ");
    printf("\nVerk%crzung: %.0lf %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:  ");
    decode_runlength(s);
    printf("\n\n");

    return 0;
}
Hier zu Verdeutlichung, was ich meine:

i=length1; --> lange Ketten stimmen, kurze um 1 verschoben.

Capture1_1.JPG Capture1_2.JPG

i=length1-1; --> kurze Ketten stimmen, lange um 1 verschoben.

Capture2_1.JPG Capture2_2.JPG

^^ Hat dazu wer eine Idee?

Die Länge wird jedes mal und für jede Kette richtig ermittlet. Hab's extra noch einmal gecheckt. Nur für kurze Ketten fängt er offensichtlich um 1 nach hinten/rechts verschoben zu schreiben an. Jetzt stellt sich mir nur die Frage, wie der Compiler "kurz" definiert. Wenn ich genau wüsste, woran er die kurzen Ketten von den langen unterscheidet, könnte ich den Fehler beheben ...
 
Zuletzt bearbeitet:
Zurück