我试图将一块电路板(这是一个已动态分配的2D阵列)保存到一个文件中,以便以后加载"用户可以再次使用该板。要保存电路板,用户必须输入s filename
。为了获得用户输入,我有一个else命令的if语句:
else if (playerMove.command == 's') {
char* fileName = NULL;
scanf(" %s", fileName);
implementSave(boardState, fileName);
由于我们只学习了如何在C中读取/打开/写入二进制文件,我试图在我的implementSave函数中为此做同样的事情:
void implementSave(BoardState* boardState, char* fileName) {
FILE* file = fopen(fileName, "wb");
fwrite(fileName, sizeof(char), sizeof(boardState->board.theBoard), file);
fclose(file);
}
注意:我在程序中使用了一些结构; struct board
包含char** theBoard, int numRows, int numCols, char blankSpace
。
但是,当我尝试运行save命令时,这会给我一个错误。有人能指出我正确的方向吗?
答案 0 :(得分:1)
此代码
fwrite(fileName, sizeof(char), sizeof(boardState->board.theBoard), file);
表示:
将数据写入文件
file
。数据位于内存位置fileName
处,数据由sizeof(boardState->board.theBoard)
个项目组成,每个项目的sizeof(char)
字节大。
这听起来对你好吗?我不这么认为;它是错误的,可以在fileName
位置找到数据,因为你想将电路板数据写入文件而没有文件名,对吗?
另外要小心sizeof()
; sizeof()
无法动态确定某些内存的内容,它只知道静态内存的大小。 E.g。
char test[20];
size_t s = sizeof(test);
s
将是20.但现在考虑一下:
char test[20];
char * ptr = test;
size_t s = sizeof(ptr);
现在s
将是4或8,因为指针通常是4个字节大小或8个字节大小。 sizeof()
为您提供指针的大小,而不是指针指向的内存大小。在C中没有办法获得指针所指向的内存块的大小,这个大小必须始终是已知的。
你说你的电路板是char ** theBoard
,所以theBoard是一个指向内存或字符指针数组的指针。
theBoard -> [0] -> ['a1', 'b1', 'c1', 'd1', ... ]
[1] -> ['a2', 'b2', 'c2', 'd2', ... ]
[2] -> ['a3', 'b3', 'c3', 'd3', ... ]
:
在这种情况下,创建代码需要看起来像那样(假设[0],[1],...是行):
theBoard = calloc(numberOfRows, sizeof(char *));
for (size_t i = 0; i < numberOfRows; i++) {
theBoard[i] = calloc(numberOfCols, sizeof(char));
}
如果是这种情况,您需要逐行编写数据:
for (size_t row = 0; row < numberOfRows; row++) {
fwrite(boardState->board.theBoard[row], sizeof(char), numberOfCols, file);
}
当然,假设所有行都有相同数量的cols。
如果我可以给你一个小费,不要让小组char **
成为char *
,因为它会使一切变得更加容易。如果您的电路板是20x30(20行,30列),那么您可以像这样定义您的电路板:
char * theBoard = calloc(numberOfRows * numberOfCols, sizeof(char))
现在你只有一个数组,如下所示:
theBoard -> ['a1', 'b1', 'c1', 'd1', ... ,
'a2', 'b2', 'c2', 'd2', ... ,
'a3', 'b3', 'c3', 'd3', ... ,
:
]
您将如何访问特定字段?很简单:
int row = 5;
int col = 8;
char field = theBoard[(row * numberOfCols) + col];
然后你可以通过一个电话编写整个电路板:
fwrite(theBoard, sizeof(char), numberOfRows * numberOfCols, file);
看,更容易。您也可以通过调用free(theBoard);
释放整个电路板,而在使用char **
方法时,则必须执行此操作:
for (size_t i = 0; i < numberOfRows; i++) {
free(theBoard[i]);
}
free(theBoard);
答案 1 :(得分:0)
您不能只将双指针写入文件。您必须索引第一个指针中的每个元素,并将数据写入行(或列)中,但我已经演示了行。为此,请使用for循环。请注意(假设电路板 all ,您将保存到二进制文件),生成的文件大小应为numRow * numCol
字节。
int i;
for (i = 0; i < BoardState->board.numRow; ++i) {
fwrite(BoardState->board.theBoard[i], sizeof(char), BoardState->board.numCol, file)
}
读取(“加载”)文件与上面的代码相反 - 请注意,仅将板保存到文件是不明智的 - 我建议在文件的开头保存行数和列数到在读取(加载)文件时,可以轻松分配内存。
因此,假设您将行/列的数量存储在上面的代码中,则变为
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)
}
注意这有可能引入字节序问题。如果您感兴趣,可以使用Google。