小小只123 2022-03-23 22:36 采纳率: 50%
浏览 91

请问这种情况怎么办啊,研究好长时间了

img

img

img

img

img

img

img

img

img


以下写的,感觉很多地方不妥,调试了很多地方出现错误

#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;
    }
}


  • 写回答

1条回答 默认 最新

  • 赵4老师 2022-03-24 11:04
    关注

    代码功能归根结底不是别人帮自己看或讲解或注释出来的;而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。
    提醒:再牛×的老师也无法代替学生自己领悟和上厕所!
    单步调试和设断点调试(VS IDE中编译连接通过以后,按F10或F11键单步执行,按Shift+F11退出当前函数;在某行按F9设断点后按F5执行停在该断点处。)是程序员必须掌握的技能之一。

    评论

报告相同问题?

问题事件

  • 创建了问题 3月23日

悬赏问题

  • ¥66 关于川崎机器人调速问题
  • ¥15 winFrom界面无法打开
  • ¥15 crossover21 ARM64版本安装软件问题
  • ¥15 mymetaobjecthandler没有进入
  • ¥15 mmo能不能做客户端怪物
  • ¥15 osm下载到arcgis出错
  • ¥15 Dell g15 每次打开eiq portal后3分钟内自动退出
  • ¥200 使用python编写程序,采用socket方式获取网页实时刷新的数据,能定时print()出来就行。
  • ¥15 matlab如何根据图片中的公式绘制e和v的曲线图
  • ¥15 我想用Python(Django)+Vue搭建一个用户登录界面,但是在运行npm run serve时报错了如何解决?