2017-12-15 3 views
1

Ich versuche, ein Brett (das ist ein 2D-Array, das dynamisch zugewiesen wurde) in einer Datei zu speichern, so dass es später von der "geladen" werden kann Benutzer und sie können das Board wieder verwenden. Um die Karte zu speichern, muss der Benutzer s filename eingeben. Um die Benutzereingabe zu bekommen, habe ich ein anderes if-Anweisung für den Befehl speichern:Wie schreibe ich ein 2D-Array in eine Datei und zurück in C

else if (playerMove.command == 's') { 
    char* fileName = NULL; 
    scanf(" %s", fileName); 
    implementSave(boardState, fileName); 

Da haben wir nur gelernt, wie man/offen lesen/schreiben, um binäre Dateien in C habe ich versucht, das gleiche zu tun für dies in meiner imploreSave-Funktion:

void implementSave(BoardState* boardState, char* fileName) { 
    FILE* file = fopen(fileName, "wb"); 
    fwrite(fileName, sizeof(char), sizeof(boardState->board.theBoard), file); 
    fclose(file); 
} 

Hinweis: Ich verwende einige Strukturen in meinem Programm; Die Struktur board enthält char** theBoard, int numRows, int numCols, char blankSpace.

Allerdings gibt dies mir einen Fehler, wenn ich versuche, den Speicherbefehl auszuführen. Kann mir jemand in die richtige Richtung zeigen?

+1

Welche Fehler? Wenn es nicht korrekt gespeichert wird, liegt das daran, dass 'sizeof' ein' char ** '4 oder 8 (oder so ähnlich) ist. Sie sollten die Anzahl der Zeichenzellen berechnen, die direkt gespeichert oder geladen werden sollen: 'boardState-> board.numRows * boardState-> board.numCols'. –

+0

'char * Dateiname = NULL; scanf ("% s", Dateiname); '- Sie haben keinen Speicher für den' fileName' zugewiesen .... Beachten Sie auch, dass die '% s' Direktive _automatisch_ über führende Whitespaces überspringt, so dass das führende Leerzeichen nicht benötigt wird die Formatzeichenfolge. –

+0

Hängt davon ab, was "BoardState" ist. Aber 'fwrite (fileName, sizeof (char), sizeof (boardState-> board.theBoard), file);' sieht sowieso total falsch aus. Meinten Sie 'fwrite (boardState, sizeof (char), sizeof (boardState-> board.theBoard), Datei);'? –

Antwort

0

Sie können nicht einfach den Doppelzeiger in Datei schreiben. Sie müssen jedes Element im ersten Zeiger indizieren und die Daten in Teile von Zeilen (oder Spalten) schreiben, aber ich habe Zeilen demonstriert. Verwenden Sie dazu eine for-Schleife. Beachten Sie, dass (unter der Annahme, dass die Karte ist, die Sie in der binäre Datei speichern) die resultierende Dateigröße numRow * numCol Bytes sein sollte.

int i; 
for (i = 0; i < BoardState->board.numRow; ++i) { 
     fwrite(BoardState->board.theBoard[i], sizeof(char), BoardState->board.numCol, file) 
} 

(„Laden“), um die Datei zu lesen, ist oben in umgekehrter Reihenfolge des Codes getan - beachten Sie, dass es nicht ratsam ist, nur das Board einer Datei zu speichern - Ich schlage vor, am Anfang der Datei speichern Sie die Anzahl der Zeilen und Spalten, um die Zuordnung von Speicher beim Lesen (Laden) der Datei zu erleichtern.

So vorausgesetzt, Sie speichern die Anzahl der Zeilen/Spalten in einem int der obige Code wird dann

fwrite(&BoardState->board.numRow, sizeof(int), 1, file); 
fwrite(&BoardState->board.numCol, sizeof(int), 1, file); 
int i; 
for (i = 0; i < BoardState->board.numRow; ++i) { 
     fwrite(BoardState->board.theBoard, sizeof(char), BoardState->board.numCol, file) 
} 

HINWEIS diese die Möglichkeit hat, endianness Probleme einzuführen. Sie können Google, wenn Sie interessiert sind.

+0

Ich werde Ihre Antwort aufwerten, wenn Sie die Aufrufe von 'fwrite()' für die korrekte Verwendung von Argumenten beheben. –

+0

@ Dúthomhas hat das nicht verstanden! Danke - schwer zu beantworten/bearbeiten auf dem Handy. – Ankush

+1

Ja, ich habe gelernt, dass es sich nicht lohnt, wenn ich nicht vor meinem PC sitze. –

1

Dieser Code

fwrite(fileName, sizeof(char), sizeof(boardState->board.theBoard), file); 

bedeutet:

schreiben Daten in die Datei file. Die Daten befinden sich am Speicherort fileName Punkte, die Daten bestehen aus sizeof(boardState->board.theBoard) Artikel und jeder einzelne Artikel ist sizeof(char) Bytes groß.

Klingt das richtig für Sie? Ich denke nicht; Es ist schon falsch, dass die Daten an der Position fileName Punkte gefunden werden können, da Sie die Board-Daten in die Datei und nicht den Dateinamen schreiben wollen, oder?

Auch vorsichtig sein mit sizeof(); sizeof() kann den Inhalt einiger Speicher nicht dynamisch ermitteln, er kennt nur die Größe des statischen Speichers. Z.B.

char test[20]; 
size_t s = sizeof(test); 

s wird 20 sein.Aber jetzt diese betrachten:

char test[20]; 
char * ptr = test; 
size_t s = sizeof(ptr); 

Jetzt s 4 sein wird oder 8 als Zeiger in der Regel 4 Bytes groß oder 8 Byte groß sind. sizeof() gibt Ihnen hier die Größe des Zeigers, nicht die Größe des Speichers, auf den der Zeiger zeigt. Es gibt in C keine Möglichkeit, die Größe eines Speicherblocks zu erhalten, auf den ein Zeiger zeigt, diese Größe muss immer bekannt sein.

Sie sagen, Ihr Board ist char ** theBoard, also ist das Board ein Zeiger auf ein Array von Zeigern auf Speicher oder Zeichen.

theBoard -> [0] -> ['a1', 'b1', 'c1', 'd1', ... ] 
      [1] -> ['a2', 'b2', 'c2', 'd2', ... ] 
      [2] -> ['a3', 'b3', 'c3', 'd3', ... ] 
      : 

In diesem Fall wird die Code-Erzeugung müßte so aussehen (unter der Annahme, dass die [0], [1], ... sind die Zeilen):

theBoard = calloc(numberOfRows, sizeof(char *)); 
for (size_t i = 0; i < numberOfRows; i++) { 
    theBoard[i] = calloc(numberOfCols, sizeof(char)); 
} 

Wenn das der Fall ist , müssen Sie Ihre Daten Zeile für Zeile schreiben:

for (size_t row = 0; row < numberOfRows; row++) { 
    fwrite(boardState->board.theBoard[row], sizeof(char), numberOfCols, file); 
} 

natürlich unter der Annahme, dass alle Zeilen eine gleiche Anzahl von Spalten haben müssen.

Wenn ich Ihnen einen Tipp geben kann, machen Sie nicht die Platine char **, machen Sie es einfach char *, wie es alles so viel einfacher macht. Sehen Sie, wenn Ihr Board 20x30 (20 Zeilen, 30 Spalten), dann können Sie Ihr Board wie folgt definieren:

char * theBoard = calloc(numberOfRows * numberOfCols, sizeof(char)) 

Jetzt haben Sie nur ein einzelnes Array, wie folgt aus:

theBoard -> ['a1', 'b1', 'c1', 'd1', ... , 
      'a2', 'b2', 'c2', 'd2', ... , 
      'a3', 'b3', 'c3', 'd3', ... , 
      : 
      ] 

Wie Würden Sie auf ein bestimmtes Feld zugreifen? Ganz einfach:

int row = 5; 
int col = 8; 
char field = theBoard[(row * numberOfCols) + col]; 

Und dann können Sie das gesamte Brett in einem Aufruf schreiben:

fwrite(theBoard, sizeof(char), numberOfRows * numberOfCols, file); 

See, viel einfacher. Sie können auch nur das gesamte Board befreien free(theBoard); durch den Aufruf während bei den char ** Ansatz verwenden, müssen Sie dies tun, statt:

for (size_t i = 0; i < numberOfRows; i++) { 
    free(theBoard[i]); 
} 
free(theBoard); 
Verwandte Themen