aufgabe



  • hallo ich lerne grad c und muss eine aufgabe machen, aber ich scheitere schon an einer minimalisierten form.

    Und zwar möchte ich einen Namen und eine Matrikelnummer einlesen Name darf maximal 20 zeichen haben matrikelnummer maximal 7-stellig sein.
    Hier mein bisheriger ansatz:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int nummer;
        char* name;
        printf("WARNUNG: Namen duerfen maximal aus 20 Zeichen bestehen,\nMatrikelnummern sind hoechstens 7-stellig. \nUeberfluessige Zeichen werden ignoriert.\n\n");
        printf("Bitte geben Sie einen Namen gefolgt von der zugehoerigen Matrikelnummer ein:\n");
        scanf("%20s %4d ", name, &nummer);
        printf("Nummer ist: %d\n Name ist: %s", nummer,name );
    
        return 0;
    }
    

    kann mir einer alle fehler die ich gemacht habe zeigen und erklären und sogar evt verbessern?

    ein fehler könnte ich mir vorstellen ist dass das char-array nie eine größe bekommt oder?



  • jopp, dein char* ist schonmal ein Fehler.

    scanf versucht an eine ungültige Adresse zu schreiben, was wiederum in einem Programmabsturz endet (im Normalfall)

    da die Zeichenkette sowieso maximal 20 Zeichen lang sein soll,
    setze die Größe des Array einfach auf 21 fest:

    char name[21];
    

    21, weil am Ende immer noch ein '\0' angehängt wird, damit die C Runtime beim Ausgeben (print, ...) weiß, wo die Zeichenkette zu Ende ist.

    aber dadrum brauchst du dich nicht kümmern, da scanf die '\0' selbst anhängt.



  • deine vorstellung geht fast in die richtige richtung, allerdings hast du kein array, sondern einen zeiger auf char. dieser zeiger zeigt auf eine unbekannte adresse.



  • ok das habe ich ausgebessert, aber jetzt habe ich noch ein problem:

    es muss in der form xxxx yyyyyyy einlesbar sein

    xxxx = name yyyyyy= matrikelnummer

    bis jetzt scheint er zwanghaft 20 zeichen einlesen zu wollen wegen meinem "%20s"
    ich möchte aber dass er MAXIMAL 20 zeichen einliest und wenn ein leerzeichen vorkommt dann die matrikelnummer einliest? ist das einfach realisierbar oder ost es besser wenn ich erstmal den namen komplett einlese und dann mittels strlen überprüfe was los ist??

    und ja wenn ich dann dieses char x[21] array habe , was passiert wenn der benutzer mher als 20 zeichen eingibt? buffer-overflow? oder wird das ignoriert?



  • scanf achtet nicht auf array-größen, deshalb ja, da gibt es einen hübschen buffer overflow 😉

    dummerweise fällt mir aber auch gerade keine ANSI C Funktion ein, welche dieses Manko behebt, da ich eher bei C++ zu Hause bin 😉



  • metapher schrieb:

    bis jetzt scheint er zwanghaft 20 zeichen einlesen zu wollen wegen meinem "%20s"
    ich möchte aber dass er MAXIMAL 20 zeichen einliest und wenn ein leerzeichen vorkommt dann die matrikelnummer einliest?

    Nö, maximal 20. Wie kommst du darauf?

    metapher schrieb:

    und ja wenn ich dann dieses char x[21] array habe , was passiert wenn der benutzer mher als 20 zeichen eingibt? buffer-overflow? oder wird das ignoriert?

    Die übrigen Zeichen verbleiben im Puffer und scanf versucht sie als int zu interpretieren und es kommt Schrott raus.

    Sei nicht so knauserig mit der Puffergröße, dann bleibt im Puffer nix über:

    const int num_max = 9999999;
    enum {namelen_max = 20};
    
    int eret(char* s)
    {
    	if(s)
    		fprintf(stderr, "%s\n", s);
    	return 1;
    }
    
    int main() 
    { 
    	int num = 0;
    	char name[BUFSIZ+1] ={0}; 
    
    	if (2 != scanf( "%s %d", name, &num))
    		return eret("Invalid input!");
    	if (strlen(name)>namelen_max || num>num_max)
    		return eret("Input out of bounds!");
    	printf("%s %d\n", name, num);
    
    	return 0;
    }
    

    In der Praxis hat man häufig eine separate Einlesefunktion, der Stackspeicher fürs Array wird beim Verlassen der Einlesefunktion wieder frei:

    const int num_max = 9999999;
    enum {namelen_max = 20};
    
    int eret(char* s)
    {
    	if(s)
    		fprintf(stderr, "%s\n", s);
    	return 1;
    }
    
    int input (int* nr, char* name)
    {
    	int num = 0;
    	char buf[BUFSIZ+1] = {0}; 
    	if (2 != scanf( "%s %d", buf, &num))
    		return eret("Invalid input!");
    	if (strlen(buf)>namelen_max || num>num_max)
    		return eret("Input out of bounds!");
    	*nr = num;
    	strcpy(name, buf);
    	return 0;
    }
    
    int main() 
    { 
    	char name[namelen_max+1] = {0};
    	int matrikel_nr = 0;
    
    	if (input(&matrikel_nr, name))
    		return 1;
    	else
    		printf("%s %d\n", name, matrikel_nr);
    	return 0;
    }
    


  • danke brother...

    ich hab das ganze jetzt unter linux neu geschrieben und ... seltsam die fehler die ich unter windows hatte kamen nicht... trotz gleichem quellcode gleicher ide und gleichem compiler ... wirklich sehr seltsam 🙂

    aber trotzdem thx , ich werd in nächster zeit eh öfter hier vorbei kommen müssen denk ich 🙂

    keep on helping



  • ja jetzt habe ich ein problem:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int i;                      
        char* nm[10];               
        //char buffer[10000];        
        int matr[10];           
        printf("Warnung:\nNamen haben maximal 20 Zeichen\nMatrikelnummern sind maximal 7-stellig\nUeberfluessige Zeichen werden ignoriert!\n");
    
        for(i=0;i<10;i++)
        {
            nm[i] = malloc(21 * sizeof(char));
        }
    
        for(i=0; i<3; i++)
        {
            printf("\nBitte geben Sie den Namen gefolgt von der zugehoerigen Matrikelnummer ein:\n");
            scanf("%20s %7d", nm[i], &matr[i]);
            printf("\nKOntrolle: %s", nm[i]);
        }
        for(i=0;i<3;i++)
        {
            printf("\n %d", matr[i]);
        }
        return 0;
    }
    

    wenn ich hier absichtlich einen viel zu langen namen eingebe dann leist er das anscheinend auch für die übrigen anfragen ein, liegt das nur am "%20s" oder muss ich da was grundlegendes #ändern?



  • mal wieder ich schrieb:

    ja jetzt habe ich ein problem:
    ...
    [zensiert]
    ...
    wenn ich hier absichtlich einen viel zu langen namen eingebe dann leist er das anscheinend auch für die übrigen anfragen ein, liegt das nur am "%20s" oder muss ich da was grundlegendes #ändern?

    guckt dir lieber nochmal an, wie man ein char-zeilenarray macht!



  • was meinst du damit? ist da was schief gelaufen?

    ist hier etwas falsch?

    nm[i] = malloc(21 * sizeof(char));

    ich kenne mich in c noch kaum aus leider ...
    aber wenn ich das 20 im einlesebefehl weglasse scheint es zu funktionieren...



  • so ich denke ich habe die aufgabe gelöst, aber da ich mich nicht gut auskenne würde ich es gerne mal kontrolliert haben:

    Aufgabenstellung:

    1. Sie können in einem ersten Schritt 10 Paare (Nachname, Matrikelnummer) in zwei Feldern vom Typ char*[10] und int[10] eintragen. An der Stelle i des jeweiligen Feldes stehen die zueinander gehörenden Daten. Dabei sind die Namen maximal 20 Zeichen lang und die Matrikelnummer ist höchstens 7-stellig.

    2. Sie können mittels der Matrikelnummer suchen, die Ausgabe ist dann der Name.

    3. Sie können nach dem Namen suchen, die Ausgabe ist dann die Matrikelnummer.

    Das Programm bekommt als Eingabe zuerst 10 Paare als Beispieldaten und dann eine Matrikelnummer nach der in den 10 Daten gesucht wird und als Letztes ein Name nach dessen Matrikelnummer gesucht wird. Beachten Sie, dass Namen mehrfach vorkommen können und es auch passieren kann, dass die gesuchten Namen bzw Matrikelnummer nicht vorhanden ist.

    hier meine lösung:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        int i;
        int ok;                   // Laufvariable
        int modus;
        int dummy;
        char* nm[10];               // MUSS ich tatsächlich einen pointer verwenden?
        char buffer[10000];         // 10000 zeichen werden wohl reichen oder?
        int matr[10];               //  array für die matrikelnummern
        printf("Warnung:\nNamen haben maximal 20 Zeichen\nMatrikelnummern sind maximal 7-stellig\n");
    
        for(i=0; i<10; i++)
        {
            do
            {
                printf("\nBitte geben Sie den Namen gefolgt von der zugehoerigen Matrikelnummer ein:\n");
                scanf("%s %d", buffer, &matr[i]);
    
                ok = 1;
                if( strlen(buffer) > 20 || matr[i] > 9999999 || matr[i] < 0)
                {
                    ok = 0;
                }
    
            }while(ok == 0);
    
            nm[i] = malloc( (strlen(buffer) + 1) * sizeof(char));
            strcpy(nm[i], buffer);
        }
        /*
        for(i=0;i<3;i++)
        {
            printf("\n%s %d",nm[i], matr[i]);
        }
        */
        ok = 1;
        int found;
        found = 0;
    
        do
        {
            printf("\nWillkommen, was moechten Sie suchen?\n(1) fuer Namen [Ausgabe zugehoerige Matrikelnummer]\n");
            printf("(2) fuer Matrikelnummern [Ausgabe zugehoeriger Name]\n");
            scanf("%d", &modus);
            switch(modus)
            {
                case 1:
                    ok = 1;
                    printf("Bitte geben Sie den Namen ein: ");
                    scanf("%s", buffer);
                    for(i = 0; i<10; i++)
                    {
                        if(strcmp(buffer, nm[i]) == 0)
                        {
                            printf("Name gefunden, zugehoerige Matrikelnummer: %d\n", matr[i]);
                            found = 1;
                        }
                    }
                    if(found == 0)
                    {
                        printf("Name nicht vorhanden!\n");
                    }
                    break;
                case 2:
                    ok = 1;
                    printf("Bitte geben Sie die Matrikelnummer ein: ");
                    scanf("%d", &dummy);
                    for(i = 0; i<10; i++)
                    {
                        if(dummy == matr[i])
                        {
                            printf("Nummer gefunden, zugehoeriger Name: %s", nm[i]);
                            found = 1;
                        }
                    }
                    if(found == 0)
                    {
                        printf("Nummer nicht vorhanden!\n");
                    }
                    break;
                default:
                    ok = 0;
                    break;
            }
        }while(ok == 0);
        for(i=0; i<10; i++)
        {
            free(nm[i]);
        }
        return 0;
    }
    

    bitte auf fehler aufmerksam machen 🙂



  • Verschiedenes (weniger Fehler als Anregung).

    1) Die Matrikelnr. und der Name bilden eine logische Einheit (beides gehoert zusammen). Es ist also naheliegend beides in einer Datenstruktur zu verarbeiten:

    Statt also

    char* nm[10];               // MUSS ich tatsächlich einen pointer verwenden?
    int matr[10];
    

    eher soetwas:

    typedef struct person
    {
        int   matr;
        char *name;
    }
    
    int main ()
    {
       person   array_persons [10]
    /*...*/
    }
    

    Spaetere Aenderungen mit zusaetzlichen Daten (Vor- und Nachname, Fakultaet, Semsteranzahl, Pruefungen, etc.) sind dann sehr viel einfacher zu implementieren.

    2) scanf hat einen Rueckgabewert - dieser sollte im Zweifelsfalle abgefragt werden:

    Also statt:

    scanf("%d", &dummy);
    

    eher etwas wie:

    if (scanf("%d", &dummy) != 1)
        printf ("Idiot! Eine Zahl will ich hier!")
    

    3) Schleifen etwas uebersichtlicher; statt

    for(i = 0; i<10; i++)
        {
            if(dummy == matr[i])
            {
                printf("Nummer gefunden, zugehoeriger Name: %s", nm[i]);
                found = 1;
            }
        }
        if(found == 0)
        {
            printf("Nummer nicht vorhanden!\n");
        }
    

    vielleicht eher:

    i = 0
    while ((i < 10) && (dummy != matr[i]))
        i++;
    
    if (dummy == matr[i])
        printf("Nummer gefunden, zugehoeriger Name: %s", nm[i]);
    else
        printf("Nummer nicht vorhanden!\n");
    

    4) "Magic Numbers":

    Du verwendest die Zahle "10" staendig, wenn Du mal eine andere Zahl an Studenten hast, musst Du ueberall aendern, einfacher waere es dann eine Zeile zu haben:

    #define MAX_NUMBER_STUDENTS     10
    

    Oder gleich mit einer dynamischen Liste arbeiten (was ich tun wuerde).



  • metapher schrieb:

    was meinst du damit? ist da was schief gelaufen?

    ist hier etwas falsch?

    nm[i] = malloc(21 * sizeof(char));

    ich kenne mich in c noch kaum aus leider ...

    ja, es ist falsch. darum noch einmal: lies nach, wie man zeilen in einem array speichert.



  • kannst du mir bitte erklären was falsch ist??

    also ich habe im grunde um mal in java zu denken char[10][]

    und dnan mach ich für alle meine chars
    char[i] = new char[21]

    so dass ich im endeffekt char[10][21] habe , was meiner meinung nach

    10 strings der länge 21 sind oder?

    wäre nett wenn du mir eine lösung gibst damit ich das mal vergleichen kann.
    ich sehe leider keinen fehler ...



  • advis0r schrieb:

    ja, es ist falsch. darum noch einmal: lies nach, wie man zeilen in einem array speichert.

    Was soll daran falsch sein? Das ist ok.

    mal wieder ich schrieb:

    wenn ich hier absichtlich einen viel zu langen namen eingebe dann leist er das anscheinend auch für die übrigen anfragen ein, liegt das nur am "%20s" oder muss ich da was grundlegendes #ändern?

    Entweder das Array groß genug machen (BUFSIZ+1), oder nach jeder Eingabe den Eingabepuffer leeren.


Log in to reply