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

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

Mit zwei Änderungen läuft es bei mir durch:

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

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

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

    /* FIX off by one */
    i = length1 - 1; /* length1 = Länge des codierten Strings. */
    while (i > 0)
    { /* 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)
        { /* Zahl gefunden. */
            k++;
            count1 = (*(s + i) - 48);
            count2 += (count1 * (int) pow(10., k - 1)); /* Berechne Gesamtzahl als integer. */
            if (*(s + i - 1) >= 65 && *(s + i - 1) <= 90)
            {
                length2 += count2;
                length2--; /* Zahlen geben bereits Vorkommen des jeweiligen Buchstabens an. Dieser darf nicht auch noch dazugezählt werden. */
            }
        }
        else if (*(s + i) >= 65 && *(s + i) <= 90)
        { /* Buchstabe gefunden. */
            length2++;
            count2 = 0;
            k = 0;
        }
        i--;
    }

    return (length2 + 1);
}

/*
 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++; /* 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++;
    }

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

    printf("%s", s); /* 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++;
    }

    /* Decodiere String: */
    length1 = checkLength(s);
    i = length1 - 1; /* length1 = Originallänge des Strings. */
    /* FIX off by one */
    j = length2 - 1; /* length2+1 = Länge des codierten Strings. */
    while (i > 0)
    {
        if (*(s + j) >= 48 && *(s + j) <= 57)
        { /* Zahl gefunden. */
            k++;
            count1 = (*(s + j) - 48);
            count2 += (count1 * (int) pow(10., k - 1)); /* Berechne Gesamtzahl als integer und ... */
            if (*(s + j - 1) >= 65 && *(s + j - 1) <= 90)
            {
                temp1 = (count2 - 1);
                temp2 = count2;
            }
            while (temp1 > 0)
            { /* ... ü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)
        { /* Buchstabe gefunden. */
            *(s + i) = *(s + j);
            i--;
            count2 = 0;
            k = 0;
        }
        j--;
    }
    *(s + length1) = '\0'; /* Hänge an die Decodierung noch eine Nullterminierung an. */

    printf("%s", s); /* Ausgabe: Decodierter String */

    return 0;
}

int main(void)
{
//int main(int argc, char *argv[]) {
    //char *s = argv[1];
    char s[] = "ABBBBBBBBAAAAAAAAACCCCCCCCCCCCCCCCCCD";
    //char s[] = "ABB";
    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 habe die Stellen mit /* FIX ... */ markiert. Du hast jeweils bei einem Element zu früh angefangen (Array-Index beginnt bei 0 und nicht bei 1, d. h. du darfst nur von 0 bis len - 1 bzw. len - 1 bis 0 laufen). Dazu ist Einzelschritt-Debugging ganz hilfreich: Einfach ein paar Breakpoints an geeigneten Stellen setzen, sich durchhangeln und die Schritte mit dem kodierten String vergleichen.
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Vielen herzlichen Dank! :daumen:
Macht natürlich Sinn, was du schreibst. Breakpoints hätte ich auch gesetzt gehabt und Debuggen tue ich immer, wenn ich Fehler suche, nur waren meine Breakpoints wohl an anderen Stellen, als deine, weil ich den Fehler ganz woanders vermutet hatte ...

Habe ich das Beispiel endlich fertig! ;)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ja, das mit dem Debuggen ist manchmal ein wenig tricky. Da hilft eigentlich nur Erfahrung und ausprobieren ^^ Freut mich aber, dass es bei dir jetzt auch funktioniert :)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Was mir gerade noch aufgefallen ist: Wir sagen jetzt in checkLength(): i=length1-1; und am Ende dann length2+1. Für meine Logik könnte man daher das -1 und das +1 streichen. Ein erster Test bestätigt dies. Möchte aber noch weitertesten, bevor ich's wirklich mache ...

[EDIT]
Am Lauflängencodierungscode kann man wohl doch nichts mehr ändern. Habe noch einiges getestet; der Code ist wirklich final. :)

Eine andere Frage:
Wir habe hier vor langer Zeit mal eine Häufigkeitsanalyse geschrieben und die habe ich mir heute wieder angeschaut. Habe da jetzt was dazuprogrammiert, dass er überprüft, ob eh eine korrekte Parameterzahl (genau 2. 1 --> Programmaufruf, 2 --> Zu überprüfender Satz) eingegeben wurde. Wenn nicht, soll das Programm abbrechen. Allerdings wird immer nur die erste Fehlermeldung vom if ausgegeben ("Missing parameters") und ich komm' nicht drauf, warum. Eingegeben wird's doch so in die cmd: Programmname "Zu ueberpruefender Satz."

Programmname = erster Parameter
alles innerhalb der Anführungszeichen = zweiter Parameter
^^ ???
Code:
#include <stdio.h>
#include <stdlib.h>

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

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

void analyzeString(char *s) {
    int charCount[27]={0}, i=0, j=0, k=0, counter=0, ascii=0, length=checkLength(s);
    float percentage=0.0;

    [COLOR=seagreen]/* Anzahl der Buchstaben des Satzes und deren Häufigkeit ermitteln: */    while (i!=length) {
        if (*(s+i)>='A' && *(s+i)<='Z') {
            ascii=((int)*(s+i))-65; [COLOR=seagreen]/* int Werte von Großbuchstaben in den Bereich zwischen 0 und 25 runterrechnen. */        } else if (*(s+i)>='a' && *(s+i)<='z') {
            ascii=((int)*(s+i))-97; [COLOR=seagreen]/* int Werte von Kleinbuchstaben in den Bereich zwischen 0 und 25 runterrechnen. */        } else {
            ascii=((int)*(s+i)); [COLOR=seagreen]/* Sonderzeichen haben Werte außerhalb des Bereichs 0 bis 25. */            charCount[26]++; [COLOR=seagreen]/* Für jedes Sonderzeichen wird Wert im letzten Feldelement inkrementiert. */        }
        if (ascii>=0 && ascii<=25) {
            counter++;
            charCount[ascii]++;[COLOR=seagreen] /* Wert an der Stelle des Feldindex (0 bis 25) des jeweiligen Buchstaben wird bei Vorkommen inkrementiert */        }
        i++;
    }

    printf("Character count: %d (100 %%)\n", counter);
    printf("\nDetailled Frequence Analysis:\n");
    printf("\n  : count : percentage\n======================\n");
    for (j='a', k=0; j<='z', k<=25; j++, k++) {
        percentage=(((float)charCount[k]*100)/(float)counter);
        printf("%c :%6d :%11.2f\n", j, charCount[k], percentage);
    }
    putchar('\n');
}

[COLOR=royalblue][B]int main(int argc, char *argv[]) {
    char *s = argv[1];

    if (argc=1) {
        printf("Invalid input! Missing parameter.\n");
        exit(1);
    } else if (argc>2) {
        printf("Invalid input! Too many parameters.\n");
        exit(1);
    } else {
        analyzeString(s);
    }[/B]
    return 0;
}
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Ah ja, wie peinlich! Ist wohl der Schlafentzug der letzten Tage ... :fresse:

BTW: Habe doch noch Optimierungspotenzial bei der Lauflängencodierung gefunden. Die ganze calcSteps() Funktion müsste man durch geschicktes Dekrementieren an den richtigen Stellen ersetzen können. Muss das noch ausprobieren. Statt pow müsste auch ein mehrfaches k*=10 möglich sein. Mal schauen, was da noch geht.

Bleibt für's erste nur meine Frage zu den komplexen Zahlen im Raum: Wie genau interpretiert ihr den Satz aus der Angabe (Achte auch auf die konkrete Verwendung von Blanks!) ? Hier mein Code:
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) {
        if (k->real>0 && k->imaginary>0) {[COLOR=seagreen] /* + + */            printf("( %.2f + %.2fi )\n", k->real, k->imaginary);
        } else if (k->real<0 && k->imaginary<0) { [COLOR=seagreen]/* - - */            k->real*=-1;
            k->imaginary*=-1;
            printf("( - %.2f - %.2fi )\n", k->real, k->imaginary); 
        } else if (k->real<0 && k->imaginary>0) { [COLOR=seagreen]/* - + */            k->real*=-1;
            printf("( - %.2f + %.2fi )\n", k->real, k->imaginary);
        } else if (k->real>0 && k->imaginary<0) { [COLOR=seagreen]/* + - */            k->imaginary*=-1;
            printf("( %.2f - %.2fi )\n", k->real, k->imaginary);
        }
    }
}

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;
}
Heißt das nur, dass eben in der Ausgabe zwischen Rechenzeichen und Zahl ein Leerzeichen sein muss? Dann wäre das Ganze ja mit meinem (unschönen) if-else Konstrukt erledigt. Oder soll das heißen, dass ich meine float Zahlen zerlegen und in einen char string packen muss, und in diesem dann Indexe bis zum Rechenzeichen durchfahren, nachfolgende Zahl nach hinten schieben und ein char 'Leerzeichen' einfügen soll?
Was würdet ihr euch zu dieser Aufgabe als Abgabe erwarten, wenn ihr der Lehrer wärt?

Ich persönlich würde die Aufgabe als erledigt entsprechend der Angabe betrachten, aber vielleicht sieht das jemand anders?! :)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ich habe ein paar Frage zu Einfach Verketteten Listen. Dazu auch ein Code-Beispiel:

Diesmal geht's nur um Erklären, nichts Programmieren ... ;)

Hier startet die Verkettete Liste (main):
Code:
typedef struct element {
    int id; [COLOR=seagreen]/* Element id */    char * daten; [COLOR=seagreen]/* Datenfeld des Listenelementes */    struct element *next; [COLOR=seagreen]/* Zeiger auf das naechste Listenelement */} Element;

int main() {
    int max = 10;
    Element *liste = NULL; [COLOR=seagreen]/* Anker der Liste im Hauptprogramm */    int i;
    
    [COLOR=seagreen]/* Liste mit 10 Elementen anlegen */    for (i=0;i<max;i++)
        liste = element_einfuegen (liste, i, "Wirf den Ring ins Feuer");
        
   [COLOR=seagreen] /* Inhalt aller Elemente schreiben */    for (i=0;i<max;i++)
        element_schreiben(liste, i);
    
    [COLOR=seagreen]/* Element zur Liste fuegen */    liste = element_einfuegen(liste, 11, "Wirf Schneewittchen ins Feuer");
    
    [COLOR=seagreen]/* Element aus der Liste loeschen */    element_loeschen(liste, 5);
    
   [COLOR=seagreen] /* Freigeben der Listenelemente */    free_liste (liste);
    
    printf ("end\n");
}
^^ Da ist noch alles klar.

Einfügen eines Elements:

Code:
[COLOR=seagreen]/*
* Element * element_einfuegen (Element *liste, int id, char *text) - Erstellt ein
* neues Element (Mit id und *text) und fuegt es am Anfang der Liste ein.
* @*liste: Zeiger auf den Beginn der Liste
* @id: Identifier des neuen Listenelements
* @*text: Textinhalt des neuen Listenelements
* @return: Zeiger auf das neue erste Element der Liste oder im Fehlerfall die
* bisherige Liste
*/Element * element_einfuegen (Element *liste, int id, char *text) {
    Element *helper = (Element*) malloc (sizeof(Element));
    printf("Element: %d einfuegen\n", id);
    
    if (helper == NULL) {
        printf("Fehler: Speicherprobleme\n");
        return liste;
    }

    [COLOR=darkorchid]helper->id = id;
    helper->daten = text;
    helper->next = NULL;
   [COLOR=seagreen] /* neues Element wird an den Anfang der Liste gesetzt */    [COLOR=darkorchid]helper->next = liste;    printf("Element: %d eingefuegt Daten: %s\n", [COLOR=darkorchid]helper->id, helper->daten);

    return helper;
}
^^
1. Was genau macht Element *helper hier bzw. wofür brauche ich das? Ist Element *helper das neue Listenelement, das am Anfang der Liste eingefügt wird?
2. Was genau bekommen die jeweiligen Komponenten des zusammengesetzten Datentyps helper in den lila Zeilen zugewiesen? id und text, die der Funktion übergeben werden?
3. Und wieso setze ich den Zeiger zuerst auf NULL, wenn das neue Element doch am Anfang der Liste eingefügt werden soll? Nur der Zeiger des letzten Listenelements zeigt auf NULL?! Und danach plötzlich auf liste? "liste" steht hier für das zweite Listenelement, oder? Und somit wäre helper dann das erste und würde auf das zweite verweisen?!
4. Und im printf werden den Komponenten von helper wieder die Werte, die der Funktion übergeben werden, zugewiesen, oder wie?

Suchen von Elementen:
Code:
[COLOR=seagreen]/*
* Element * element_suchen (Element *liste, int id) – Sucht
* das Element mit der id in der Liste liste
* @*liste: Zeiger auf das erste Element der Liste
* @id: Identifier des zu suchenden Listenelements
* @return: ein Zeiger auf das gesuchte Element oder NULL, falls das
* Element nicht in der Liste enthalten ist
*/Element * element_suchen (Element *liste, int id){
    [COLOR=darkorchid]Element * result = liste;    
    printf("Element: %d suchen\n", id);

    while ((result != NULL) && [COLOR=darkorchid](id != result->id))
        [COLOR=darkorchid]result = result->next;
    if (result != NULL) 
        printf("Element: %d gefunden\n", result->id);

    return result;
}
^^
1. Kann man einfach einem struct ein anderes zuweisen, oder was genau passiert in der ersten lila Zeile? Wieso soll liste laut Kommentar nur ein Zeiger sein? next ist doch der Zeiger in dem struct?!
2. Die while Schleife soll laufen, bis entweder das Ende der verketteten Liste erreicht ist, oder die id des gesuchten Elements und somit das Element selbst gefunden wurde. Aber was genau sind die zwei id's hier? Das erste id ist wohl das, das an die Funktion zum Suchen übergeben wird, aber das zweite?
3. Und die dritte lila Zeile: Wie genau muss ich das verstehen? Der next pointer von result soll immer um ein Element weiter zeigen, aber wie/wo wird next weitergesetzt, wenn das gesuchte Element im jeweiligen Schleifendurchlauf noch nicht gefunden wurde?

Löschen eines Elements:
Code:
[COLOR=seagreen]/*
* int element_loeschen (Element *liste, int id) - Sucht das Element
* mit der id in liste und loescht dieses
* @*liste: Zeiger auf das erste Element der Liste
* @id: Identifier des zu löschenden Elements
* @return: Liste ohne geloeschtes Element
*/Element * element_loeschen (Element *liste, int id) {
    [COLOR=darkorchid]Element *delElem = liste , *vorgaenger = NULL;    printf("Element: %d loeschen\n", id);

    while ((delElem != NULL) && (id != delElem->id)) {
        [COLOR=darkorchid]vorgaenger = delElem;
        delElem = delElem->next;    }

    if (delElem == NULL)
        printf("Element nicht gefunden\n");
    else [COLOR=darkorchid]if (vorgaenger == NULL) {
        liste = delElem->next;        printf("Element: %d wird geloescht\n", delElem->id);
        free (delElem);
    } else {
        [COLOR=darkorchid]vorgaenger->next = delElem->next;        printf("Element: %d wird geloescht\n", delElem->id);
        free (delElem);
    }
    
    return liste;
}
^^
1. Hier verstehe ich auch wieder die lila Zeilen nicht wirklich. Ich weiß auch nicht genau, was ich fragen soll. Erklärt mir bitte einfach wozu das, was passiert, passieren muss.

Ausgabe eines Elements:
Code:
[COLOR=seagreen]/*
* int element_schreiben(Element *liste, int id) – Gibt den Inhalt 
* eines Elements (id und *daten) aus. 
* @*liste: Zeiger auf das erste Element der Liste 
* @id: Identifier des auszugebenden Elements 
* @return: 0 falls die Ausgabe erfolgreich war, 1 falls das Element 
* nicht gefunden wurde 
*/ int element_schreiben(Element *liste, int id) { 
    Element *elm = NULL; 
    
    printf("Element: %d schreiben\n", id); 
    
    elm = element_suchen (liste, id); 
    
    if (elm == NULL) 
        return 1; 
    else { 
        printf("Element: %d Daten: %s\n", elm->id, elm->daten); 
        return 0; 
    } 
}
^^ Das ist wieder klar.
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Einfügen:
Helper ist halt das neue Element, was eingefügt werden soll. Der helper ist natürlich jetzt natürlich nur ein Speicherbereich ohne Funktion! Die Daten ID/Text/Next-Element machen den Bereich halt für dich in der verketteten Liste nutzbar und deswegen setzt du da ID/Text auf die Parameterwerte.
Warum jetzt das Next-Element zuerst auf NULL und dann auf nen gültigen Wert gesetzt wird weiß ich nicht, vielleicht weil in dem Speicher vorher (vor setzen auf NULL) nur KrimsKrams drinsteht und du damit sichergehst, dass das überschrieben wird, aber das machst du eigentlich dann auch mit setzen auf liste --> auf NULL finde ich da überflüssig^^

Suchen:
Result ist der zeiger auf das Element, das die gesuchten Daten enthält. Und wie sucht man? Richtig man setzt in der ersten violetten Zeile Den Zeiger auf das erste Listenelement (bzw. den Zeiger darauf).
Falls du irgendwann bei der richtigen ID (id = gesuchte id und Bedingung ist id == result->id, weil das ja immer das aktuell betrachtete Litenelement repräsentiert) angekommen bist, enthält result den Zeiger auf das Element, falls es die ID nicht gibt, ist result = NULL, weil das letzte Element der Liste ja NULL als Next-Element hat --> Abbruchbedingung
Vielleicht ist Punkt 3 so einfacher zu verstehen:
Code:
int find(int wert)
{
    int result = 0;
    while(result != NULL oder sonstwas && result != wert)
    {
          result = result + 1;
    }
    return result; // result == wert, sinnlos, aber vielleicht ja repräsentativ^^
}

Das gleiche Vorgehen wendest du halt auch auf die Liste an, nur dass du da die IDs vergleichst, Abbruch ist NULL=result und result = result + 1 ist halt das Next-Element von result immer.


Löschen:
Du brauchst einmal wieder das aktuelle Element und einmal den Vorgänger, weil stell dir mal die Liste so vor:
AABBABAAACBBABAA
Und jetzt löschst du "C"!
Dann musst du schauen, wann du bei "C" angekommen bist (im obigen Code wieder ID-Vergleich) und dann entsprechen vom Vorgänger "A" das NextElement auf "C"->NextElement setzen, denn wenn du C löschst musst du die entstandene "Lücke" ja überbrücken, sonst würde deine Liste immer wieder mitten in der Wallachei aufhören :D

Konkreter Fall:
delElem = "C"
vorgänger = "A" (also ein bestimmtes)

Die obere Schleife bricht ab, weil C != NULL und IDs stimmen überein. Nun füllst du halt je nach Fall (direkt Start der Liste/mittendrin/Ende der Liste) die entstandene Lücke auf.

Hoffe ist einigermaßen verständlich^^
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ok, danke! Bis auf das Löschen des Elements habe ich alles einigermaßen verstanden ...

Dazu noch einmal:
Code:
Element * element_loeschen (Element *liste, int id) {
    [COLOR=darkorchid]Element *delElem = liste , *vorgaenger = NULL;    printf("Element: %d loeschen\n", id);

    while ((delElem != NULL) && (id != delElem->id)) {
        [COLOR=darkorchid]vorgaenger = delElem;
        delElem = delElem->next;    }

    if (delElem == NULL)
        printf("Element nicht gefunden\n");
    else [COLOR=darkorchid]if (vorgaenger == NULL) {
        liste = delElem->next;        printf("Element: %d wird geloescht\n", delElem->id);
        free (delElem);
    } else {
        [COLOR=darkorchid]vorgaenger->next = delElem->next;        printf("Element: %d wird geloescht\n", delElem->id);
        free (delElem);
    }
    
    return liste;
}
Das if ist klar --> Das Element, das gelöscht werden soll, gibt's gar nicht. Aber was ist der Unterschied zwischen dem else if und dem else? In beiden Fällen wird was gelöscht ...
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

if (delElem == NULL) --> Element nicht Existent
else if (vorgaenger == NULL) --> delElem ist ERSTES Element der Liste.
Beispielfall: CAABB ist Liste und du möchtest C löschen. Jetzt kommst du da an delElem ist C und vorgänger ist NULL, weil da halt noch nix is.
C wird gelöscht und Liste müsste ja mit A anfangen, und das ist delElem->next (was dann der neue Listenanfang ist)

else --> wie im obigen Post erwähnt, "Lücke" des Löschens füllen.
Bsp1: AACBAAB muss ja in AABAAB resultieren und AABAABC[NULL] müsste ja in AABAAB[NULL] resultieren
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Achso, der Anker einer verketteten Liste ist ebenfalls NULL (sieht man in der main). Nicht nur der Zeiger des letzten Elementes. Jetzt wird das klarer ...

Ok, danke! Das reicht mir für's erste. Wenn noch Fragen auftauchen, melde ich mich wieder. :)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ich bräuchte einen Code, der mir aus einem vorgegebenen Buchstaben-String alle möglichen Kombinationen (mit Mehrfachvorkommen) berechnet. In der Fachsprache "Permutation MIT Wiederholung" genannt.
Irgendwo in meinen Ansätzen dürfte ich einen Denkfehler drinnen haben, weil am Ende immer wieder nur eine Permutation OHNE Wiederholung rauskommt. Und man findet auch nur das (in allen möglichen Programmiersprachen) im Internet, weshalb ich auch keine vernünftigen Code-Beispiele habe, an denen ich mich orientieren könnte.

Das hier z. B. wäre ne perfekte Permutation OHNE Wiederholung. Nur wie bastle ich das so um, dass ich eine MIT WH habe? :huh:
Code:
#include <stdio.h>
#include <string.h>

void swap(char a[], int i, int j) {
    char temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

void permut(char a[], int endIndex) {
    int i = 0;

    if (endIndex == 0) {
        printf("%s\n", a);
    } else {
        permut(a, endIndex-1);
        for (i = 0; i <= endIndex-1; i++) {
            swap(a, i, endIndex);
            permut(a, endIndex-1);
            swap(a, i, endIndex);
        }
    }
}

int main(void) {
    char str[] = "ahlo";
    int maxIndex = strlen(str)-1;

    permut(str, maxIndex);

    return 0;
}
Ich verlange auch nicht, dass mir jetzt wer einen fertigen Code "hinknallt", sondern ich wäre schon über Lösungsansätze und Ideen froh ...
(Ober rekursiv oder iterativ ist auch egal)
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Auf der Seite war ich schon, aber ich krieg's nicht hin, den passenden Code richtig nach C umzuschreiben. Ich schau mir das morgen nochmal an ...
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

Ich bräuchte einen Code, der mir aus einem vorgegebenen Buchstaben-String alle möglichen Kombinationen (mit Mehrfachvorkommen) berechnet.
bin mir nicht ganz sicher ob ich das richtig verstanden habe, aber der Code gibt dir für die Zeichenkette "ab" mit einer Ziellänge von 2 das hier aus:

Code:
aa
ab
ba
bb


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

const char* text = "ab";

/**
 * Permutation mit Wiederholungen
 * @param string zu permutierender String
 * @param strLen Laenge des strings
 * @param desLen Laenge der zu erstellenden Permutationen
 */
void permute(const char* string, int strLen, int desLen) 
{
	int number[desLen];
	char out[desLen];
	int i = 0;
	int j = 0;
	const int max = desLen * (strLen-1);
	while(i != desLen) 
	{
		number[i] = 0;
		out[i] = string[0];
		++i;
	}	

	printf("%s\n", out);
	i = 0;

	while(i != max) 
	{
		while(1)
		{
			++i;
			if(++number[j] < strLen)
			{
				out[j] = string[number[j]];
				break;
			}

			i -= strLen;
			out[j] = string[0];
			number[j] = 0;
			++j;
		}
		j = 0;

		printf("%s\n", out);
	}
}


int main(int argc, char** argv) 
{
	permute(text, strlen(text), 2);
	return 0;
}


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

^^ Ja, danke! Das ist jetzt eine Permutation mit Wiederholung. Nur zwei Probleme hat der Code in dieser Form laut Visual Studio:

1) Irgendwo wird offenbar eine Feldgrenze überschritten?!

Capture.JPG

2) Auch wenn ich das ebenso gemacht hätte, das hier wird rot unterwellt, weil desLen ein "constant value" sein muss:
Code:
void permute(const char* string, int strLen, int desLen) {
    int number[[COLOR=red]desLen];
    char out[[COLOR=red]desLen];
Muss ich jetzt wirklich ein dynamisches Array dafür erstellen, oder lässt sich das noch anders lösen? Bzw. mit einem Macro müsste es auch gehen, wäre aber ebenso wenig "ellegant".
 
Zuletzt bearbeitet:
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

^^ Ja, danke! Das ist jetzt eine Permutation mit Wiederholung. Nur zwei Probleme hat der Code in dieser Form laut Visual Studio:

1) Irgendwo wird offenbar eine Feldgrenze überschritten?!

Anhang anzeigen 733874
Das Problem ist, dass dein String vermutlich kein null-Charakter besitzt. Das Problem sollte durch
Code:
a[length] = '\0';
gelöst werden können.


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

const char* text = "ahlo";

/**
* Permutation mit Wiederholungen
* @param string zu permutierender String
* @param strLen Laenge des strings
* @param desLen Laenge der zu erstellenden Permutationen
*/
void permute(const char* string, int* number, char* out, int strLen, int desLen)
{
	int i = 0;
	int j = 0;
	const int max = desLen * (strLen - 1);
	while (i != desLen)
	{
		number[i] = 0;
		out[i] = string[0];
		++i;
	}

	printf("%s\n", out);
	i = 0;

	while (i != max)
	{
		while (1)
		{
			++i;
			if (++number[j] < strLen)
			{
				out[j] = string[number[j]];
				break;
			}

			i -= strLen;
			out[j] = string[0];
			number[j] = 0;
			++j;
		}
		j = 0;

		printf("%s\n", out);
	}
}

int main(int argc, char** argv)
{
	int length = strlen(text);
	char* a = malloc((length + 1) * sizeof(char));
	a[length] = '\0';
	int* n = malloc(length * sizeof(int));
	permute(text, n, a, strlen(text), length);
	free(a);
	free(n);
	getchar();
	return 0;	
}

Ausgabe:
Code:
aaaa
haaa
laaa
oaaa
ahaa
hhaa
lhaa
ohaa
alaa
hlaa
llaa
olaa
aoaa
hoaa
loaa
ooaa
aaha
haha
laha
oaha
ahha
hhha
lhha
ohha
alha
hlha
llha
olha
aoha
hoha
loha
ooha
aala
hala
lala
oala
ahla
hhla
lhla
ohla
alla
hlla
llla
olla
aola
hola
lola
oola
aaoa
haoa
laoa
oaoa
ahoa
hhoa
lhoa
ohoa
aloa
hloa
lloa
oloa
aooa
hooa
looa
oooa
aaah
haah
laah
oaah
ahah
hhah
lhah
ohah
alah
hlah
llah
olah
aoah
hoah
loah
ooah
aahh
hahh
lahh
oahh
ahhh
hhhh
lhhh
ohhh
alhh
hlhh
llhh
olhh
aohh
hohh
lohh
oohh
aalh
halh
lalh
oalh
ahlh
hhlh
lhlh
ohlh
allh
hllh
lllh
ollh
aolh
holh
lolh
oolh
aaoh
haoh
laoh
oaoh
ahoh
hhoh
lhoh
ohoh
aloh
hloh
lloh
oloh
aooh
hooh
looh
oooh
aaal
haal
laal
oaal
ahal
hhal
lhal
ohal
alal
hlal
llal
olal
aoal
hoal
loal
ooal
aahl
hahl
lahl
oahl
ahhl
hhhl
lhhl
ohhl
alhl
hlhl
llhl
olhl
aohl
hohl
lohl
oohl
aall
hall
lall
oall
ahll
hhll
lhll
ohll
alll
hlll
llll
olll
aoll
holl
loll
ooll
aaol
haol
laol
oaol
ahol
hhol
lhol
ohol
alol
hlol
llol
olol
aool
hool
lool
oool
aaao
haao
laao
oaao
ahao
hhao
lhao
ohao
alao
hlao
llao
olao
aoao
hoao
loao
ooao
aaho
haho
laho
oaho
ahho
hhho
lhho
ohho
alho
hlho
llho
olho
aoho
hoho
loho
ooho
aalo
halo
lalo
oalo
ahlo
hhlo
lhlo
ohlo
allo
hllo
lllo
ollo
aolo
holo
lolo
oolo
aaoo
haoo
laoo
oaoo
ahoo
hhoo
lhoo
ohoo
aloo
hloo
lloo
oloo
aooo
hooo
looo
oooo


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

Okay, so funktioniert's dann in dem Code, aber ich muss mir das jetzt erst überlegen, ob ich das wirklich alles genau so brauche. Ich bastle nämlich an was größerem, wovon dieser Code nur ein Teil ist, den ich jetzt integrieren muss ...
 
AW: [C] Hilfe beim Programmieren und Verständnis-Fragen zu Code-Beispielen ...

2) Auch wenn ich das ebenso gemacht hätte, das hier wird rot unterwellt, weil desLen ein "constant value" sein muss:
Code:
void permute(const char* string, int strLen, int desLen) {
    int number[[COLOR=red]desLen];
    char out[[COLOR=red]desLen];
Muss ich jetzt wirklich ein dynamisches Array dafür erstellen, oder lässt sich das noch anders lösen? Bzw. mit einem Macro müsste es auch gehen, wäre aber ebenso wenig "ellegant".
Statische Arrays werden auf dem Stack angelegt, daher muss die Größe zur Compile-Zeit bekannt (also const) sein. Also entweder feste Länge oder ein dynamisches Array verwenden.
 
Zurück