LINUX 入门 2.3

LINUX 入门 2

day5 20240428 耗时:135min

课程链接地址

第2章 linux c 通讯录

接上回,两个文件操作

c语言开发知识点很综合了,掌握上一章和这一章差不多了

C基础

  1. 二级指针问题

    1. 如果不改变指针,只通过指针访问,一级就行;
    2. 如果涉及通过指针改变内容用二级,对链表插入,删除链表元素,可能空链表情况需要二级(指针的指针)

    试了一下不用二级指针**ppeople,用一级指针*people,涉及改变空指针的delete和insert有什么bug:

    1. insert:会插不进去,宏那里LIST_INSERT有问题
    2. delete: 还行,因为先search找不到;但貌似删只剩一个的时候,有问题,删不掉而且name改了会
  2. 函数如果传入形参改值,不用值传递,用引用传递类似& 用*

    比如int change(int *cnt)而不是int change(int cnt), 然后是(*count)++

    接受一个指向整数的指针 cnt 作为参数,并对指针所指向的整数进行递增操作

  3. 常见错误不是struct *contacts ctsstruct contacts *cts

  4. 不建议用goto,因为循环里goto跳来跳去,嵌套很乱

7 文件保存与加载的接口层实现

想看效果可以

cat b.txt
  1. 保存

    1. 用循环,没用递归实现save,以键值对的struct 存到file里,遍历一个存一个
    2. 接口和支持层放在一起,然后再业务层
    3. 文件操作自己查:
      1. fprintf打印到文件里,printf打印到command终端
      2. fprintf要再fflush,因为fprintf写道缓存cache里要flush刷新到磁盘里,真正做到落盘
      3. fclose
  2. 加载

    1. feof(fp)是不是结尾,是返回0

    2. buffer大小,注意这种数字统统放前面宏定义define,不然很容易乱掉!!

    3. 读行+解析内容:

      fgets(buffer, 长度,fp) 读一行,然后分装parser解析出name phone用上一章的状态机统计文字个数,妙啊!!!!!!

      长这样

      name: qiuxiang,telephone: 98765678123
      

      遇到空格状态跳1,默认0, 再用person_insert插入到ppeople

完整代码

int save_file(struct person *people, const char *filename){
    FILE *fp = fopen(filename, "w");
    if(fp == NULL) return -1;

    struct person *item = NULL;
    for(item = people; item != NULL; item = item->next){
        fprintf(fp, "name: %s, phone: %s", item->name, item->phone);
        fflush(fp); //从缓存刷到磁盘里
    }
    fclose(fp);
}

//用来封装读一行以后解析出name和phone过程
int parser_token(char *buffer, int length, char *name, char *phone){
    // 提取name
    if(buffer ==NULL) return -1;

    int i = 0,j =0,  status = 0; // 默认0, 遇到空格开始提取,变成1
    for(i = 0; buffer[i]!= ','; i++){
        if(buffer[i] ==' ') status =1;
        else if(status ==1) name[j++] = buffer[i];
    }

    // 提取phone
    status = 0, j =0;
    for(; i< length; i++){
        if(buffer[i] == ' ') status =1;
        else if(status == 1) phone[j++]= buffer[i];
    }

    INFO("file token: %s --> %s\n", name, phone);
    return 0;
}

//count要改,引用传递
int load_file(struct person **ppeople, int* count, const char *filename){
    FILE *fp= fopen(filename, "r");
    if(fp == NULL) return -1;

    while(!feof(fp)){
        char buffer[BUFFER_LENGTH] = {0};
        fgets(buffer, BUFFER_LENGTH, fp); //读一行 以后解析

        char name[NAME_LENGTH] = {0};
        char phone[PHONE_LENGTH] ={0};

        //失败了就跳了
        if(0!= parser_token(buffer,strlen(buffer),name,phone) continue;


        // 插入,借助pereson_insert函数
        struct person *p = (struct person *) malloc(sizeof struct person);
        if(p== NULL) return = -2;

        memcpy(p->name, name, NAME_LENGTH);
        memcpy(p->phone, phone, PHONE_LENGTH);

        person_insert(ppeople, p);
        (*count)++;
    }
    fclose(fp);
    return 0;
}

8 文件保存与加载的业务层实现

业务层entry,“entry” 通常指的是程序的入口点,即程序开始执行的地方。

默认other key的操作default是exit,不建议用goto,因为循环里goto跳来跳去,嵌套很乱,写了也行

int save_entry(struct contacts *cts){
    if(cts == NULL) return -1;

	INFO("Please Input Save Filename :\n");

    char filename[NAME_LENGTH] = {0};
    scanf("%s",filename);

    save_file(cts->people,filename);
}

int load_entry(struct contacts *cts){
    if(cts ==NULL) return -1;

	INFO("Please Input Load Filename :\n");
	char filename[NAME_LENGTH] = {0};
	scanf("%s", filename);
    load_file(&cts->people,&cts->count, filename);
}

main的switch里面最后加上
     default:
                goto exit;
        }
    }
exit:
    free(cts);
    return 0;
}

9 通讯录调试与运行

不知不觉已经写了三百多行,c语言开发知识点很综合了,掌握上一章和这一章差不多了

重点是产品和分层的思想:产品——分层——业务层(用户操作)-接口层(隔离底层数据实现和上层用户操作)- 系统支持层(数据结构实现+文件操作)

分层好处:调试很有用,分层排查错误!!!

我出bug了:

  1. 5保存它不跳提示信息,为啥:调不出来啊啊啊啊:绝了,终于找出了bug,switch里面的case后面竟然直接打了break服了!!!

  2. 6加载只有两行,它出来三行,最后一行是乱码,因为默认文件结尾有结束符EOF

    加上对strlen(buffer)的判断,如果太短,不会解析了,改load_file和parser_token

  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值