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

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

man kann ja als zusatzaufgabe versuchen, ne funktion zu bauen, die auch "gleichungen" berücksichtigt ^^ also +-*/ der einfachheit halber. sprich das selbe wie bisher (vorranggehende leerzeichen usw ignorieren, bei buchstaben abbrechen - ABER: nich nur das erste + - usw beachten und beim 2. abbrechen, sondern die entstehenden werte korrekt berechnen.

als bsp:
" 043+1-a5" => 44
"+123-45*2" => 156 (lineare abarbeitung fürs erste - normal würde man das ja als 123-(45*2) rechnen, sprich 33 als ergebnis)

wenn man den hier schon angekratzten fehler und vllt sogar klammern berücksichtigen will, das wird dann glaube der experten mode :P naja, als stichpunkt fällt mir zumindest erstmal rekursion ein. werd mich nachher mal prototypisch (hier im eingabefeld) dran probieren ^^
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Naja, 'return result;' gibt ein falsches Ergebnis bei zB. ("-323c47")
Bei welcher Eingabe hat er bei break ein Minus gesetzt? Eigentlich solltes damit stimmen, aber vielleicht hab ich ja was übersehen.
Stimmt, da käme ich auf 323 (ohne Minus). Wenn ich allerdings deine Version mit dem break anstelle des returns nehme, liefert mir "+13-56a" -13 (mit Minus) ...

BTW: Wir arbeiten nicht mehr mit exakt dem selben Code (siehe meine Version im vorherigen Posting). Habe z.B. die Plus-Überprüfung gelöscht, weil die mehr oder weniger sinnlos war. Die Rückgaben von result und -result hängen jetzt auch in einem if-else gemeinsam drinnen. Ändert semantisch nichts, ist aber optisch schöner.

@ DarkMo
Also solche "wilden" Dinge überlasse ich dann lieber mal dir. ;)

Wenn ich mit Freddycbv die letzten Ungereimtheiten geklärt habe, möchte ich wieder die Lauflängencodierung, die wir hier schon einmal hatten, probieren. Beim ersten Anlauf haben wir uns ja in eine Sackgasse programmiert, wo kein sinnvolles Weiterarbeiten im Rahmen der Aufgabenstellung mehr möglich war. Es muss also ein neuer Ansatz her und mir schwirrt auch schon eine erste Idee im Kopf herum. Ich muss das aber zuerst ausprobieren, bevor ich sagen kann, ob wir damit ans Ziel kommen können ... :)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

achsooo!
Dadurch dass du das mit dem Plus herausgenommen hast, gibts jetzt den Fehler:
Code:
    /* Leerzeichen/Tabulatoren entfernen und Vorzeichen prüfen */
    while (*(s+i) != '\0') {
        if (*(s+j)==' ' || *(s+j)=='\t') {
            j++;
        } else if (*(s+i)=='+') {
            [COLOR=blue]break;        } else if (*(s+i)=='-') {
            minus=1;
           [COLOR=blue] break;        }
        i++;
    }
Dieser Teil der Funktion soll ja voranstehende Tabulatoren und Leerzeichen herausfiltern, aber auch das Vorzeichen festlegen.
Mit der Plus-Abfrage geht er alle Zeichen des Strings Zeichen für Zeichen durch, und sobald er das erste Vorzeichen findet, bricht er ab(+/-)
Lässt du das mit dem Plus weg, geht er alles durch, bis er das erste Minus findet, bzw. der String zuende ist.

Gut das du das bemerkt hast!

Weil damit ist auch mein gepostetes Schnipsel nicht ganz richtig:
Das Programm muss die ersten Zeichen durchgehen, und sobald ein Zeichen außer Leerzeichen / Tabulatoren kommt, gehts an die "Zahlensuche" weiter unten
Wenn ein Vorzeichen gefunden wurde, dann muss es gesetzt werden (beim Minus), und man muss ein Zeichen weiter gehen.

Bei der "Zahlensuche" muss jetzt auch nurnoch darauf geachtet werden, ob Zahl oder Keine Zahl.
Auf Vorzeichen, bzw. erstes Zeichen muss keine Rücksicht mehr genommen werden


Code:
int convert(char s[]) {
    [COLOR=navy]int i=0, Vorzeichen=1, result=0;

    [COLOR=navy]/* Leerzeichen/Tabulatoren entfernen und Vorzeichen prüfen */
    for(i; *(s+i) != '\0'; i++) {
        //Beim Vozeichenfund abbrechen, und eventuell ein Minus setzen
        if(*(s+i)=='+' || *(s+i) == '-'){
            if(*(s+i)=='-'){
                Vorzeichen = -1;
            }
            i++;
            break;
        }
        //Tabulatoren und Leerzeichen ignorieren, ansonsten abbrechen
        else if (*(s+i)!=' ' && *(s+i)!='\t') {
            break;
        }
    }
    /* Prüfen auf Gültigkeit der Zahl und Rückrechnung von Dec nach Chr */
    for (i; *(s+i) != '\0'; i++) {
        if (*(s+i)>=48 && *(s+i)<=57) { /* ASCII-Bereich der chars */
            result = result*10+*(s+i)-48;
        [COLOR=navy]} else break; //abbrechen, falls keine Zahl    }

    /* dem Vorzeichen entsprechende Rückgabe */
[COLOR=navy]    return Vorzeichen * result;}
War jetzt vielleicht ein wenig kompliziert, aber das Problem war ja, dass bei der Vorzeichensuche folgende Ergebnisse beachtet werden müssen:
- Vorzeichen Minus
- Vorzeichen Plus
- Kein Vorzeichen (also in unserer Welt ein Plus ;) )
Das war bei den vorherigen Schleifen halt nicht der Fall, denn wenn kein Vorzeichen vor der ersten Zahl gefunden wurde, aber ein Minus nach der ersten Zahl, es automatisch ein Minus wurde :ugly:
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

wegen dem return in if schleifen und kein problem... manche compiler haben damit sehr wohl ein problem ^^ die wollen unbedingt ein return, das definitiv ausgeführt wird. sieh dir zum bsp den code hier an:
Code:
char sinnlos(char c) {
    if(c == 'a') return 'A';
    else if(c == 'b') return 'B';
}
hier ist der einwand des compilers durchaus berechtigt - weil wenn c weder 'a' noch 'b' ist, wird garnichts zurückgegeben - was falsch ist, da die funktion nicht void ist sondern ein char als rückgabewert verlangt. und auch wenn man
Code:
char sinnlos(char c) {
    if(c == 'a') return 'A';
    else return 'B';
}
schreibt (einfach else statt else-if), meckert so mancher, obwohl es hier eigentlich lauffähig wäre. die sehen dann aber nur, dass da bedingte returns sind, und das darf nicht sein. daher hab ich mir bersönlich nen simples
Code:
char sinnlos(char c) {
    if(c == 'a') return 'A';
    return 'B';
}
angewöhnt ^^ dann wird garantiert nicht gemeckert, bei genauso guter funktionalität. gut, das wollt ich aber nur am rande mal erwähnt haben als "good to know".

jetzt mal zu meinem vorhaben ^^ mein plan für die simple erweiterung wäre, dass convert einen string annimmt und das erste vorkommen eines vorzeichens oder einer zahl sucht (abbruchbedingungen wie gehabt). findet er eine zahl, wird diese wi gehabt schrittweise konvertiert, findet er ein vorzeichen, schneidet er den anfang (inklusive vorzeichen) ab und schickt den rest "sich selbst" - rekursiver aufruf.

vorüberlegung: "1--12" würde auch gehen. er findet die '1', dann das '-' und übergibt einer weiteren instanz von sich selbst '-1' (das bisher bearbeitete '1-' wird abgeschnitten). hmm, nun findet er wieder ein '-' und übergibt der 3. instanz die '12' - die zur 12 ausgewertet und an die 2. instanz zurückgegeben wird. in der 2. instanz ist der value 0 und davon wird die in der 3. instanz konvertierte 12 abgezogen -> -12. diese -12 der 2. instanz geht nun zurück an unsere erste instanz, die bisher schon die '1' konvertiert hat (value is also 1) und zieht davon die -12 ab -> 1- (-12) = 1+12 = 13. hmm, is ja doch garnich so übel ^^

gut, sollte also so kein problem sein - wir brauchen nur eine hilfsfunktion substring (und die obligatorische länge). fein...

Code:
int strLen(char *s) {
    int length = 0;
    while(*s != '\0') {
        length++;
        s++;
    }
    return length;
}

char* subStr(char *s, int start, int length) {
    char *sub = (char*) malloc(length + 1);
    int i;

    if(sub == NULL) exit(1); // sollte er keinen speicher allokieren können, raus hier ^^
    for(i = 0; i < start; i++) s++; // zeiger von s weiterschieben, bis der startindex erreicht wurde
    for(i = 0; i < length; i++) { // und nun length zeichen in sub kopieren
        sub[i] = *s;
        s++;
    }
    sub[i] = '\0'; // nullterminierten string basteln

    return *sub;
}

bool isDigit(char s) {
    if((int)s > 47 && (int)s < 58) return true;
    return false;
}

int convert(char s[]) {
    int value = 0, pos = 0, length = strLen(s);

    while (*s==' ' || *s=='\t') { // leerzeichen skippen
        s++; // den zeiger weiterschieben
        pos++; // und noch den index (position) aktualisieren
    }

    // vorrangestellte vorzeichen bearbeiten
    if (*s=='-') {
        pos++; // vor der substringbildung den index erhöhen, damit das vorzeichen in der nächsten instanz nicht nochmal behandelt wird (auch abschneiden)
        value -= convert(subStr(s, pos, length - pos)); // rekursiver aufruf von convert mit dem substring als parameter
        return value; // der rest wurde in den "tieferen instanzen" alles abgearbeitet, raus hier
    } else if (*s=='+') { // mit den anderen genauso verfahren
        pos++;
        value += convert(subStr(s, pos, length - pos));
        return value;
    } else if (*s=='*') {
        pos++;
        value *= convert(subStr(s, pos, length - pos));
        return value;
    } else if (*s=='/') {
        pos++;
        int tmp = convert(subStr(s, pos, length - pos));
        if(tmp != 0) value /= tmp; // division durch 0 verhindern
        return value;
    }

    // wurde kein vorzeichen gefunden, wandle das ganze gerödel in ne zahl um
    while (*s != '\0') {
        pos++;

        // weitere vorzeichen bearbeiten
        if (*s=='-') {
            value -= convert(subStr(s, pos, length - pos)); // rekursiver aufruf von convert mit dem substring als parameter
            return value; // der rest wurde in den "tieferen instanzen" alles abgearbeitet, raus hier
        } else if (*s=='+') { // mit den anderen genauso verfahren
            value += convert(subStr(s, pos, length - pos));
            return value;
        } else if (*s=='*') {
            value *= convert(subStr(s, pos, length - pos));
            return value;
        } else if (*s=='/') {
            int tmp = convert(subStr(s, pos, length - pos));
            if(tmp != 0) value /= tmp; // division durch 0 verhindern
            return value;
        }

        if (!isDigit(*s)) break; // keine ziffer mehr? raus hier

        value = value*10 + (int)*s - 48;
        s++;
    }

    return value;
}

hmm, jetz wüsst ich gern, ob das so funzt ^^
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

@ Freddycbv
Ich glaube, in deiner ersten for-Schleife kannst du dir das i++ vor dem break sparen, weil du eh schon im Schleifenkopf inkrementierst.

Ich habe jetzt bei mir das else if (*(s+i)=='+') wieder reingetan und jetzt funktioniert's mit dem break anstelle von return result. Was ich aber nicht ganz verstehe, ist, wo denn jetzt der 0er im Falle von ungültigen Zahlen herkommt. Zuerst war's logisch --> return result --> result=0. Aber jetzt?
Ich vermute mal, irgendwie aus dieser Zeile: result = result*10+*(s+j)-48; ... aber wie kommt der Compiler da hin? Er geht ja nur in's else, wenn das if nicht stimmt. Und wenn das if nicht stimmt, wird doch die Anweisung darin gar nie ausgeführt?!

^^ Hach, immer diese Logiksachen. Bis bei mir da mal das Licht aufgeht ... :schief:

@ DarkMo
Ich verstehe, was du mir bezüglich Rückgabe von Werten sagen willst, aber ich hab's noch nie erlebt, dass sich ein Compiler beschwert hätte (glaub's dir aber, dass es passieren kann). Ok, ich programmiere aber auch nur ausschließlich mit Visual Studio unter Windows. Vielleicht ist es da zufällig egal.

Unnötig verkomplizieren will ich das Programm jetzt ehrlich gesagt nicht mehr. Die Aufgabestellung wäre ja erfüllt. Danke für eure Hilfe! :daumen:

Was ich gerne noch geklärt hätte, bezieht sich noch auf eure Kommentare zu unserem vorigen Beispiel: Palindrom
Length enthält die Anzahl der Zeichen ohne Nullterminierung. Du hast also length Zeichen, von str[0] bis str[length-1]. Was ich da meinte war, wenn du mit str[length] arbeitest, liegt du im besten Fall auf dem Null-Zeichen, im schlimmsten Fall bei einer Speicherschutzverletzung (man kann auch Strings ohne Nullterminator nutzen!)
Length beinhaltet also alle Zeichen exklusive der Nullterminierung und du meintest, es müsste daher mit nur length/2 anstatt von (length-1)/2 im Schleifenkopf funktionieren. Nun, tut's aber nicht (falsche Ergebnisse). Wieso, wenn doch die Nullterminierung eh nicht mehr enthalten ist?
Code:
#include <stdio.h>

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

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

    return length;
}

int checkPalindrome(char *s) {
    int i=0, j=0, length=checkLength(s);
    char checkString[50]={0}, firstHalf[25]={0}, secondHalf[25]={0}; 
    
   [COLOR=seagreen] /*
    Speichere das jeweils übergebene Wort in checkString und wandle anschließend alle 
    Großbuchstaben in Kleinbuchstaben um. 
    */    for (i=0; i<length; i++) {
        *(checkString+i)=*(s+i);
        if (*(checkString+i) >= 'A' && *(checkString+i) <= 'Z') {
            *(checkString+i)+=32;
        }
    }

    [COLOR=seagreen]/* 
    Zerlege das zu überprüfende Wort in 2 Hälften und speichere jede in einem eigenen string.
    Der string, der die zweite Worthälfte bekommt, muss verkehrt herum angefüllt werden. 
    */    [COLOR=royalblue][B]for (i=0, j=(length-1); i<((length-1)/2), j>((length-1)/2); i++, j--) {[/B]        *(firstHalf+i)=*(checkString+i);
        *(secondHalf+i)=*(checkString+j);
    }

    [COLOR=seagreen]/* Vergleiche die beiden strings. */    i=0;
    while (*(firstHalf+i) != '\0' || *(secondHalf+i) != '\0') {
        if (*(firstHalf+i) != *(secondHalf+i)) {
            return 1;
        }
        i++;
    }

    return 0;
}

int main(void) {
    int i=0;
    char *s[] = {"Hannah", "Smartphone", "Retsinakanister", "Lagerregal", "programmieren", 0 };

    while (*(s+i) != '\0') {
        if (checkPalindrome(*(s+i))==0) {
            printf("%s is a Palindrome!\n", *(s+i));
        } else {
            printf("Sorry, %s isn't a Palindrome.\n", *(s+i));
        }
        i++;
    }
    putchar('\n');

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

Unnötig verkomplizieren will ich das Programm jetzt ehrlich gesagt nicht mehr. Die Aufgabestellung wäre ja erfüllt.
der spaß beim programmieren fängt für mich da an, wo man selber was bastelt ^^ hier wars halt der ehrgeiz - und rekursion kann man nie genug üben :P

wegen der length geschichte: die "grundlagen" kennste aber oder? also "abcde" hat die länge 5, da der index aber bei 0 anfängt, muss man hier immer -1 rechnen:
string|a|b|c|d|e
stelle|1|2|3|4|5
index|0|1|2|3|4
so quasi. willst du das letzte zeichen, darfst du eben nicht string[length] nehmen, sondern string[length-1]. stelle "length" ist index length-1.
und wegen dem palindrom: abcba zum bsp ist ein palindrom - aber 5 ist schlecht (ganzzahlig) durch 2 teilbar. mit glück rundet er gescheit und du hast aus abc die 2 "hälften" abc und cba gemacht, wobei cba in umgekehrter richtung gespeichert wird - und du kannst abc mit abc vergleichen und der sinn erfüllt sich. im schlechtesten fall versuchts du aber abc mit reverse(ba) zu vergleichen ^^ aber ich glaub, er rundet da ordentlich. 5/2=3 also indizes 0 bis 3-1 ergeben die erste hälfte und indizes length-1 bis length-3 die 2. hälfte. im notfall bei sowas mit nem überschaubaren bsp arbeiten und "abzählen" um zu schauen, obs stimmt ^^ mach ich auch immer :P is zwar gefühlt wie rechnen mit der handabzählerei als hilfe, aber solange es klappt xD
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Mein Plan war eigentlich, nicht auf gescheite Rundung durch den Compiler zu hoffen (abcba --> abc, cba), sondern bei strings mit ungerader Länge das Zeichen ganz in der Mitte zu ignorieren. :D
Sollte ja problemlos möglich sein, nur den Teil links davon mit dem Teil rechts davon zu vergleichen. Das besagte Zeichen kommt ja nur 1x vor und muss daher mit nichts verglichen werden.

Die Sache mit Index, Stellen, etc. verstehe ich schon. Ich sehe auch schon, wo bei uns die konkreten Unterschiede liegen. Du fängst in deinem Palindrom Code in der Schleife (die das gesamte Array durchläuft) bei i=0 an und musst somit entweder bis i<=length-1 oder i<length gehen.

Bei mir sieht die Sache so aus:
Code:
[COLOR=seagreen]/* 
    Zerlege das zu überprüfende Wort in 2 Hälften und speichere jede in einem eigenen string.
    Der string, der die zweite Worthälfte bekommt, muss verkehrt herum angefüllt werden. 
    */    for (i=0, j=(length-1); i<(length/2), j>(length/2); i++, j--) {
        *(firstHalf+i)=*(checkString+i);
        *(secondHalf+i)=*(checkString+j);
    }
^^ So würde es gehen. Wenn ich das hier richtig verstehe, muss j length-1 sein, weil j bis (Index) 0 runterzählt?! Und bei den Abbruchbedingungen selbe Situation, wie bei dir: < (kleiner) length läuft ja auf's selbe hinaus, wie <= und length-1. Hier geht's offensichtlich um die Indexe.

Wenn ich mich nicht ganz täusche, müsste auch mein Plan mit dem Ignorieren des Zeichens ganz in der Mitte bei ungeraden Arrays aufgehen?! ;)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

@ Freddycbv
Ich glaube, in deiner ersten for-Schleife kannst du dir das i++ vor dem break sparen, weil du eh schon im Schleifenkopf inkrementierst.
Leider nicht, ist eine kleine Falle: Weil wenn ich bei Vorzeichen abbreche, ohne zu inkrementieren, ist er weiter unten in der Zahlensuche immer noch beim '+'/'-'. Dann würde er sofort abbrechen, und plötzlich ist auch "-300" oder "+70" falsch.
Also eine Stelle weiter, um zur 1.Zahl zu kommen
Ich habe jetzt bei mir das else if (*(s+i)=='+') wieder reingetan und jetzt funktioniert's mit dem break anstelle von return result.
Aber nicht perfekt. Ich vermute, dass er so Zahlen wie "370-7" als -370 interpretiert. Deshalb hab ich in meinem letzten Post die Suche nach dem Vorzeichen nochmal komplett verändert.
Was ich aber nicht ganz verstehe, ist, wo denn jetzt der 0er im Falle von ungültigen Zahlen herkommt. Zuerst war's logisch --> return result --> result=0. Aber jetzt?
Ich vermute mal, irgendwie aus dieser Zeile: result = result*10+*(s+j)-48; ... aber wie kommt der Compiler da hin? Er geht ja nur in's else, wenn das if nicht stimmt. Und wenn das if nicht stimmt, wird doch die Anweisung darin gar nie ausgeführt?!
^^ Hach, immer diese Logiksachen. Bis bei mir da mal das Licht aufgeht ... :schief:
Ja, die If-Anweisung wird bei ungueltigen Zahlen nie ausgeführt! Er breaked sofort, und gibt dann sofort result zurück.
Result ist doch von Anfang an 0. So hast du das doch ganz oben initialisiert: int result = 0;
Ich glaub, das mit der Logik kommt mit der Zeit... :D Ist ja auch nicht so einfach, immerhin redet kein Mensch in C :lol:
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ok, danke! Das mit dem 0er ist jetzt auch klar und die Vorzeichensuche werde ich ebenfalls noch so weit verallgemeinern, dass nicht nur die 6 Arrays in der Angabe richtig umgewandelt werden.

Bleibt nur noch eines, das mir heute Früh aufgefallen ist: Wieso ist ...
Code:
} else if ([COLOR=royalblue][B]![/B](*(s+j)[COLOR=royalblue][B]==[/B]'+' || *(s+j)[COLOR=royalblue][B]==[/B]'-') || startPos!=j) {
... semantisch nicht das selbe, wie ...
Code:
} else if ((*(s+j)[COLOR=royalblue][B]!=[/B]'+' || *(s+j)[COLOR=royalblue][B]!=[/B]'-') || startPos!=j) {
... ?
Jedenfalls stimmen die Ergebnisse nur bei der ersten Variante, nicht aber bei der zweiten. In beiden Fällen kann man sich das doch als "wenn-nicht-dann-mache" vorstellen?!
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Wenn das Zeichen nicht + oder - ist, dann breche ab.
!(*(s+j)=='+' || *(s+j)=='-') ist dasselbe wie (*(s+j)!='+' && *(s+j)!='-')

Ist ein bisschen schwer, aber man muss sich das einfach im Kopf vorstellen.

*(s+j)=='+' || *(s+j)=='-' => gibt true, wenn das Zeichen Plus oder Minus ist
*(s+j)!='+' || *(s+j)!='-' => gibt true, wenn das Zeichen (nicht Plus) oder (nicht Minus) ist; also IMMER
*(s+j)!='+' && *(s+j)!='-' => gibt true, wenn das Zeichen weder Plus noch Minus ist.

Einfach mal mit ein paar Werten im Kopf durchspielen, dann merkt man schon, obs passt oder nicht :D
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Aha, du meinst:
1 || 1 --> 1, wobei die 1er links und rechts vom logischen ODER eben von der Auswertung des Ausdrucks abhängen. Auf's && wäre ich übrigens sogar gekommen, nur habe ich es an der falschen Stelle ausprobiert (... && startPos!=j). ;)

Ist jetzt keine Frage, aber ich habe eben noch was entdeckt: Wenn du deine Schleife von for auf while umschreibst, brauchst du das i++ vor dem break wirklich nicht ...
Code:
    while (*(s+i) != '\0') {
        if (*(s+i)=='+' || *(s+i) == '-'){
            if (*(s+i)=='-') {
                minus=1;
            }
            break;
        } else if (*(s+i)!=' ' && *(s+i)!='\t') {
            break;
        } 
        i++;
    }
^^ So funktioniert's bei mir (auch das "307-7"). :)
Code:
#include <stdio.h>
#include <stdlib.h>

int convert(char s[]) {
    int i=0, j=0, minus=0, startPos=0, result=0;

    [COLOR=seagreen]/* Leerzeichen/Tabulatoren entfernen und Vorzeichen prüfen */    
    while (*(s+i) != '\0') {
        if (*(s+i)=='+' || *(s+i) == '-'){
            if (*(s+i)=='-') {
                minus=1;
            }
            break;
        } else if (*(s+i)!=' ' && *(s+i)!='\t') {
            break;
        } 
        i++;
    }
    
    [COLOR=seagreen]/* Prüfen auf Gültigkeit der Zahl und Rückrechnung von Dec nach Chr */    startPos=i;
    for (i; *(s+i) != '\0'; i++) {
        if (*(s+i)>=48 && *(s+i)<=57) { /* ASCII-Bereich der chars */
            result = result*10+*(s+i)-48;
        } else if ((*(s+i)!='+' && *(s+i)!='-') || startPos!=i) {
            break;
        }
    }

    [COLOR=seagreen]/* dem Vorzeichen entsprechende Rückgabe */    if (minus==1) {
        return -result;
    } else {
        return result;
    }
}

int main(void) {
    char *t1 = "012431234";
    char *t2 = "  -124";
    char *t3 = " +562";
    char *t4 = "13a";
    char *t5 = " a56 ";
    char *t6 = "     +13-56a";
    char *t7 = "  307-7";

    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t1, convert(t1), atoi(t1));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t2, convert(t2), atoi(t2));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t3, convert(t3), atoi(t3));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t4, convert(t4), atoi(t4));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t5, convert(t5), atoi(t5));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t6, convert(t6), atoi(t6));
    printf ("The value entered is %s. convert() liefert %d. atoi liefert %d.\n", t7, convert(t7), atoi(t7));

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

ja, das liegt daran, dass ich weiter unten ja auch noch was umgebaut hatte :D
Nämlich genau bei dem else if
Code:
    // Prüfen auf Gültigkeit der Zahl und Rückrechnung von Dec nach Chr 
    for (i; *(s+i) != '\0'; i++) {
        if (*(s+i)>=48 && *(s+i)<=57) { // ASCII-Bereich der chars 
            result = result*10+*(s+i)-48;
        } [COLOR=darkred]else break; //abbrechen, falls keine Zahl    }
Ich fands so schöner, bzw besser getrennt: Die obere Schleife legt das Vorzeichen fest, und entfernt voranstehende Leerzeichen; und die unterer sucht nur nach Zahlen, und muss Vorzeichen und so nicht mehr berücksichtigen.

Deswegen brauche ich jetzt das i++ weiter oben, weil ich ja nicht mehr darauf prüfe,
ob es ein Vorzeichen ist, das an erster Stelle steht.

Naja, ist jetzt eigentlich unwichtig...
wichtig ist ja nur, dass die Funktion jetzt richtig funktioniert :D
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

ahja, das logische 1*1 ^^

ein oder zu negieren endet in einem und (und umgekehrt). zu sagen !(a v b) entspricht !a ^ !b (v = oder zeichen, ^ = und zeichen. als eselsbrücke: das v kommt dem u nahe, man möcht also ans und denken, ergo isses das oder xD). gibt da noch mehr so regeln, wäre sicher ganz intressant für dich, dir das mal anzuschauen. du siehst ja, es bringt was (du hast es ja erstmal schön falsch gemacht ^^).
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Ich sollte eigentlich binär rechnen können. v und ^ kenne ich, genau so wie das "halbe Plus" (habe kein passendes Symbol auf der Tastatur) für Negation. K.A. warum ich das hier übersehen habe. !(Irgendwas) ist halt wieder sowas, das ich nie benutze, weil ich != einfach wesentlich logischer finde. Dass man da dann bei den Verknüpfungen entsprechend umdenken muss, muss ich mir noch angewöhnen. ;)

Werde jetzt mal versuchen, meinen Ansatz für die Lauflängencodierung zu programmieren ...

Thanks für die Erklärungen beim Umwandlungsbeispiel. :daumen:

[EDIT]
@ DarkMo
Meine Idee für die Lauflängencodierung ist Rekursion, weil du gemeint hast, das sollte man eh immer wieder mal üben. ;)

Mein erster Anlauf ist auch gar nicht sooo schlecht:
Code:
#include <stdio.h>

double encode_runlength(char *s) {
    int i=0, j=1;

    while (*(s+i) != '\0') {
        j+=i;
        if (*(s+i)!=*(s+j)) {
            if (j==1) {
                printf("%c", *(s+i));
            } else {
                printf("%c%d", *(s+i), j);
            }
            i=j;
            encode_runlength(s+i);
            break;
        }
        i++;
    }
}

int decode_runlength(char *s) {

}

int main(void) {
    char *s = "AAAABBBCCCCCCCCDEABBBBDDDDDDDD";

    encode_runlength(s);

    return 0;
}
^^ Nur bei drei Buchstaben (beim ersten B-Vorkommen, das C- und das zweite D-Vorkommen) verzählt er sich noch. Aber den Fehler finde ich hoffentlich bald.

[EDIT2]
Hab's! j darf nicht um i erhöht werden, sondern immer nur um 1 --> j++. Die Decodierung wäre somit schon erledigt und der Code ist, zumindest für mich, wesentlich einfacher zu verstehen, als das (längere) Konstrukt, dass wir vor ein paar Wochen gebaut haben.
Code:
double encode_runlength(char *s) {
    int i=0, j=1;

    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) {
            if (j==1) {
                printf("%c", *(s+i));
            } else {
                printf("%c%d", *(s+i), j);
            }
            i=j;
            encode_runlength(s+i);
            break;
        }
        i++;
        j++;
    }
}
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Hm, schaut so weit schon ganz gut aus. :) Nur die Berechnung der Verkürzung liefert noch bull**** (1431655765 %). Sehe den Fehler noch nicht (vermutlich irgendein double-int Konflikt) ...
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, length=checkLength(s);
    double ratio=0.0, counter=0.0, count1=0.0, count2=0.0;

    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) {
            if (j==1) {
                count1+=printf("%c", *(s+i));
            } else {
                count2+=printf("%c%d", *(s+i), j);
            }
            i=j;
            encode_runlength(s+i);
            break;
        }
        i++;
        j++;
    }

    counter=(count1+count2);
    ratio=((counter*100)/(double)length);

    return ratio;
}

int decode_runlength(char *s) {

}

int main(void) {
    char *s = "AAAABBBCCCCCCCCDEABBBBDDDDDDDD";

    printf("Original:   %s\n", s);
    printf("Codiert:    ");
    printf("\nVerk%crzung: %d %%\n", 129, (100-encode_runlength(s)));
    printf("Decodiert:\n\n");

    return 0;
}
Ausgabe:

Capture.JPG

^^ Sobald die Verkürzung stimmt, bräuchte ich einen guten Tipp, wie ich denn nun die Encodierung (also, die verkürzte Zeichenkette) in die Decodier-Funktion rüberbringen kann. Ein Punkt der (strengen) Vorgaben ist nämlich folgender: Es darf ausschließlich mit dem Feld *s gearbeitet werden! :fresse:

Sobald also der komplette Inhalt encodiert ist, muss ich den Originalinhalt in der Funktion encode_runlength() damit überschreiben und anschließend irgendwie *s nach decode_runlength() verfrachten. Hier aber wieder das Problem: Die Vorgabe besagt, dass encode_runlength() nur die Verkürzung zurückgeben darf und kein Feld, oder sonst was ... :ugly:
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

hmm, auf jedenfall ein intressanter ansatz (also die rekursive lösung). du zählst also all gleichen buchstaben zusammen und am ende gibst dus aus, gehst in die nächste instanz (rekursiv) und machts mim nächsten buchstaben weiter. funktioniert, allerdings hast du nix "verwertbares" am ende. besser wärs meines erachtens nach, wenn du nen neuen string zusammen friemelst. dann haste a) was zum benutzen (ausgegeben aufm schirm isses nutzlos ^^) und b) kannste dann damit auch wieder dekodieren.

gut, wegen der ratio: das kann doch so garnich klappen ^^ hmm, gehn wir dein bsp (verkürzt) mal durch: AAAABBBCCCCCCCC
(beim funktionsaufruf ist die stelle des strings, auf die der zeiger zeigt, unterstrichen)
Code:
-> encode_runlength([U]A[/U]AAABBBCCCCCCCC)
    er findet 4 A's, i ist also 3 und j 4
    dann findet er das B, er gibt A4 aus und count2 wird 2
    rekursiver aufruf:
    -> encode_runlength(AAAA[U]B[/U]BBCCCCCCCC)
        er findet 3 B's, i ist also 2 und j 3
        dann findet er das C, er gibt B3 aus und count2 wird 2
        rekursiver aufruf:
        -> encode_runlength(AAAABBB[U]C[/U]CCCCCCC)
            er findet 8 C's, i ist also 7 und j 8
            dann findet er das ende, und hier is doch dann ... aso, die '\0' is ja ungleich dem 'C' ^^ ales klar*. also gibt er deswegen nochma C8 aus und count2 ist wieder 2
            der string is zuende, die counter werden zusammen gezählt** und ergeben 2
            die ratio wird errechnet: 2*100/15=13,333 und zurückgegeben
        <- 13,333
        der rückgabewert wird garnich gespeichert und weiter ausgewertet ><
        er nimmt sich nur wieder die selbe rechnung her für die ratio: wieder 2*100/15 und wieder 13,333
    <- 13,333
    hier natürlich das selbe und schlussendlich wird der wert an die main übergeben
<- 13,333
und die gibt 100-13,333 aus -> 86,667
anmerkung an der stelle: j is eigentlich unnötig. einfach s+i mit s+i+1 vergleichen sollte es auch tun ^^ man müsste aber glaube in der while dann auch s+j oder s+i+1 auf null prüfen! bei der if innendrin dann statt j==1 einfach auf i==0 getestet, fertig. spart ne variable und somit speicher ^^
* ok, beim weiter durchgehen is mir dann aufgefallen, wieso es klappt mit der abbruchbedingung in der while :)
** 2 counter (bzw eben gar 3) is völlig sinnbefreit :P einer reicht hier vollkommen

gut, ok. wir sehen, rein theoretisch sollte er wenigstens ne sinnvolle %zahl ausgeben. wieso da jetz son unfug rauskommt, puh. vllt ergibt ja count1+=printf("%c", *(s+i)); hier mist? printf gibt int zurück und count1 is double. aber ich kann mir nich so ganz vorstellen, das er das ned gebacken bekommt *grübel* wär mMn aber der einzige knackpunkt hierbei.

nun gut. mal paar lösungsansätze:
ich habs ja schon angemerkt, dass du die ratio ned auffängst und weiterverarbeitest, macht das ganze unterfangen recht.... sinnlos ^^ und nebenher: ne ratio kann man so nich berechnen. stell dir vor, du würdest die irgendwie weiterverarbeiten. zum bsp ratio = (ratio + encode_runlength(s+i)) / 2; -> so ala durchschnitt der ratio bilden. dann hättest du bei ABBCCCCCCCCCC -> AB2C10 -> 3*100/13 = 23,08 -> 2*100/13 = (15,38 + 23,08)/2 = 19,23 -> 1*100/13 = (7,69 + 19.23)/2 = 13,46%
so, demgegenüber steht nun die tatsächliche verkürzung von 13 auf 6 zeichen -> 6*100/13 = 46,15%

du siehst - so kommt nur mist raus. besser isses also wenn du die gekürzte länge zurück gibst und immer addierst: counter += encode_runlength(s+i); und dann in der main startest du das ganze genauso und errechnest hier die ratio aus ursprungslänge und counter -> eben jenes (double)counter*100/length was in unserem bsp dem 6*100/13 entspräche und somit ein vernünftiges ergebnis erzielt.

ein passender code könnte also sein:
Code:
#include <stdio.h>

int checkLength(char *s) {
    int length=0;
    while (*(s+length) != '\0') length++;
    return length;
}

int encode_runlength(char *s) {
    int i=0, counter = 0;

    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+i+1)) {
            if (i==0) counter += printf("%c", *(s+i));
            else counter += printf("%c%d", *(s+i), i+1); // die selbsterstellte länge erfassen
            counter += encode_runlength(s+i); // und die länge der anderen rekursiv-instanzen dazuzählen
            break;
        }
        i++;
    }

    return counter;
}

int main(void) {
    char *s = "AAAABBBCCCCCCCCDEABBBBDDDDDDDD";
    int counter, length = checkLength(s);
    double ratio;

    printf("Original:   %s\n", s);
    printf("Codiert:    ");
    counter = encode_runlength(s);
    ratio = (double)counter * 100 / length;
    printf("\nVerk%crzung: %5.2%%\n", 129, ratio);
    printf("Decodiert:\n\n");

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

^^ :fresse: :ugly: :D :schief:

Auf deine Lösung bin ich auch selbst schon gekommen und ich kann mir auch einigermaßen vorstellen, wo der blödsinnige Wert in meiner jetzigen Version herkommt. Ich habe nämlich mal testweise die jeweiligen Werte für count1, count2 und counter ausgeben lassen:

Capture.JPG

count1 und count2 habe in jedem Schleifendurchlauf den richtigen Wert und aufsummiert würde sich tatsächlich 13 ergeben. Das Problem: Es wird nur leider nie aufsummiert (warum auch immer) und somit bleibt counter 0. Wenn man sich das jetzt in der Rechnung anschaut, haben wir (0*100)/30. Tja, das kann nichts Gescheites ergeben ...

Das eigentliche Problem ist aber, dass die Vorgaben in der Angabe (siehe Absatz in/nach Zitat) keinen anderen Weg zulassen und das versuche ich euch schon seit 3 Wochen, oder wann auch immer wir mit dem Beispiel gestartet haben, zu sagen!!! ;)
bräuchte ich einen guten Tipp, wie ich denn nun die Encodierung (also, die verkürzte Zeichenkette) in die Decodier-Funktion rüberbringen kann. Ein Punkt der (strengen) Vorgaben ist nämlich folgender: Es darf ausschließlich mit dem Feld *s gearbeitet werden!

Sobald also der komplette Inhalt encodiert ist, muss ich den Originalinhalt in der Funktion encode_runlength() damit überschreiben und anschließend irgendwie *s nach decode_runlength() verfrachten. Hier aber wieder das Problem: Die Vorgabe besagt, dass encode_runlength() nur die Verkürzung zurückgeben darf und kein Feld, oder sonst was ...
Klar, wenn's nach mir ginge, würde ich zack-bum ein weiteres Feld machen und den codierten string darin speichern. Dann string weiter an decode_runlength() --> wieder decodieren --> fertig. NUR: Darf ich ja nicht! Es darf ausschließlich mit *s gearbeitet werden.
Und als ob das noch nicht Restriktion genug wäre: Die Funktion encode_runlength() darf NUR die brechnete Ratio zurückgeben, nichts anderes!

^^ Bitte bei sämtlichen weiteren Tipps das berücksichtigen. Wie gesagt, mir fallen selbst zig Wege ein, die Aufgabe zu lösen, nur nutzen die uns in dem Fall leider nichts ...

[EDIT]

Hier die Aufgabenstellung. Glaub's zwar nicht, aber vielleicht interpretiere ich das Ganze ja auch falsch?!

Capture1.JPG Capture2.JPG

PS: Dass ich mich noch um Groß-/Kleinschreibung und übergabe des Strings an die main kümmern muss, weiß ich, nur das will ich mir für den Schluss aufheben. :)

[EDIT2]
Habe eben einfach "zum Spaß" jetzt mal deine Version ausprobiert (copy paste in's Visual Studio). Ist aber eine Endlosschleife, die nur "A"s ausgibt. Einfügen geschwungener Klammern, um eventuelle Missinterpretation von zusammengehörigen Befehlen durch den Compiler zu vermeiden, hat auch nichts gebracht. Ich glaube, ganz so weit kann man das dann doch nicht vereinfachen. Was jetzt nur die Codierung selbst betrifft, bleibe ich lieber bei i und j.

Und wenn ich nur die Aufsummierungen nach deinem Schema in meinen Code übernehme, bleibt counter genau 0. Daher: return counter ist praktisch return 0 ... und damit bin ich in etwa soweit, wie heute Nachmittag (siehe erstes Bild in diesem Posting).
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

gut, dann bleibt ansich nur, auf rekursion zu verzichten (wie ichs dir hier eh geraten hätte) und call-by-reference zu verwenden. eine funktion kann nur einen rückgabe-wert haben, und das soll ja scheinbar die ratio sein. wenn du aber *s an sich verändern sollst, muss das ja auch zurück gegeben werden. das klappt ganz "simpel", indem man nicht den wert einer variablen übergibt (die funktionslokale variable kopiert den wert nur), sondern die referenz darauf (einen zeiger). also eigentlich müsste das scho fast klappen *grübel* ^^

nur um die theorie nochmal abzureisen, damit wir auch wissen, wovon wir sprechen:
Code:
void fkt(int i) {
    i++;
    printf("fkt: %d\n", i);
}

void main(void) {
    int a = 2;
    printf("main: %d\n", a);
    fkt(a);
    printf("main: %d\n", a);
}
Ausgabe:
main: 2
fkt: 3
main: 2

in der funktion wird der kopierte wert verändert, nich aber der originale. grund: a aus der main hat die speicheradresse 12345 und i aus fkt is ne andere, neue variable mit der adresse 743375. beim übergeben von a an fkt wird also der wert von a (an adresse 12345) an die adresse von i (743375) kopiert. man verändert mit i also nur die kopie, das original bleibt unberührt.

man kann jetz natürlich den rückgabewert nutzen, was dann so aussähe:
Code:
int fkt(int i) {
    i++;
    printf("fkt: %d\n", i);
    return i;
}

void main(void) {
    int a = 2;
    printf("main: %d\n", a);
    a = fkt(a);
    printf("main: %d\n", a);
}
Ausgabe:
main: 2
fkt: 3
main: 3

aber dann bearbeitet man immernoch nur eine kopie und überschreibt das original dann mit dem wert der kopie. gut, solange der erfolg eintritt, den man will kanns ja erstma wurscht sein. wir haben ja nun aber eben das problem, dass wir keine kopie von a übergeben wollen, sondern a selbst, um dann den rückgabewert für die ratio reservieren/nutzen zu können. das is dann dass call-by-reference. das bisherige war call-by-value.

bei call-by-reference übergibt man nicht den wert von a, sondern den zeiger auf a. mit diesem zeiger kann man nun direkt a aus der funktion heraus verändern:
Code:
void fkt(int &i) {
    i++;
    printf("fkt: %d\n", i);
}

void main(void) {
    int a = 2;
    printf("main: %d\n", a);
    fkt(a);
    printf("main: %d\n", a);
}
Ausgabe:
main: 2
fkt: 3
main: 3

is im endeffekt wieder bsp 1, nur mit nem & vorm funktionsparameter ^^
hier auch nochmal ein intressanter "bericht": call-by-reference @ C/C++ - tutorials.de: Tutorial, Forum, Anleitung & Hilfe is nich allzulang. hier wird auch auf den unterschied zw &var und *var eingegangen. das erste (&) ist c++ und "richtiges" call by reference, das zweite (*) ist die frühe version vom reinen c. nachteil ist wohl, dass man die adresse des pointers nicht ändern kann, nur den inhalt. ich versteh das gerade so: wenn du in der funktion s++ machst um den ointer weiter zuschieben, so geschieht das wiederrum nur lokal. du kannst aber dennoch global die adresswerte ändern - das würde uns ansich auch völlig reichen *denk*

probieren wirs mal ^^
....
............
viele monde später: ich gebs erstma auf >< hab noch Pointer-to-Pointer and Reference-to-Pointer gefunden, was glaub ich prinzipiell ganz gut is, aber irgendwie schmeisst mein visual nur fehler :/
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Call-by-value, call-by-reference, ... kenne ich alles. Ist ja nicht das erste Beispiel, wo wir mit Zeigern arbeiten.

Der Knackpunkt dürfte hier wirklich die Rekursion sein. Wir müssen einen Weg finden, die Zeichenkette nicht in mehreren Anläufen zu codieren, sondern in einem und mit dem Ergebnis dann sofort den Inhalt des Zeigers (also das, was an der Adresse, die er referenziert, steht), was ja die originale Zeichenkette ist, zu überschreiben. Wenn ich dann *s ganz normal in decode_runlength() ausgeben lasse, müsste er mir die codierte Version anzeigen, weil ja die dann an der Adresse von s gespeichert sein müsste. So könnte ich dann auch damit weiterarbeiten.
Interessanter Ansatz, wenn ich das richtig verstanden habe ... :)

Was mir jedoch "Spanisch" vorkommt, ist &irgendwas in einem Funktionsheader. So was haben wir nie gelernt und ich habe sowas auch noch nie gesehen. Es reicht doch, wenn ich mit * auf die Adresse zeige?! Werde mir morgen (also heute später ;)) deine Links ansehen und dann das ganze mal von rekursiv auf iterativ umschreiben. Wenn dann erst einmal die Codierung und die Berechnung/Rückgabe von ratio läuft, überlegen wir weiter ...

[EDIT]
Nur ein Gedankenspiel: Rein theoretisch müsste es doch auch mit dem rekursiven Ansatz gehen, und zwar so --> Nach jeder Runde ist eine Buchstabenfolge codiert. Am Ende jeder Runde überschreibe ich nun im Originalstring immer die beiden Indexstellen der ersten beiden Vorkommen des jeweiligen Buchstaben.

Z.B.: *s = AAAABBBCCCCC --> encode_runlength() läuft --> vor dem nächsten rekursiven Aufruf --> i=0(Buchstabe), j=1(Zahl); *(s+i) und *(s+j) = Ergebnis des Durchlaufs --> *s = A2xxBBBCCC (xx weil ich mir nicht ganz sicher bin, was für die beiden Index-Stellen ausgegeben werden würde) --> in der nächsten Runde würde dann nach der Berechnung xx mit B3 überschrieben werden --> usw. ...

^^ Somit würde ich zwar bereits Werte an der Speicheradresse von s verändern obwohl andere Werte an der selben Speicheradresse noch zur Auswertung benötigt werden, aber da die Vorkommensberechnung jedes Buchstabens eh immer bei einem Index startet, der nach dem überschriebenen liegt, sollten sich Zuweisung(=Überschreibung) und Berechnung nicht in's Gehäge kommen?!

Das muss ich "zum Spaß" direkt mal ausprobieren. :D
Dürfte aber relativ kompliziert zu programmieren sein, falls es überhaupt geht. Was hälst du davon?

[EDIT2]

So, das ^^ oben habe ich nicht hingekriegt. Ist aber auch egal; habe jetzt nämlich eine iterative Lösung ...

Code:
#include <stdio.h>

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

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

    return length;
}

[COLOR=royalblue][B]double encode_runlength(char *s) {
    int i=0, j=1, count=0, length=checkLength(s);
    double ratio=0.0; 

    while (*(s+i) != '\0') {
        if (*(s+i)!=*(s+j)) {
            printf("%c%d", *(s+i), (j-count));
            count=j;
        }
        i++;
        j++;    
    }

    return ratio;
}[/B]
int decode_runlength(char *s) {
    printf("%s\n", s);
}

int main(void) {
    char *s = "AAAABBBCCCCCCCCDEABBBBDDDDDDDD";

    printf("Original:   %s\n", s);
    printf("Codiert:    ");
    printf("\nVerk%crzung: %d %%\n", 129, encode_runlength(s));
    printf("Decodiert:\n\n");
    decode_runlength(s);

    return 0;
}
Jetzt müsste ich irgendwie den codierten String an der Adresse, auf die *s zeigt, speichern, um damit in der Decodierfunktion weiterarbeiten zu können ...
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

das mit der string-änderung sehe ich bei der rekursion auch nich als das problem dabei an - es ist die ratio. er will ja zwingend, dass ne ratio zurück gegeben wird, und das wird schlicht und ergreifend nix, wenn du das in teilschritten machst. hab ich ja weiter oben schonma durchgerechnet:
nun gut. mal paar lösungsansätze:
ich habs ja schon angemerkt, dass du die ratio ned auffängst und weiterverarbeitest, macht das ganze unterfangen recht.... sinnlos ^^ und nebenher: ne ratio kann man so nich berechnen. stell dir vor, du würdest die irgendwie weiterverarbeiten. zum bsp ratio = (ratio + encode_runlength(s+i)) / 2; -> so ala durchschnitt der ratio bilden. dann hättest du bei ABBCCCCCCCCCC -> AB2C10 -> 3*100/13 = 23,08 -> 2*100/13 = (15,38 + 23,08)/2 = 19,23 -> 1*100/13 = (7,69 + 19.23)/2 = 13,46%
so, demgegenüber steht nun die tatsächliche verkürzung von 13 auf 6 zeichen -> 6*100/13 = 46,15%
wenn man die ratien simpel addiert, kämen wir auf ... wow 46,15 ^^ ok, also scheint man die einfach nur addieren zu brauchen, ok. das war mir bisher nich bewusst. dann scheints also doch auch so zu gehn ^^ der übersichtlickheit wegen hätt ichs aber dennoch nicht grad rekursiv gelöst.

meine grundidee dazu war die folgende:
man reduziert alle vorkommen wie gehabt und schreibt das reduzierte immer an den anfang, während man quasi am ende liest. gott, das lässt sich blöd erklären, ich versuchs mal visualisiert darzustellen. hierbei soll jetzt unterstrichen der lese-zeiger sein und fett der schreib-zeiger:

Code:
[COLOR=red][U][B]A[/B][/U]AAABBBCCCCCCCCDEABBBBDDDDDDDD -> er zählt 4 A's und schreibt sie an den anfang. lese-zeiger is beim ersten B, schreiber hinterm A4
A4[COLOR=seagreen][B]A[/B]A[COLOR=red][U]B[/U]BBCCCCCCCCDEABBBBDDDDDDDD_ -> er zählt 3 B's und schreibt sie
A4B3[COLOR=seagreen][B]B[/B]BB[COLOR=red][U]C[/U]CCCCCCCDEABBBBDDDDDDDD_ -> er zählt 8 C's und schreibt sie
A4B3C8[COLOR=seagreen][B]B[/B]CCCCCCCC[COLOR=red][U]D[/U]EABBBBDDDDDDDD_ -> er zählt ein D und schreibt es
A4B3C8D[COLOR=seagreen][B]C[/B]CCCCCCCD[COLOR=red][U]E[/U]ABBBBDDDDDDDD_ -> er zählt ein E und schreibt es
A4B3C8DE[COLOR=seagreen][B]C[/B]CCCCCCDE[COLOR=red][U]A[/U]BBBBDDDDDDDD_ -> er zählt ein A und schreibt es
A4B3C8DEA[COLOR=seagreen][B]C[/B]CCCCCDEA[COLOR=red][U]B[/U]BBBDDDDDDDD_ -> er zählt 4 B's und schreibt sie
A4B3C8DEAB4[COLOR=seagreen][B]C[/B]CCCDEABBBB[COLOR=red][U]D[/U]DDDDDDD_ -> er zählt 8 D's und schreibt sie
A4B3C8DEAB4D8[COLOR=seagreen][B]C[/B]CDEABBBBDDDDDDDD[COLOR=red]_ -> er erkennt das ende und "kopiert" es
A4B3C8DEAB4D8_[COLOR=seagreen][B]C[/B]DEABBBBDDDDDDDD[COLOR=red]_
da erkennt mans hoffentlich ganz gut, dass die sich ned in die quere kommen und das klappen dürfte.

so wegen dieser c_by_ref geschichte: hab hier nochmal nen link gefunden - The Use of * and & in C/C++ . ein & stellt also die adresse der variablen dar. ah ok, jetz hab ichs glaube:
References, pointers and addresses are closely related concepts. Addresses are addresses in computer memory (typically the address in memory where the value of some variable is stored), e.g. (in hexadecimal) 0xAB32C2. Pointers are variables which hold addresses, and so "point to" memory locations (and thus to the values of variables). Conceptually, reference variables are basically pointers by another name (but may not be instantiated as such by the compiler).
also die adresse an sich ist der punkt im speicher, wo meine variable steht. ein zeiger (*p) zeigt nun auf diese adresse. der zeiger selbst ist eine variable, die an einer anderen speicher adresse steht, deren wert die adresse der variablen ist, auf die er zeigt.
Code:
int i = 15;
int *p = &i; // wenn mich jetz nich alles täuscht. mit & bekommt man die adresse einer variablen
Adresse|Wert|Var-Name
123|15|i
...||
234|123|p
der knackpunkt ist nun folgender:
übergibst du nun den zeiger an eine funktion, so wird dieser wieder nur kopiert. man hat also quasi sowas hier dann:
Code:
void fkt(int *q) {}
void main(void) {
    int i = 15;
    int *p = &i;
    fkt(p);
}
Adresse|Wert|Var-Name
123|15|i
...||
234|123|p
...||
345|123|q
so, jetz kommt das große überlegen. weil mir erscheint das auf anhieb garnich schlecht ^^ mit q kann ich auf die speicheradresse zugreifen und den wert darin ändern, so eigentlich. das machen wir ja die ganze zeit. veränder ich q (iteriere durch den string) bleibt p in der main davon unberührt. also während ich in der funktion q auf stelle 5 habe, ist p immernoch am anfang. das wäre für die weitere verwendung zum dekodieren ganz praktisch so :P

gut, jetzt mal zu dem & ding da. mit & gibt man der variablen wohl nen 2. namen, mal blöde gesagt. also quasi so in etwa:
Code:
void fkt(int &q) {}
void main(void) {
    int i = 15;
    int *p = &i;
    fkt(p);
}
Adresse|Wert|Var-Name
123|15|i
...||
234|123|p,q
wobei ich hier eben grad nich weis, ob das schon der springende punkt ist. denn im urpsungszenario siehts ja so aus:
Code:
void fkt(int &q) {}
void main(void) {
    int i = 15;
    fkt(i);
}
Adresse|Wert|Var-Name
123|15|i,q
also man übergibt die variable an sich und hat in der funktion eine referenz, quasi einen zweiten namen für ein und die selbe speicherstelle. verändere ich hier nun q in der funktion, bleibt die änderung auch ausserhalb bestehen. bei normalen variablen. ich werfe i rein und die funktion krallt sich die adresse von i für q. ja genau. will ich nun aber eben einen zeiger übergeben, klappt das so nich mehr. wobei wir wieder bei dem vorletzten bsp wären, wo ich ja p als zeiger auf i baue und der funktion übergeb. was passiert hier? mal überlegen. ich werfe p in die funktion und q krallt sich dessen adresse. also scheint meine tabelle da oben auch zu stimmen. p und q sind variablen namen für ein und die selbe speicheradresse.

ok, gut so weit. wenn ich jetzt innerhalb der funktion mit q rum iteriere (also hier geh ich ma nich vom i ausm bsp aus, da gibts nix zu iterieren ^^, sondern von unsrem char *s ^^), dann zeigt auch ausserhalb p auf diese position. wöllte ich dann also danach unseren string per zeiger an die decode funke übergeben, müsste ich ihn erst wieder auf den anfang setzen.

so, um nun auf den wert der variablen hinter der adresse zu kommen, muss man wieder den * benutzen. also int *p; p = &i; dann ist p die adresse von i und *p der wert, wenn ichs richtig verstanden hab.

nun gut, jetz will ich mal dieses schon genannte ( Pointer-to-Pointer and Reference-to-Pointer ) bsp durchprobieren: teil1:
Code:
int g_One = 1; //global variable

void func(int* pInt) {
  pInt=&g_One;
}

int main() {
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  std::cout<<*pvar<<std::endl;    //Will still show 2
  return 0;
}
Adresse|Wert|Var-Name
123|1|g_One
124|2|nvar
...||
234|124|pvar
...||
345|234|pInt
das müssts sein jetz. er versucht, in der funktion den wert für die ausserhalb der funktion stehende pvar-variable zu ändern. klappt aber nich. ja genau, das is genau das, was wir hier schon durchgegangen sin: pInt (in der funktion) kopiert nur pvar. man ändert also die kopie (welche am ende der funktion wieder verfällt) und nicht das original. würde man innerhalb der funktion noch ne ausgabe machen, würde er tatsächlich den wert von g_One ausgeben, weil pInt jetzt darauf zeigt. pInt ist aber eben nicht pvar, sondern nur eine kopie davon. pvar selber bleibt unberührt davon.

sein 2. bsp:
Code:
void func(int** ppInt) {
  //Modify the pointer ppInt points to
  *ppInt=&g_One;
  //You can also allocate memory, depending on your requirements
  *ppInt=new int;
  //Modify the variable *ppInt points to
  **ppInt=3;
}

int main() {
  int nvar=2;
  int* pvar=&nvar;
  func(&pvar);
  ....
  return 0;
}
Adresse (wo)|Wert (was)|Var-Name
123|2|nvar
...||
234|123|pvar
...||
345|234|ppInt
hmm. er übergibt nun also die adresse vom pointer an die funktion. und die funktion greift dank ** was auf? den wert oder? * von & wäre die adresse von pvar meines erachtens nach. und der * dieser adresse (der * vom * -> **) müsste nun doch der wert sein. den erklärungen im text danach zu folge dürfte das stimmen. mit *ppInt ändere ich die adresse, auf die pvar (also auch ausserhalb) zeigt, mit ** würde ich dann ändern "what pvar points to", also auf was pvar zeigt. ja genau, nich wohin es zeigt, sondern auf was es zeigt - den wert. ändere ich also nun in der funktion was an ppInt, dann hat das nach aussen keinerlei auswirkung, da es nur eine kopie ist. hmm, warscheinlich muss man das ganze in der tabelle sogar erweitern, da es ne "tiefere" kopie ist:
Adresse (wo)|Wert (was)|Var-Name
123|2|nvar
...||
234|123|pvar
...||
345|2|**ppInt
346|123|*ppInt
347|234|ppInt
wobei das auch nich sehr schlüssig aussieht. die 2 neuen zeilen hier sind warscheinlich "einfach" bestandteil von ppInt - mitkopiert. ich ändere also die "tieferliegenden bestandteile" von ppInt, nicht aber pvar oder gar nvar. also: was ich in der funktion änder, hat hier auch wieder nur in der funktion auswirkung. die äusseren variablen bleiben davon unberührt.

wad macht nun aber das 3, bsp wieder anders? ma schauen, dann erstma schluss ><
Code:
int g_One=1; //global variable

void func(int*& rpInt)
{
  //Modify what pvar is pointing to, to g_One
  rpInt=&g_One;
  //You can also allocate memory, depending on your requirements
  rpInt=new int;
  //Modify the variable rpInt points to
  *rpInt=3;
}

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  ....
  return 0;
}
Adresse (wo)|Wert (was)|Var-Name
123|1|g_One
124|2|nvar
...||
234|124|pvar, rpInt
hier wird nun also eine referenz des zeigers (*&) pvar angelegt. man bekommt also tatsächlich den zeiger pvar innerhalb der funktion und keine kopie davon. jetzt kann ich wieder ganz normal innerhalb der funktion die adresse für pvar ausserhalb ändern - und auch den wert der variablen ausserhalb, auf die pvar zeigt (also nvar) kann ich von innen her ändern.

gut gut, ich glaube, die letzte version wäre für uns ganz brauchbar oder? so hab ichs gestern auch schon versucht, aber ohne dieses durchexerzieren und das tiefere verständnis. nu wäre ich gespannt, obs mir jetz besser gelingen würde ><

nun gut, genug geschrieben, ich hoffe ihr kamt alle mit und konntet mir folgen. und vorallem hoffe ich, das ich ned allzuviel bull *piep* verzapft hab hier xD
 
Zurück