简介
最近大一的学弟开始布置C语言的大作业了,于是在此提供一种比较简单的2048存档读档功能的实现
1 获取当前目录及存档文件
记得自己大一的时候在这里研究了很久,在这里提供C语言的实现思路
首先是用到的函数介绍:
getcwd()
按住Ctrl后点击getcwd可以知道getcwd接受两个变量:一个char*,用于以字符串形式保存绝对地,另一个变量是第一个变量字符串的大小,以防止出现路径长度大于字符串长度的情况。返回值就是当前路径的字符串形式。以下是常见用法的demo
#include<unistd.h>//记得getcwd是在unistd.h头文件中的,使用时请记得包含相关头文件
char _paTh[2048];//用于储存当前路径
getcwd(_paTh,sizeof(_paTh));//将当前路径赋值给noWPos
对于这种用法有一个显而易见的问题:我们无法判断当前路径的长度,因此只能尽可能开大这个字符串的空间。但是另一方面,开过大的字符串难免会造成内存空间的浪费。
还记得之前说的getcwd的返回值是字符串首地址吗?在getcwd函数运行过程中,函数会自动申请空间来储存这个字符串。因此我们可以不给字符串申请空间来使getcwd自动申请内存空间,并将返回值首地址赋给用于储存的char*。样例如下:
char *path = NULL;
path = getcwd(NULL,0);
puts(path);//甚至可以直接puts(path)
fopen()
在获取到当前路径后,我们就可以用fopen函数打开存档文件,在此之前先复习下fopen的基本用法
fopen接受两个char*变量,第一个记录文件的路径,第二个表示文件的读取模式,返回值为File*(文件指针)
对于第一个变量,我们需要传入完整的文件路径,这就需要我们将文件名和路径两个字符串拼接在一起(不会的自行复习strcat()函数)
#include<stdio.h>
#include<string.h>//包含strcat()
#include<unistd.h>//包含getcwd()
char *path = NULL;//新建char* 空指针
path = getcwd(NULL,0);//保存绝对路径
strcat(path,"\\data.txt");//将存档文件名和路径拼接,由于转义字符的原因此处反斜杠要写两个
puts(path);//输出完整文件名测试
获取到文件名之后,按照fopen的访问规则打开文件即可,常用的访问规则有:
"r+" 打开一个用于更新的文件,可读取也可写入。该文件必须存在。
"w+" 创建一个用于读写的空文件。
对我们要实现的功能进行分析,读档自然是使用"r+"
模式,读取已有的存档,如不存在返回失败。
对于存档,覆盖已有存档或保存新存档,则使用"w+"
模式
综上所述,对于存档打开过程,可以写出如下代码:
void save(){
FILE* f;
char *path = NULL;
path = getcwd(NULL,0);
puts(path);
strcat(path,"\\data");
puts(path);
f=fopen(path,"w+");
}
void lord(){
FILE* fp;
char *path = NULL;
path = getcwd(NULL,0);
puts(path);
strcat(path,"\\data");
puts(path);
fp=fopen(path,"r+");
if(fp==NULL){printf("不存在存档\n");return;}
}
存档格式
在讨论存档格式前,我们先参考下常见ACM题目对于图论存图的用例形式
由此可知,我们可以使用邻接矩阵的方式,在文件和内存之间相互转化
设计文件格式如下:
第一行,给出一个整数n
,表示方阵的边长(如不是方阵则设为n m
两个整数分别表示长和宽)
以下n
行,每行给出n
个整数,表示当前位置的值
文件流的输入输出:fscanf()和fprintf()
由函数名就不难看出,这两个函数与scanf()
和printf()
非常相似,事实上这两个函数在使用上只要在传参的最前面加上FILE* fp
即可
例如从fp
指向的文件读入一个整数到n
:
fscnaf(fp,"%d",&n);//对比scanf("%d",&n)
再例如向fp
指向的文件输出一个整数n
:
fprintf(fp,"%d",n)//对比printf("%d",n)
综上我们可以写出完整的存档读档代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int** map;//存图数组
int n;//图的大小
void save(){
FILE* f;
char *path = NULL;
path = getcwd(NULL,0);
puts(path);
strcat(path,"\\data");
puts(path);//输出完整的地址用于测试
f=fopen(path,"w+");//打开文件
fprintf(f,"%d\n",n);//输出尺寸
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
fprintf(f,"%d ",map[i][j]);//输出图
fprintf(f,"\n");
}
return;
}
void lord(){
FILE* fp;
char *path = NULL;
path = getcwd(NULL,0);
puts(path);
strcat(path,"\\data");
puts(path);//输出完整地址用于测试
fp=fopen(path,"r+");//打开文件
if(fp==NULL){printf("不存在存档\n");return;}//特判:如不存在改存档直接报错
fscanf(fp," %d",&n);//读入图的大小
map=(int**)malloc(n*sizeof(int*));//申请空间
for(int i=0;i<n;i++)
map[i]=(int**)malloc(n*sizeof(int));
//申请空间完成
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
fscanf(fp,"%d ",&map[i][j]);//依次读入图的元素
return;
}
void get_data(){//简单的获取存档函数
printf("请输入你要 1.存档还是 2.读档\n");
int c;scanf("%d",&c);
if(c==1)save();
else lord();
}
void tsave(){//测试存档功能的函数,生成一个图并存入data文件
scanf("%d",&n);
map=(int**)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)map[i]=(int**)malloc(n*sizeof(int));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&map[i][j]);
}
void tlord(){//测试读档功能的函数,在控制台输出从data文件读区的存档
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("%d ",map[i][j]);
printf("\n");
}
}
int main(){
// tsave();
get_data();
// tlord();
return 0;
}
测试读档功能:
测试存档功能: