Problem mit Structs in C

Hi,

Meine Freundin arbeitet gerade an folgender Aufgabe und kommt nicht weiter - ich kann ihr leider auch nicht helfen da ich keine Erfahrung mit C habe:

Link zur Aufgabenstellung (PDF)

Es handelt sich um Aufgabe 4.

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

    /* AUFGABE 1: structs */

struct messobjekt{
    int objektnr;
    char* bezeichnung;
};

typedef struct messobjekt Messobjekt;

struct messwert{
    Messobjekt* objekt; /* AUFGABE 3 */
    int messnr;
    double messwert;
};

typedef struct messwert Messwert;

int main(){
    /* AUFGABE 3 */

    auto Messwert *userMesswert;
    int size=3;
    int obnr=0;
    int counter=0;
    int i=0;
    int objnr = 0;
    char bezeichnung[50];
    int messnr = 0;
    float messwert = 0;

    userMesswert=(Messwert*)calloc(size,sizeof(Messwert));

    FILE *fp = NULL;
    fp = fopen("messungen.txt", "r");
    fseek(fp, 52, SEEK_CUR);

    printf("Objektnummer: ");
    scanf("%i", &obnr);
    fflush(stdin);

    while(!feof(fp)) {
        fscanf(fp,"%i,%[A-Za-z]s,%i,lf\n", &objnr, bezeichnung, &messnr, &messwert);
        if (objnr==obnr) {
            if(size==counter){
            size = size*2;
            userMesswert=(Messwert*)realloc(userMesswert,size);
            }

            userMesswert[i].objekt->objektnr = objnr; //PROBLEM TRITT HIER AUF
            userMesswert[i].objekt->bezeichnung = bezeichnung;
            userMesswert[i].messnr = messnr;
            userMesswert[i].messwert = messwert;
            counter++;
            i++;
        }
    }
    return 0;
}

Das Problem ist, dass die Wertzuweisung nicht klappt. Gut möglich das noch mehr nicht stimmt - aber das ist wo die erste Fehlermeldung auftritt.

Wäre echt nett wenn da mal jemand drüber schauen könnte
 
*ich sollte mal vor dem Antworten die Seite updaten*
Edit:
btw: calloc, realloc und (viel häufiger) fscanf können auch schiefgehen. Gut, dass 1 ... ∞ Std. Debugging einem die lästige Prüfung der Rückgabewerte erspart ;)
 
Vielen Dank, ich hab bei sowas echt 'nen Brett vorm Kopf.

Ich hab nun Speicher für das Objekt und für die Objekt.bezeichnung alloziert und die Wertzuweisung klappt! Leider habe ich jetzt tatsächlich einen Fehler beim fscanf!

in der Datei stehen die Werte wie folgt:

objektnummer,objektbezeichnung,messnummer,messwert
1,tower,1,17.334
1,tower,2,17.410
1,tower,3,16.986
1,tower,4,18.342
1,tower,5,15.999
1,tower,6,17.523
2,bridge,1,249.121
und so weiter..

Sowohl '1' als auch 'tower' konnte ich richtig zuweisen, die folgenden beiden Werte werden nicht korrekt ausgelesen (genauer gesagt habe ich bei beiden Werten 0 zugewiesen da ich beide Variablen vorher auf 0 gesetzt habe)

code ist momentan wie folgt:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

    /* AUFGABE 1: structs */

struct messobjekt{
    int objektnr;
    char* bezeichnung;
};

typedef struct messobjekt Messobjekt;

struct messwert{
    Messobjekt* objekt; /* AUFGABE 3 */
    int messnr;
    double messwert;
};

typedef struct messwert Messwert;

int main(){
    /* AUFGABE 3 */

    auto Messwert *userMesswert;
    int size=3;
    int obnr=0;
    int counter=0;
    int i=0;
    int objnr = 0;
    char bezeichnung[50];
    int messnr = 0;
    float messwert = 0;

    userMesswert=(Messwert*)calloc(size,sizeof(Messwert));

    FILE *fp = NULL;
    fp = fopen("messungen.txt", "r");
    fseek(fp, 52, SEEK_CUR);

    printf("Objektnummer: ");
    scanf("%i", &obnr);
    fflush(stdin);

    while(!feof(fp)) {
        fscanf(fp,"%i,%[A-Za-z]s,%i,lf\n", &objnr, bezeichnung, &messnr, &messwert);
        if (objnr==obnr) {
            if(size==counter){
            size = size*2;
            userMesswert=(Messwert*)realloc(userMesswert,size);
            }

            userMesswert[i].objekt = (Messobjekt *)malloc(sizeof(Messobjekt));
            userMesswert[i].objekt->bezeichnung=(char*)malloc(sizeof(char)*50);

            userMesswert[i].objekt->objektnr=objnr;
            strcpy(userMesswert[i].objekt->bezeichnung, bezeichnung);
            userMesswert[i].messnr=messnr;
            userMesswert[i].messwert=messwert;
            counter++;
            i++;
        }
    }
    return 0;
}
 
Code:
fscanf(fp,"%i,%[A-Za-z],%i,%f\n", &objnr, bezeichnung, &messnr, &messwert);

Ein String wird zwar mit %s eingelesen, ein Scanset jedoch ohne s, nur %[a-z]
 
fflush(stdin); ist UB in C.

Ich benutze immer ein #define für diese Zwecke :

Code:
#include <stdio.h>

#define CLR_BUFFER while( (c = getchar()) != EOF && c != '\n') ;

int main()
{
    int c;
    int i;

    scanf("%d", &i);
    CLR_BUFFER
    printf("%d", i);

    getchar();
    return 0;
}
Und den File Pointer auf NULL prüfen :)

Mfg
 
Hätte xrayn (wer sollte auch sonst schuld sein? :) ) gestern nicht so schnell gepostet, hätte ich den Code durch den Compiler gejagt - und da fällt eigentlich direkt auf:
Code:
gcc -Wall main.c
main.c: In function 'main':
main.c:48:9: warning: too many arguments for format [-Wformat-extra-args]
"-Wall" ist ein Kompilerflag, um die meisten Warnungen anzeigen zu lassen.
Einen ähnlichen Flag hat sowohl der MS-Compiler wie auch Clang.

Also, erstmal zu den Rückgabewerten:
man fscanf hat gesagt.:
These functions return the number of input items assigned.
This can be fewer than provided for, or even zero ... Zero indicates that, although there was input available, no conversions were assigned ... The value EOF is returned if an input failure occurs before any conversion such as an end of file occurs.
Erweiterung:
Code:
int fscanf_ret = 0;
...
fscanf_ret = fscanf(fp,"%i,%[A-Za-z]s,%i,lf\n", &objnr, bezeichnung, &messnr, &messwert);
        fprintf(stdout, "fscanf result: %i\n", fscanf_ret);
Ausgabe:
Code:
Objektnummer: 1
fscanf result: 2
fscanf result: 0
fscanf result: 0
fscanf result: 0
...
segfault
Die Fehlerquelle schlechthin ist nämlich, dass fscanf hier nur 2 Argumente "match"/"konsumiert" - die Position im Stream zeigt dann auf ",4.1234".

Danach wird immer wieder fröhlich in der Schleife versucht, weiterzulesen - allerdings kann dann gar nichts mehr gematcht werden => Streamposition bleibt gleich => EOF wird nie erreicht.
Dabei auch fleißig "gemalloct", da die objnr ja nicht verändert wurde und if ((objnr==obnr) greift => alloziert immer mehr Speicher.

"Glücklicherweise" (sonst hätten wir warten müssen, bis der ganze Heap durch malloc-Aufrufe aufgebraucht wird, was unter Umständen auch erstmal Swapping angeworfen hätte => träges System, 0-Spass usw. ;) ) gibt es ja den
realloc(oldbuf, 6)
Aufruf, wodurch natürlich nicht wirklich der Speicherblock erweitert wird => segfault (=Speicherfehler) beim Zuweisen der Werte => Programmabsturz :)

Aalso:
1) wenn fscanf aus irgendwelchen Gründen nicht die erwartete Anzahl an Objekten eingelesen hat => Fehler. Schleife unterbrechen oder sonstwie behandeln.
2) realloc überarbeiten, die aktuelle Größenangabe stimmt einfach nicht.

3) Eine gute Idee wäre strcopy durch strncpy zu ersetzen =>
Code:
strncpy(userMesswert[i].objekt->bezeichnung, bezeichnung, sizeof(bezeichnung));
und (oder zumindest) fscanf einschränken:
Code:
fscanf(fp,"%i,%6[A-Za-z],%i,%lf\n"
http://flash-gordon.me.uk/ansi.c.txt hat gesagt.:
After the %,
the following appear in sequence:

* An optional assignment-suppressing character * .

* An optional decimal integer that specifies the maximum field width.
Hat jetzt weniger mit den mystischen Bufferoverflows und Korinthenkackerei zu tun (obwohl man natürlich von Anfang an auf solche Sachen achten sollte), sondern mit "Bugs" und falsch formatiertem Input, der dann schnell zu "unerklärlichen" Programmabstürzen führt ;)

Nochmal zu den Compilerwarnungen:
Code:
warning: too many arguments for format
=> irgendwas passt mit den Argumenten nicht.
wir sehen uns die Zeile genauer an:
Code:
fscanf(fp,"%i,%[A-Za-z]s,%i,[color=red]lf[/color]\n", &objnr, bezeichnung, &messnr, &messwert);
=> %lf
ist allerdings erst das 4te Argument - ikkebins hat allerdings schon angesprochen, dass das s da überflüssig ist (und "lf" still und leise zu "%f" korrigiert).

Erstmal zu %lf korrigieren.
gcc -Wall sagt dazu:
Code:
main.c:48:9: warning: format '%lf' expects argument of type 'double *', but argu
ment 6 has type 'float *' [-Wformat]

Möchte man es ignorieren, sollte man vorher testweise ein
printf("%i %s %i %f\n",objnr, bezeichnung, messnr, messwert);
nach dem fscanf einfügen und staunen und dann doch zu %f korrigieren ;)
 
Zuletzt bearbeitet:
Zurück
Oben