"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

"C" HELP - Array of Structs

charmin 15.05.2016 - 17:58 2321 10
Posts

charmin

Super Moderator
Muper Soderator
Avatar
Registered: Dec 2002
Location: aut_sbg
Posts: 13991
Servus oc.at,

Komme bei einer Hausübung einfach nicht weiter.

Soll eine Datei binär eine .dat datei einlesen, in ein Struct speichern und dieses Struct, dann in eine Structtabelle, welche dynamisch erweitert wird.

Danach soll das ganze in eine XML datei geschrieben werden.

Mein Problem ist, dass ich zwar das Strukt einlesen kann und in das Strukt Array dann speichern kann, allerdings ist dann in dem Strukt Array in allen Positionen " [ ] " dasselbe drinnen


Code: C
    #pragma pack(push)
    #pragma pack(1)

	typedef struct
	{
		char Interpret[P];
		char Album[P];
		char Title[P];
		int Tracknr;
         }structRec;

    #pragma pack(pop)


    structRec *Record;
    structRec **RecordTable;

    Record = calloc(size, sizeof(structRec));
    RecordTable = calloc(size, sizeof(structRec));

        // Input DAT
        if (!strcmp(ivalue,"dat"))
        {
            // Filestream Inputfile öffnen
            fpIN=fopen("mediaDB.dat", "rb");

            printf("\nInput: mediaDB.dat\n");

        }


        // Output XML
        if (!strcmp(ovalue,"xml"))
        {
            // Filestream Outputfile öffnen
            fpOUT=fopen("mediaDBout.xml", "w");

            printf("\nOutput: mediaDBout.xml\n");
        }



            k=0;

            // Lese Records aus Binärdatei
            while(fread(Record, sizeof(structRec), 1, fpIN) == 1)
            {

                if (!strcmp(ovalue, "xml"))
                {
                    // Benötigter neuer Speicher
                    size += sizeof(structRec);

                    // Speicher reallozieren für Strukturtabelle
                    RecordTable = (structRec*) realloc(RecordTable, size);

                    // Speichere den eingelesenen Record in die Recordtabelle
                    RecordTable[k] = Record;

                    k++;
                }
             }

Währen der While schleife schreibt mir printf("%s", RecordTable[k]) das richtige auf die Konsole.

Allerdings nach der while schleife gibt mir printf ("%s", RecordTable[0]); und das ganze bis RecordTable[3] dasselbe heraus.

Das einlesen vom dat file haut also hin. Er kopiert mir das eingelesene Record struct auch ins RecordTable. Allerdings kommts mir vor als würde er in jedem while durchlauf alle Indexstellen von RecordTable mit dem aktuelle Inhalt der Record füllen und nicht nur gerade Index [k]. Zum Schluss ist in RecordTable[0] bis RecordTable[3] überall dasselbe im letzten while durchlauf eingelesene Record drinnen. Die anderen werden überspielt.

Weiss da jemand was?

habs auch mit memcopy oder strcpy nicht hinbekommen.

danke :)



Angabe:

Options: -i dat –o xml
Es soll die Binärdatei eingelesen werden und in das xml-Format konvertiert werden. Um die Anzahl der Records ermitteln zu können, müssen zuerst alle Binärdatensätze in eine dynamische Struct-Tabelle gelesen werden. Der Aufbau einer Struct-Tabelle ist gleich dem Aufbau einer String-Tabelle. Wenn die Struct-Tabelle fertig aufgebaut wurde, dann erfolgt die Ausgabe in die xml-Datei.
Achten Sie auf die ordnungsgemäße Freigabe von nicht mehr benötigtem dynamischen Speicher!
Bearbeitet von charmin am 16.05.2016, 12:56

Obermotz

Fünfzylindernazi
Avatar
Registered: Nov 2002
Location: OÖ/RI
Posts: 5262
Wuerde mir fuer spaeteres traversieren immer merken, wie lange die Liste schon ist..

Code: C
typedef struct {
	structRec **elem;
	size_t length;			
	size_t capacity;		
} RecList;


Reallocaten mit sowas in die Richtung (nicht getestet):

Code: C
size_t newCapacity = recList->capacity+1;
structRec ** newRecList = (structRec **) realloc(structRec->elem,	newCapacity * sizeof(structRec);

if (newRecList != NULL) {
			memset(newRecList + recList->capacity, 0,	(newCapacity - recList->capacity) * sizeof(structRec);

			newRecList ->elem = newElementList;
			newRecList ->capacity = newCapacity;
		}


// Zugriff via
newRecList ->elem[n]
Bearbeitet von Obermotz am 15.05.2016, 18:23

Vinci

hatin' on summer
Registered: Jan 2003
Location: Wien
Posts: 5777
Irgendwas kann bei der Berechnung der Größe nicht stimmen.

Code: C
// Benötigter neuer Speicher
size += sizeof(structRec);

// Speicher reallozieren für Strukturtabelle
RecordTable = (structRec*) realloc(RecordTable,     size*sizeof(structRec));

Du liest sizeof(structRec) ein, allozierst aber selbst bei der 1.Iteration schon size*sizeof(structRec).
So wie ich das seh brauchst du eigentlich immer nur "size" allozieren. Da steht ja die neue Größeninformation bereits drinnen.


/edit
Das is übrigens mit Sicherheit nicht die Lösung des Problems. Ich nehm mal an das .dat hat keine zig gb, also selbst wenn du massiv drüber allozierst dürft nix passieren...
Magst du nicht mal das .dat hochladen?
Bearbeitet von Vinci am 15.05.2016, 18:29

PuhBär

Schau ned so genau
Avatar
Registered: Sep 2002
Location: .
Posts: 1201
Das Problem ist, wie beim letzten Mal, dass du den Speicher, den du aus dem File einliest, nicht kopierst, sondern immer nur den Pointer kopierst.

Am Ende stehen in deiner Table lauter Pointer, die auf dem gleichen Speicher zeigen.

Du musst Record jedesmal neu allozieren, dann kannst du einfach wie bisher den Pointer kopieren.

Und RecordTable ist viel zu groß. Du brauchst nur um sizeof(Record*) zu erhöhen.
Bearbeitet von PuhBär am 15.05.2016, 18:44

charmin

Super Moderator
Muper Soderator
Avatar
Registered: Dec 2002
Location: aut_sbg
Posts: 13991
Das Programm liest ursprünglich ein xml file ein, macht ein csv draus, aus diesem dann ein dat und daraus wieder ein xml.


https://workupload.com/archive/crRGS2c

Hier die Dateien. Wurden von mir gekürzt, normalerweise sinds 13.000 records oder so. Jetzt schau ich mir mal eure Lösungsvorschläge an, danke!

@PuhBär: Ich versteh leider nur Bahnhof.

Was hat das jedesmal neu allozieren mit dem Pointer zu tun?

warum geht zb das nicht? Programm stürzt ab in dem Fall.

Code:
strcpy(RecordTable[k]->Interpret, Record->Interpret);

Ich will den Dreck eigentlich nur noch fertig haben.

Möchte nur den aktuellen Inhalt vom struct Record in eine Position meines structarrays structtable drinnen haben. Wie bekomm ich das hin?

Hab bisher den Pointer reinkopiert, ok. Wie kopier ich den Inhalt rein? bzw solche Pointer, die mir dann richtig hinzeigen.
Bearbeitet von charmin am 16.05.2016, 12:12

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11327
Zitat von charmin
Zitat von ccr
In Schottland kennst eh oft froh sein, wennst einmal 50km/h fahren kannst - und beim ständigen Ausweichen (weil die Straßen so eng sind) freust Dich auch über ein handlicheres Auto :p

P?

Code: C
    structRec *Record;
    structRec **RecordTable;

    Record = calloc(size, sizeof(structRec));
    RecordTable = calloc(size, sizeof(structRec));

Wenn RecordTable eine Liste von Pointern ist, warum reservierst du dann sizeof(structRec) dafür?

Code: C
                    // Benötigter neuer Speicher
                    size += sizeof(structRec);

                    // Speicher reallozieren für Strukturtabelle
                    RecordTable = (structRec*) realloc(RecordTable, size);

Du musst dich schon entscheiden, ob du eine Liste von Pointern auf structs oder eine Liste von structs speichern willst.

Code: C
                    // Speichere den eingelesenen Record in die Recordtabelle
                    RecordTable[k] = Record;

Das kopiert nur einen Pointer, nicht den Inhalt von structRec. Wenn du eine struct kopieren willst, nimm memcpy.

charmin

Super Moderator
Muper Soderator
Avatar
Registered: Dec 2002
Location: aut_sbg
Posts: 13991
Zitat von that
P?

ist 100 in diesem Fall, schlecht?

Zitat von that
Wenn RecordTable eine Liste von Pointern ist, warum reservierst du dann sizeof(structRec) dafür?

Keine Ahnung, brauche ich nicht?

Zitat von that
Du musst dich schon entscheiden, ob du eine Liste von Pointern auf structs oder eine Liste von structs speichern willst.

Weiss ich nicht, was ist "besser"?

Zitat von that
Das kopiert nur einen Pointer, nicht den Inhalt von structRec. Wenn du eine struct kopieren willst, nimm memcpy.

Okay, Siehe oben, "was ist besser?"


Siehe Angabe:

Angabe:

Options: -i dat –o xml
Es soll die Binärdatei eingelesen werden und in das xml-Format konvertiert werden. Um die Anzahl der Records ermitteln zu können, müssen zuerst alle Binärdatensätze in eine dynamische Struct-Tabelle gelesen werden. Der Aufbau einer Struct-Tabelle ist gleich dem Aufbau einer String-Tabelle. Wenn die Struct-Tabelle fertig aufgebaut wurde, dann erfolgt die Ausgabe in die xml-Datei.
Achten Sie auf die ordnungsgemäße Freigabe von nicht mehr benötigtem dynamischen Speicher!
Bearbeitet von charmin am 16.05.2016, 12:56

Blaues U-boot

blupp, blupp
Avatar
Registered: Aug 2005
Location: Graz
Posts: 1537
ich würds so machen:
jedes struct bekommt einen eigenen pointer auf seinem dynamischen speicher und diese pointer werden in einer liste gespeichert. dann braucht man nie structs herumkopieren. in der einleseschleife muss natürlich jedes struct neu allociert werden und der pointer einfach in die liste geschrieben.
wie man die liste aufbaut ist im prinzip egal (ich gehe mal davon aus, dass die größe unbekannt ist), entweder als dynamisches array oder eine linked-list ist wohl am einfachsten. die listengröße am besten immer mitspeichern, ist für die nachfolgeoperationen komfortabler.

charmin

Super Moderator
Muper Soderator
Avatar
Registered: Dec 2002
Location: aut_sbg
Posts: 13991
Okay, ich probiers mal weiter. Vielen Dank für euren Input. Wirklich! Ist nur grad etwas viel momentan mit Hackn, Schule, Projekt etc wah wah

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11327
Zitat von charmin
Weiss ich nicht, was ist "besser"?

Am einfachsten ist, wie das U-Boot schon sagt, eine Liste oder ein Array von Pointern auf Datensätze.

Das funktioniert dann ungefähr so (etwaige Fehler bitte selbst ausbessern :)):

Code: C
struct SomeRecord
{
  char name[100];
  ...
};

// Deklaration:
SomeRecord** array = NULL;
size_t arraysize = 0;


...


// Datensatz einfügen:
++arraysize;
array = realloc(array, arraysize * sizeof(SomeRecord*));  // Platz für "arraysize" Pointer
if (!array)
  handle_out_of_memory();
SomeRecord* currentRecord = calloc(1, sizeof(SomeRecord));  // Platz für einen Record reservieren
array[arraysize - 1] = currentRecord;  // den neuen Record im Array merken
strlcpy(currentRecord->name, "test", sizeof(SomeRecord::name));  // irgendwas reinfüllen
...


// alles freigeben:
for (size_t i = 0; i < arraysize; ++i)
  free(array[i]);
free(array);

charmin

Super Moderator
Muper Soderator
Avatar
Registered: Dec 2002
Location: aut_sbg
Posts: 13991
okay, setz mich gleich dran!

danke :)
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz