以下写的,感觉很多地方不妥,调试了很多地方出现错误
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <direct.h>//getcwd函数头文件
#include <malloc.h>
#include <io.h>//access函数头文件
void getParam(CONF* conf);
void getRecNum(CONF* conf);
void getFileName(CONF* conf);
int checkFilePath(char* path);
void splitFilePath(CONF* conf, char* path);
void fixFileName(CONF* conf);
int random(int max, int min);
void createFile(CONF conf);
int isNumber(char* str);
int strToNumber(char* str);
#define MAX_STR_LEN 4000
#define MAX_RANDOM 100
#define MAX_BUF 1024
#define MAX_NUM 500
#define MIN_NUM 50
typedef struct configinfo
{
char filesavepath[MAX_STR_LEN]; //用于存放数据记录文件的存储目录
char filename[MAX_STR_LEN]; //用于存储数据记录文件的文件名信息
int number; //用于存放生成的记录条数
int maxvalue1; //用于存放实验2中生成的数据记录三元组中第1、2个元素取值的上限
int minvalue1; //用于存放实验2中生成的数据记录三元组中第1、2个元素取值的下限
int maxvalue2; //用于存放实验2中生成的数据记录三元组中第3个元素取值的上限
int minvalue2; //用于存放实验2中生成的数据记录三元组中第3个元素取值的下限
int recordcount1; //用于存放数据记录文件需要随机生成记录条数时条数值的上限
int recordcount2; //用于存放数据记录文件需要随机生成记录条数时条数值的下限
}CONF;
int main(int argc, char* argv[])
{
run(argc, argv); //调用程序主功能实现函数
return 0;
}
void run(int argc, char* argv[])
{
CONF sys_info;
//结构体变量各分量初始化默认值
FILE* fp;
if ((fp = fopen("repos\conf.ini.txt", "r")) == NULL) {
printf("文件没有被打开\n");
exit(EXIT_FAILURE);//这条语句是退出程序的意思
}
else {
fgets(sys_info.filesavepath, 20, fp);
fgets(sys_info.filename, 20, fp);
fgets(sys_info.filesavepath, 20, fp);
sys_info.number = 0;
fscanf(fp, "%d", &sys_info.maxvalue1);
fscanf(fp, "%d", &sys_info.minvalue1);
fscanf(fp, "%d", &sys_info.maxvalue2);
fscanf(fp, "%d", &sys_info.minvalue2);
fscanf(fp, "%d", &sys_info.recordcount1);
fscanf(fp, "%d", &sys_info.recordcount2);
}
srand((int)time(0));//设置随机数种子
if (argc == 1)
{
getParam(&sys_info);//通过界面交互获取记录条数和文件存储路径参数
createFile(sys_info);//生成数据文件
}
else if (argc == 2)
{
if (isNumber(argv[1]))
{
if (strToNumber(argv[1]) == 0)
{
sys_info.number = random(sys_info.recordcount1, sys_info.recordcount2);
printf("已随机生成记录条数:%d\n", sys_info.number);
}
else
{
sys_info.number = strToNumber(argv[1]);
printf("您输入的记录条数为:%d\n", sys_info.number);
}
getFileName(&sys_info);//实参是结构体类型变量,形参用结构体类型的引用
createFile(sys_info);
}
else
{
if (checkFilePath(argv[1]))//若用户输入的文件名及文件存储目录合法
{
getRecNum(&sys_info);
splitFilePath(&sys_info, argv[1]);//拆分用户输入的文件名及文件存储目录
createFile(sys_info);
}
else
{
printf("命令行参数中文件存储路径不合法,请修改后尝试!\n");
}
}
}
else if (argc == 3)
{
if (isNumber(argv[1]))
{
if (strToNumber(argv[1]) == 0)
{
sys_info.number = random(sys_info.recordcount1, sys_info.recordcount2);
printf("已随机生成记录条数:%d\n", sys_info.number);
}
else
{
sys_info.number = strToNumber(argv[1]);
printf("您输入的记录条数为:%d\n", sys_info.number);
}
if (checkFilePath(argv[2]))
{
splitFilePath(&sys_info, argv[2]);
createFile(sys_info);
}
else
{
printf("命令行参数中文件存储路径不合法,请修改后尝试!\n");
}
}
else if (isNumber(argv[2]))
{
if (strToNumber(argv[2]) == 0)
{
sys_info.number = random(sys_info.recordcount1, sys_info.recordcount2);
printf("已随机生成记录条数:%d\n", sys_info.number);
}
else
{
sys_info.number = strToNumber(argv[2]);
printf("您输入的记录条数为:%d\n", sys_info.number);
}
if (checkFilePath(argv[1]))
{
splitFilePath(&sys_info, argv[1]);
createFile(sys_info);
}
else
{
printf("命令行参数中文件存储路径不合法,请修改后尝试!\n");
}
}
else
{
printf("您输入的两个参数中无法识别出记录条数参数,系统无法运行,请重新尝试!\n");
}
}
else
{
printf("您输入参数超过了系统参数限制,系统无法处理,请重新尝试!\n");
}return 0;
}
/***********************************************************************
函数名称:getParam
函数功能:通过界面交互获取记录条数及文件存储路径参数
输入参数:CONF* conf(配置参数结构体指针,指向存放配置信息的结构体)
返 回 值:无
模块历史:
*************************************************************************/
void getParam(CONF* conf)
{
getRecNum(conf);
getFileName(conf);
}
/***********************************************************************
函数名称:getRecNum
函数功能:通过界面交互获取记录条数
输入参数:CONF* conf(配置参数结构体指针,指向存放配置信息的结构体)
返 回 值:无
模块历史:
*************************************************************************/
void getRecNum(CONF* conf)
{
char temp[MAX_STR_LEN];
printf("请输入您需要生成的记录条数(输入0或r表示随机生成记录条数):\n");
scanf("%s", temp);
getchar(); //清空输入缓冲区,以防止一次输入多余缓冲干扰二次输入
//判断用户输入是否合法
while (!isNumber(temp))
{
printf("您的输入无法转换为整数,请重新输入:\n");
scanf("%s", temp);
getchar();
}
conf->number = strToNumber(temp);
printf("您输入的记录条数为:%d\n", conf->number);
if (conf->number == 0)
{
conf->number = random(conf->recordcount1, conf->recordcount2);
printf("已随机生成记录条数:%d\n", conf->number);
}
}
/***********************************************************************
函数名称:getFileName
函数功能:通过界面交互获取文件存储路径参数
输入参数:CONF* conf(配置参数结构体指针,指向存放配置信息的结构体)
返 回 值:无
模块历史:
*************************************************************************/
void getFileName(CONF* conf)
{
char user_input[MAX_STR_LEN];
printf("请输入您需要生成的记录文件名称(输入no表示使用默认文件名):\n");
scanf("%s", user_input);
getchar();
while (!checkFilePath(user_input))
{
printf("您的输入文件名或文件路径非法,请重新输入:\n");
scanf("%s", user_input);
getchar();
}
splitFilePath(conf, user_input);
}
/***********************************************************************
函数名称:checkFilePath
函数功能:检查输入的文件路径及文件名是否合法
输入参数:char* path(文件路径)
文件路径合法性规则:
1)文件不能以'//'(可以以'\'开头,表示从当前盘符位置开始计算)
2)":\\"或":/"均表示绝对路径,如"E:\\abc\\111.txt"和"E:/abc\\111.txt"均为正确路径
3)路径不能以"\\"或"/"结尾,以这两个结尾的话就相当于文件名为空
4)相对路径中不能出现':',绝对路径中":"必须与'\\'或'/'成对出现,并且只能出现一次,其他情况下再出现':'也为非法
5)目录名或文件名中不能出现非法字符包括:':'、'*'、'?'、'\"'、'<'、'>'、'|'
6)路径中'\\'和'/'分隔符可以混用,都是合法的
返 回 值:不合法,返回0;合法,返回1
模块历史:
*************************************************************************/
int checkFilePath(char* path)
{
//不能以'//'开头
if (*path == '//')
{
return 0;
}
//不能以"\\"或"/"结尾,以这两个结尾的话就相当于文件名为空
char* index1 = strrchr(path, '\\');//strrchr函数用于查找一个字符在一个字符串中末次出现的位置
char* index2 = strrchr(path, '/');
if (index1 - path + 1 == strlen(path) || index2 - path + 1 == strlen(path))
{
return 0;
}
//判断输入的路径是绝对路径还是相对路径
char* p1 = strstr(path, ":\\"); //strstr函数用于在字符串中查找第一次出现某字符串的位置
char* p2 = strstr(path, ":/");
if (p1 || p2) //输入的是绝对路径
{
//单独将盘符取出
char disk[3];
char* index;
if (p1)
{
strncpy(disk, path, p1 - path + 1);//strncpy函数用于将指定长度的字符串复制到字符数组中
index = p1;
}
if (p2)
{
strncpy(disk, path, p2 - path + 1);
index = p2;
}
disk[2] = 0;//disk[0]和disk[1]有值
//判断盘符是否存在
if (_access(disk, 0) != 0)//access函数用来判断指定的文件或目录是否存在,存在返回0,不存在返回-1
{
return 0;
}
//将绝对路径盘符后的字符串取出
int full_len = strlen(path);
int sub_index = index - path + 2;//从规范盘符位置起算其值为3
char sub_path[MAX_STR_LEN];
strncpy(sub_path, index + 2, full_len - sub_index);//截取文件路径,数组sub_path[]长度为full_len-sub_index
sub_path[full_len - sub_index] = 0;//数组sub_path[]从0到full_len-sub_index-1有值
//判断路径中是否有非法字符
if (strstr(sub_path, ":") || strstr(sub_path, "*") || strstr(sub_path, "?") || strstr(sub_path, "\"") || strstr(sub_path, "<") || strstr(sub_path, ">") || strstr(sub_path, "|"))
{
return 0;
}
}
else
{
if (strstr(path, ":") || strstr(path, "*") || strstr(path, "?") || strstr(path, "\"") || strstr(path, "<") || strstr(path, ">") || strstr(path, "|"))
{
return 0;
}
}
return 1;
}
/***********************************************************************
函数名称:splitFilePath
函数功能:拆分用户输入的文件存储路径,将文件存储目录信息与文件名信息拆分开,分别存入配置结构体变量
输入参数:CONF* conf(配置参数结构体指针,指向存放配置信息的结构体),char* path(文件路径)
返 回 值:无
模块历史:
*************************************************************************/
void splitFilePath(CONF* conf, char* path)
{
//判断输入的路径是绝对路径还是相对路径
char* p1 = strstr(path, ":\\");//在参数path所指向的字符串中查找第一次出现特定字符串的位置,不包含终止符 '\0'
char* p2 = strstr(path, ":/"); //绝对路径
if (p1 || p2) //输入的是绝对路径
{
char* index1 = strrchr(path, '\\');//在参数path所指向的字符串中搜索最后一次出现特定字符串的位置,并输出其后字符串
char* index2 = strrchr(path, '/');
char* index;
if (index1 > index2)
{
index = index1;//index是带有符号的文件名字符串
}
else
{
index = index2;
}
int full_len = strlen(path);
int sub_index = index - path + 1;//得到除去文件名的字符串长度
strncpy(conf->filesavepath, path, sub_index);//用于将指定长度的字符串复制到字符数组中
conf->filesavepath[sub_index] = 0;
strncpy(conf->filename, index + 1, full_len - sub_index);
conf->filename[full_len - sub_index] = 0;
}
else //输入的是相对路径
{
char* index1 = strrchr(path, '\\');//在参数path所指向的字符串中搜索最后一次出现特定字符串的位置,并输出其及其后字符串
char* index2 = strrchr(path, '/');
char* index;
if (index1 > index2)
{
index = index1;
}
else
{
index = index2;
}
if (index)
{
//当相对路径中包含目录信息时,将目录信息和文件名信息分别提取
int full_len = strlen(path);
int sub_index = index - path + 1;
strncpy(conf->filesavepath, path, sub_index);
conf->filesavepath[sub_index] = 0;
strncpy(conf->filename, index + 1, full_len - sub_index);
conf->filename[full_len - sub_index] = 0;
}
else
{
//当相对路径中不含目录信息时,直接作为文件名处理
if (strcmp(path, "no") == 0)
{
path = conf->filename;
printf("已使用默认文件名:%s\n", conf->filename);
}
strcpy(conf->filename, path);
}
}
fixFileName(conf);
}
/***********************************************************************
函数名称:fixFileName
函数功能:生成规范文件名
输入参数:CONF* conf(配置参数结构体指针,指向存放配置信息的结构体)
返 回 值:无
模块历史:
*************************************************************************/
void fixFileName(CONF* conf)
{
char* Name = ".txt";
int len = strlen(conf->filename); //取文件名字符串长度
if (len < 4) //文件名字符串长度小于等于4,则认为其无格式后缀
{
strcat(conf->filename, Name); //给文件名字符串添加“.txt”格式后缀
}
else
{
int flag = ((strcmp(conf->filename + (len - 4), ".txt") && strcmp(conf->filename + (len - 4), ".dat")));
//判断文件名字符串中有无“.txt”或“.dat”格式后缀,strcmp函数比较相同返回0
if (flag)
{
strcat(conf->filename, Name); //给文件名字符串添加“.txt”格式后缀
}
}
}
/***********************************************************************
函数名称:random
函数功能:随机生成有上下限的值,值域为[min, max]
输入参数:最大值max,最小值min
返 回 值:number
模块历史:
*************************************************************************/
int random(int max, int min)
{
int number;
number = ((rand() % (max - min + 1)) + min);
return number;
}
/***********************************************************************
函数名称:createFile
函数功能:生成数据文件
输入参数:CONF conf(配置参数结构体)
返 回 值:无
模块历史:
*************************************************************************/
void createFile(CONF conf)
{
char buffer[MAX_BUF] = { 0 };
if (_access(conf.filesavepath, 0) != 0)//access函数判断文件目录有效返回0,无效返回-1
{
printf("文件目录不存在,已使用当前工作目录!\n");
getcwd(buffer, sizeof(buffer));//将当前工作目录的绝对路径存入buffer
}
else
{
strcpy(buffer, conf.filesavepath);
}
if (*buffer == NULL)
{
printf("文件目录不存在,且创建失败!\n");
}
else
{
char buf[4] = "\\";
strcat(buffer, buf);
strcat(buffer, conf.filename);
FILE* fp = NULL;
fp = fopen(buffer, "w+");
if (!fp)
{
printf("文件打开失败!\n");
}
else //文件打开/创建成功
{
//申请行数未定的数组a的动态存储空间
int** a = (int**)malloc(sizeof(int*) * conf.number); //申请n行动态内存分配空间
for (int i = 0; i < conf.number; i++)
{
a[i] = (int*)malloc(sizeof(int) * 3); //申请3列动态内存分配空间
}
//给数组a的元素赋值
for (int i = 0; i < conf.number; i++)
{
int j = 0;
a[i][j] = random(conf.maxvalue1, conf.minvalue1);
j++;
a[i][j] = random(conf.maxvalue1, conf.minvalue1);
while (a[i][0] == a[i][1])
{
a[i][1] = random(conf.maxvalue1, conf.minvalue1);
}
j++;
a[i][j] = random(conf.maxvalue2, conf.minvalue2);
}
fprintf(fp, "%d\n", conf.number);//在文件中打印条数信息
//将数组a中的元素打印到文件中
for (int i = 0; i < conf.number; i++)
{
for (int j = 0; j < 3; j++)
{
if (j != 2)
fprintf(fp, "%d,", a[i][j]); //将int型数字打印到文件中
else
fprintf(fp, "%d", a[i][j]); //将int型数字打印到文件中
}
fprintf(fp, "\n");
}
fclose(fp); //关闭文件
//释放动态申请的堆区空间
for (int i = 0; i < conf.number; i++)
{
free(a[i]); //逐个释放指针内存
}
free(a); //释放指向指针的二级指针内存
}
}
printf("输出文件‘%s’生成成功!\n", conf.filename);
}
/***********************************************************************
函数名称:isNumber
函数功能:判断字符串首字符是否为数值
输入参数:字符串str
返 回 值:首字符为数值则返回1;非数值则返回0
模块历史:
*************************************************************************/
int isNumber(char* str)
{
if (*str >= '0' && *str <= '9')
{
return 1;
}
else if (strcmp(str, "r") == 0)
{
return 1;
}
else
{
return 0;
}
}
/***********************************************************************
函数名称:strToNumber
函数功能:从字符串中提取数值
输入参数:字符串str
返 回 值:数值number
模块历史:
*************************************************************************/
int strToNumber(char* str)
{
int len = strlen(str); //获取命令行参数字符串的长度
int k = 0, number = 0;
if (strcmp(str, "r") == 0)
{
return number;
}
else
{
for (int i = 0; i < len; i++)
{
while (str[i] >= '0' && str[i] <= '9') //依次获取数字字符串的数值
{
k = number;
number = number * 10 + (str[i] - '0'); //位乘相加,恢复数字字符串的int数值
if (number > MAX_NUM)
{
number = k;
printf("记录条数过大,已取有效位数(不大于%d),", MAX_NUM);
i = len;
}
else i++;
}
}
return number;
}
}