In C eine Struktur schreiben



  • Hallo Liebes C Forum,

    ich bin 23 Jahre alt, studiere Elektrotechnik und habe momentan das Fach Informatik 2.
    Gerade jetzt bei den Klausuraufgaben habe ich eine Frage bzw. eher ein Problem das ich nicht weiter komme und hoffe jemand von euch kann mir auf idiotensichereweise erklären was zu tun ist.

    Um folgende Aufgabenstellung dreht es sich:

    Für doe Struktur Student sei folgende Deklaration gegeben:

    struct Student {
    int matnr;
    char* name;
    };
    typedef struct Student StudiTyp

    a) Schreiben Sie eine Funktion viod student_eingeben(), mit dem Sie die Matrikelnummer und den Nmane eines Studenten mit der Tastatur eingeben können.
    b) Schreiben Sie die Struktur in eine Klasse um und ergänzen Sie diese mit der Funktion student_eingeben():

    Meine bisherige Lösung ist:

    #include <stdio.h>
    #include <conio.h>
    
    struct Student		//Deklaration der Struktur erfolgt global
    {
    	int matnr;
    	char* name;
    };
    
    typedef struct Student StudiTyp;		//typedef vergibt den neuen Namen StudiTyp, dadurch muss struct nicht mehr angegeben werden
    
    void student_eingeben(int matnr,char* name);
    
    int main()
    {
    	void student_eingeben(matnr,name);
    
    	printf("Kontrolle der Eingabe: \n");
    	printf("Matrikelnummer: %i\n", &StudiTyp.matnr);
    	printf("Name: %s", &StudiTyp.name);
    
    	return 0;
    }
    
    void student_eingeben(int matnr,char* name)
    {
    	do
    	{
    		printf("Bitte geben Sie die Matrikelnummer ein: ");
    		scanf("%i", &StudiTyp.matnr);
    		printf("Bitte geben Sie den Namen ein:\n");
    		scanf("%s", &StudiTyp.name);
    		printf("\nFuer einen weiteren Eintrag bitte -j- druecken!\n");
    
    	}while (_getche() == 'j');
    }
    

    Jedesmal wenn ich das Programm in Visual Studio ausführen möchte bricht es nach der Eingabe der Matnr ab und ich weiß nicht wieso oder wo mein Fehler liegt?

    Könnte mir das einer einfach und verständlich erklären Warum es zu dem Fehler kommt und was ich vergessen habe, denn mit meinem Erlenkötter sowie dem Skript des Profs und den zusätzlichen Nachschlagewerken ist nichts aufzufinden wo mein Fehler liegt.

    Gruß

    Ricky



  • Visual Studio zeigt dir doch deine Fehler an. Hast du die schon mal angeguckt und versucht zu beheben?

    Auch: Wieso wird diese Aufgabe hier so oft gepostet?



  • Wie oft gepostet?
    Ich hab die Aufgabe hier nicht gefunden....könnte aber daran liegen das euer Forum ganz oben bei Google auftaucht wenn man c und c++ programmierung sucht.

    Diese Fehler die mir das Visual Studio anzeigt verstehe ich nicht.

    Bsp.:
    Links von ".matnr" muss sich eine Klasse/Struktur/Union befinden.

    matnr befindet sich doch in meiner Struktur und trotzdem kommt der Fehler.

    Gruß



  • Du hast nur einen Typ (struct Student bzw. StudiTyp) definiert, aber keine Variable. Du brauchst doch Speicher für die Daten!

    // Es ist hier angebrachter die Adresse anstelle der einzelnen Attribute zu übergeben.
    void student_eingeben(StudiTyp *student);
    
    int main(void)
    {
        StudiTyp student;
        // ...
        // Den Rückgabedatentyp (void) musst du bei einem Aufruf nicht angeben.
        student_eingeben(&student);
        // ...
        printf("Matrikelnummer: %i\n", student.matnr);  // du willst den Wert, nicht die Adr.
        // ...
    }
    

    Zudem muss in student_eingeben , wenn es nach der von dir geposteten Aufgabenstellung geht, nur einer eingegeben werden können. Deine Aufforderung zum Drücken von J ergäbe viel mehr Sinn, wenn du z.B. fragst, ob die Eingabe richtig ist und wenn das der Fall ist, die Schleife beendest.



  • meinst du so:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Student		//Deklaration der Struktur erfolgt global
    {
    	int matnr;
    	char* name;
    };
    typedef struct Student StudiTyp,eingabe;		//typedef vergibt den neuen Namen StudiTyp, dadurch muss struct nicht mehr angegeben werden
    
    void student_eingeben(StudiTyp *eingabe);
    
    int main()		//Hauptprogramm
    {
    	StudiTyp eingabe;
    	student_eingeben(&eingabe);	//Einsatz der Funktion als Baustein(Rückgabetyp wie void ist hir überflüssig)
    	printf("Kontrolle der Eingabe: \n");
    	printf("Matrikelnummer: %i\n", eingabe.matnr);
    	printf("Name: %s", eingabe.name);
    	return 0;
    }
    
    void student_eingeben(StudiTyp *eingabe)
    {
    	do
    	{
    		printf("Bitte geben Sie die Matrikelnummer ein: ");
    		scanf("%i", eingabe.matnr);
    		printf("\nBitte geben Sie den Namen ein: ");
    		scanf("%s", eingabe.name);
    
    		printf("\nFuer einen weiteren Eintrag bitte -j- druecken!\n");
    	}while (getchar() =='j');
    	return;
    }
    


  • so hab nun noch weiter recherchiert und habe mein Code wie folgt geändert, jedoch
    bricht das Programm nach der Eingabe der Matrikelnummer immernoch ab mir wird gesagt das die exe nicht funktioniert. ein fehler wird bei Visual Studio nicht ausgegeben.

    #include <stdio.h>
    
    struct Student      //Deklaration der Struktur erfolgt global
    {
        int matnr;
        char* name;
    };
    typedef struct Student StudiTyp;        //typedef vergibt den neuen Namen StudiTyp, dadurch muss struct nicht mehr angegeben werden
    
    void student_eingeben(StudiTyp *);		//Deklaration des Funktionsprototyp mit Pointer(Zeiger) auf die Struktur
    
    StudiTyp ausgabe;		//Variable "ausgabe" wird vom Typ Struktur(StudiTyp) definiert
    
     int main(void)      //Hauptprogramm
    {
        student_eingeben(&ausgabe); //Einsatz der Funktion als Baustein(Rückgabetyp wie void ist hier überflüssig)
    
    	printf("Kontrolle der Eingabe: \n");
        printf("Matrikelnummer: %i\n", ausgabe.matnr);
        printf("Name: %s", ausgabe.name);
    
    	return 0;
    }
    
    void student_eingeben(StudiTyp * eingabe)	//Von der Funktion wird die Adresse eingabe entgegengenommen, sie dient als Pointer auf die Struktur(StudiTyp)
    {
            printf("Bitte geben Sie die Matrikelnummer ein: ");
            scanf("%i", (*eingabe).matnr);		//Die Klammern sind wichtig, weil der Punktoperator eine höhere Priorität hat als der Sternoperator
            printf("\nBitte geben Sie den Namen ein: ");
            scanf("%s", (*eingabe).name);		//Man könnte auch "eingabe->name" statt "(*eingabe)name)" schreiben
    
        return;
    }
    

    Ich brauch dringend Hilfe 😃



  • Du benötigst noch Speicher für den Namen. Du hast bisher nur einen Zeiger mit einem unbekannten Wert ( char *name ). Speicher kannst du entweder statisch ( char name[255]; ) oder dynamisch reservieren ( ausgabe.name = malloc(255); und mit free freigeben).
    Und dann scanf mit dem Formatstring "%254[^\n]" aufrufen, so dass du nicht mehr einliest als du Speicher reserviert hast (buffer overflow). Warum 254 statt 255? Wegen NUL.
    Du kannst außerdem auch fgets zum Einlesen von Strings verwenden:

    fgets(eingabe->name, 255, stdin);
    

    Und: scanf arbeitet mit Zeigern, also schreib den Bretzeloperator wieder hin!

    scanf("%i", &(*eingabe).matnr);
    


  • Danke für den Tipp mit dem Adressoperator, gerade bei der matnr war der wichtig da mir immer ne andere nummer als ich eingegeben habe rauskam, jetzt passt es.
    Wenn ich den Adresoperator beim name einfügen, zeigt er mir aber ein fehler.

    Hab das Programm/Code folgend geändert:

    #include <stdio.h>
    #include <stdlib.h>	//Für Funktion malloc
    #include <conio.h>
    
    struct Student      //Deklaration der Struktur erfolgt global
    {
        int matnr;
        char* name;
    };
    typedef struct Student StudiTyp;        //typedef vergibt den neuen Namen StudiTyp, dadurch muss struct nicht mehr angegeben werden
    
    void student_eingeben(StudiTyp *);		//Deklaration des Funktionsprototyp mit Pointer(Zeiger) auf die Struktur
    
    StudiTyp ausgabe;		//Variable "ausgabe" wird vom Typ Struktur(StudiTyp) definiert
    
     int main(void)      //Hauptprogramm
    {
    	do
    	{
    		student_eingeben(&ausgabe); //Einsatz der Funktion als Baustein(Rückgabetyp wie void ist hier überflüssig)
    		printf("\nFuer die Eingabe eines weiteren Studenten druecken Sie 'j': ");
    	}while (getche() == 'j');
    
    	printf("\nKontrolle der Eingabe: \n");
        printf("\nMatrikelnummer: %i\n", ausgabe.matnr);
        printf("Name: \t\t%s\n", ausgabe.name);
     }
    
    void student_eingeben(StudiTyp * eingabe)	//Von der Funktion wird die Adresse eingabe entgegengenommen, sie dient als Pointer auf die Struktur(StudiTyp)
    {
    		(*eingabe).matnr=(int)malloc(6*sizeof(int));		//Reservierung des Speicher für die matnr
    		(*eingabe).name=(char*)malloc(20*sizeof(char));		//Reservierung des Speicher für den namen    
    		printf("\nBitte geben Sie die Matrikelnummer ein: ");
            scanf("%i", &(*eingabe).matnr);						//Der &-Operator muss hier verwendet werden damit die Nummer und nicht die Adresse ausgegeben wird
    		printf("\nBitte geben Sie den Namen ein: ");
            scanf("%s", (*eingabe).name);		//Man könnte auch "eingabe->name" statt "(*eingabe)name)" schreiben
    											//Die Klammern sind wichtig, weil der Punktoperator eine höhere Priorität hat als der Sternoperator
    		return;		//Wertrückgabe
    }
    

    Oder steckt noch ein Fehler drin? Das mit dem scanf "254[^\n]" versteh ich nicht...wo und wofür sollte ich das ändern?



  • Für matnr musst du keinen Speicher reservieren. Das geschieht durch StudiTyp ausgabe; bereits (reserviert ein int und char*). Ansonsten sehe ich keinen Fehler, nur einige Punkte, die ich ändern würde (sizeof(char) ist IMMER 1 und in void-Funktionen brauchst du kein "return").

    Und:

    scanf("%19[^\n]", (*eingabe).name);
    

    Wofür du das benötigst? Gib doch bei dir, wenn du es zum Laufen gebracht hast, mal >= 20 Zeichen ein.



  • Rickytop schrieb:

    Oder steckt noch ein Fehler drin?

    Da sind noch ein ganz schön fetter Klopper drin, ja.

    1. Zu jedem erfolgreichen malloc/calloc gehört ein free
    2. Jeder Aufruf von student_eingeben produziert ein Memory-Leak
    3. matnr ist kein Zeiger und hat schon Speicher, malloc ist nicht nötig.
    Wäre es ein Zeiger würde

    eingabe->matnr = malloc(sizeof(int));
    

    völlig ausreichen, oder wozu die sechsfache Speichermenge?
    4. Die Anzahl der Zeichen für einen Namen hartgecodet ist unschön,
    lieber eine Variable oder ein #define verwenden.

    EinGast schrieb:

    scanf("%19[^\n]", (*eingabe).name);
    

    Das [^\n] hat 0 Effekt.



  • ^größer gleich 20 funktioniert trotzdem...
    mein problem ist gerade eher, angenommen ich möchte einen zweiten studenten eingeben und das in einer tabelle ausgeben wie mache ich das, dass das programm den ersten studenten in ein feld und den zweiten studenten in ein feld schreibt bzuw und noch weitere. Ich weiß das ich zb i++ also hochzählen lassen muss aber wie bzw wo gebe ich das feld [i] ein bei scanf?



  • Rickytop schrieb:

    ^größer gleich 20 funktioniert trotzdem...

    nur weil es nicht sofort kracht(programmabsturz), heißt es noch lange nicht, dass alles okay ist.
    bei >= 20 zeichen ist dein stack schon mal kaputt.

    Rickytop schrieb:

    mein problem ist gerade eher, angenommen ich möchte einen zweiten studenten eingeben und das in einer tabelle ausgeben wie mache ich das, dass das programm den ersten studenten in ein feld und den zweiten studenten in ein feld schreibt

    das einfachste ist ein array von strukturen.



  • @ cler:
    danke für den hinweis,leider darf ich aber an der struktur nichts verändern und ich weiß nicht wie ich das sonst einbauen sollte. wenn ich mir arrays bilden dürfte wie ich will, wäre es einfacher. aber ich darf ja nach der aufgaben stellung nicht verändern es muss also

    struct Student      //Deklaration der Struktur erfolgt global
    {
        int matnr;
        char* name;
    };
    typedef struct Student StudiTyp;
    

    bleiben!

    es kann eig nicht schwer und auch nicht viel sein, sonst wre das keine klausuraufgabe, dann hätten wir keine zeit für andere aufgaben.
    ich versteh es nur nicht was ich genau wo ändern muss...ich bin ein noob in dem bereich also nehmt mich bitte an die hand und helft mir 😃

    mittlerweile ist mein code so:

    #include <stdio.h>
    #include <stdlib.h>	//Für Funktion malloc
    #include <conio.h>
    
    struct Student      //Deklaration der Struktur erfolgt global
    {
        int matnr;
        char* name;
    };
    typedef struct Student StudiTyp;        //typedef vergibt den neuen Namen StudiTyp, dadurch muss struct nicht mehr angegeben werden
    
    void student_eingeben(StudiTyp *[20]);		//Deklaration des Funktionsprototyp mit Pointer(Zeiger) auf die Struktur
    
    StudiTyp ausgabe;		//Variable "ausgabe" wird vom Typ Struktur(StudiTyp) definiert
    
    int i=0,anfang;
    
     int main(void)      //Hauptprogramm
    {
    
    	do
    	{
    		student_eingeben(&ausgabe); //Einsatz der Funktion als Baustein(Rückgabetyp wie void ist hier überflüssig)
    
    		printf("\nFuer die Eingabe eines weiteren Studenten druecken Sie 'j': ");
    	}while (getche() == 'j');
    
    	printf("\nKontrolle der Eingabe: \n");
        printf("\nMatrikelnummer: %i\n", ausgabe.matnr);
        printf("Name: \t\t%s\n", ausgabe.name);
    
    	printf("\n|Lfd.|Name---------------|Matrikelnummer-----|\n");		//Ausgabe des Tabellenkopfes (%-19s heist nur linksbündig)
    	printf("|----|-------------------|-------------------|\n");
    	for (anfang=1; i>=anfang; anfang++)		//for schleife zur Erstellung der Liste anhand der eingegebenen einträge
    		{
    			printf("|%4i|%-19s|%-19i|",anfang, ausgabe.name, ausgabe.matnr);
    			printf("\n|----|-------------------|-------------------|\n");
    		}
    	free(ausgabe.name);		//Speicherbereich wieder freigeben
     }
    
    void student_eingeben(StudiTyp * eingabe[20])	//Von der Funktion wird die Adresse eingabe entgegengenommen, sie dient als Pointer auf die Struktur(StudiTyp)
    {
    		(*eingabe)[i].name=(char*)malloc(20*sizeof(char));		//Reservierung des Speicher für den Namen, bei Matnr wird dies nicht benötig da es kein Zeiger ist und somit Speicher besitzt
    		printf("\nBitte geben Sie die Matrikelnummer ein: ");
            scanf("%i", &(*eingabe)[i].matnr);						//Der &-Operator muss hier verwendet werden damit die Nummer und nicht die Adresse ausgegeben wird
    		printf("\nBitte geben Sie den Namen ein: ");
            scanf("%s", (*eingabe)[i].name);		//Man könnte auch "eingabe->name" statt "(*eingabe)name)" schreiben
    											//Die Klammern sind wichtig, weil der Punktoperator eine höhere Priorität hat als der Sternoperator
    		i++;
    }
    

    An dieser stelle zeigt der mir ein fehler bei dem bretzeloperator und ich weiß nicht wieso und wie ich das verlinken muss:

    student_eingeben(&ausgabe);
    


  • Rickytop schrieb:

    @ cler:
    danke für den hinweis,leider darf ich aber an der struktur nichts verändern und ich weiß nicht wie ich das sonst einbauen sollte. wenn ich mir arrays bilden dürfte wie ich will, wäre es einfacher. aber ich darf ja nach der aufgaben stellung nicht verändern es muss also

    struct Student      //Deklaration der Struktur erfolgt global
    {
        int matnr;
        char* name;
    };
    typedef struct Student StudiTyp;
    

    bleiben!

    da stimme ich dir voll und ganz zu, dass es einfacher wäre, ich meine aber mit einem array von strukturen so etwas:

    StudiTyp studis[40];
    


  • achso meinst du das...mom ich bastel mal 😃



  • der zeigt mir immernoch bei student_eingeben(&ausgabe) in der main ein fehler beim &-Operator. wie behebe ich das?



  • lies doch mal, was der fehler bedeutet ... 😉
    du müsstest in deiner do while schleife auch nen index oder sowas mitlaufen lassen.
    ich muss mich jetzt verpieseln, hab dir mal nen ansatz getippt, kriegste schon hin.
    wenn er bei malloc meckert, kompilierst du im c++ modus und musst casten oder auf c umstellen.
    gutes gelingen, bye.

    #define NAMELEN_MAX 63
    #define STUDENTEN_MAX 10000
    
    typedef struct tagStudent
    {
        int matnr;
        char* name;
    } Student;
    
    void student_anzeige ( Student* p, size_t n )
    {
    	size_t i;
    	for ( i = 0; i < n; i++ )
    		printf ("%d %s\n", p[i].matnr, p[i].name);
    }
    
    size_t student_eingabe ( Student* p, size_t n )
    {
    	size_t i = 0;
    	char eingabe[80*25];
    	char name[NAMELEN_MAX+1];
    	int matnr;
    
    	puts("Martielnummer und Namen eingeben, beenden mit Entertaste");
    	while ( i < n )
    	{
    		fgets(eingabe, sizeof(eingabe), stdin);
    		if ( eingabe[0] == '\n' )
    		{
    			break; // beendet durch benutzer
    		}
    		else if (2 != sscanf ( eingabe, "%d %63s", &matnr, name))
    		{
    			puts("Eingabefehler!");
    			continue;
    		}
    		else
    		{
    
    			p[i].name = malloc (strlen(name + 1));
    			if ( NULL != p[i].name )
    			{
    				p[i].matnr = matnr;
    				// ... strcpy benutzen, kriegste schon hin ...
    				i++;
    			}
    			else
    			{
    				// fehlerbehandlung ...
    				break;
    			}
    		}
    	}
    	return i; // anzahl eingegebener studenten
    }
    int main(void)
    {
        Student studenten[STUDENTEN_MAX];
    	size_t n = student_eingabe(studenten, STUDENTEN_MAX);
    	student_anzeige(studenten, n);
        return 0;
    }
    


  • danke dir aber glaube damit kann ich noch weniger anfangen 😃
    Denn leider habe ich vergessen zu erwähnen, dass wir kein string.h und die dazugehörigen funktionen wie strlen,strcpy benutzen dürfen. das macht es ja für mich ungemein schwer...erst darf ich keine arrays bilden wie ich mag und dann die einfachen string funktionen auch nicht nutzen...

    Mein problem bleibt soviel stehen, was meint visual studio damit wenn es an der &ausgabe sagt: Konvertierung des Parameters 1 von 'StudiTyp (*)[20]' in 'StudiTyp *[]' nicht möglich

    Ich verstehe es ja leider nicht und kann mir deshalb nicht helfen...



  • schreib dir doch deine eigene strlen und strcpy funktion, das sind wenige zeilen.
    dein compiler will dir mitteilen, dass die zeiger nicht kompatibel sind.



  • ja das könnte ich tun aber ich möchte wissen wieso der fehler dort ist bzw wie ich diesen fehler an dem Bretzeloperator behebe, sonst läuft mein programm und wirft mir ein student auch in tabellen form durch die printf anweisung aus...
    Kann mir nicht einer an von euch einfach nur sagen was ich an dieser stelle ändern muss damit die arrays von ausgabe richtig abgespeichert werden bzw wie ich das hinbekomme das die zeiger kompatiel werden??


Anmelden zum Antworten