0x02-C语言实现通讯录


0x02-C语言实现通讯录

两个思考题

如何分离业务数据 name/phone 和数据结构层的 next/prev?

解决方案: 分层设计

1752149587972-102f18fe-ae07-4d3c-83f4-71c99180f95d.jpeg

如何修复 scanf 缓冲区溢出漏洞?

限制读入字符数, 超出部分污染下一次读入

1752141741886-607eb142-2b8e-4b34-9556-3e28936da97e.jpeg

使用安全的fgets

fgets(buffer, sizeof(buffer), stdin);

缺点: 需要额外处理 buffer 中被读入的换行符

<font style="color:#DF2A3F;">scanf()</font>会默认跳过换行符<font style="color:#DF2A3F;">\n</font>, 空格<font style="color:#DF2A3F;">space</font>等等, 使他们被留在缓冲区

两种 <font style="color:#DF2A3F;">fgets()</font>出现意外的场景

场景原因解决方案
scanf后接 fgetsscanf不读取换行符,残留的 \n会被fgets立即读取while(getchar() != '\n');
输入超出预期长度fgets / scanf只读取部分输入
剩余内容会污染下次读取
检查输入是否完整,若不完整则清空

记录

C 语法不熟悉

1752131628497-1da2a33a-c8f8-466c-9752-9b084906bd8a.jpeg

有几次 malloc/new , 就要 free/delete 几次

函数的实现, 坚持判断每一个参数是否无意义(如指针是否为空)

所有”意义不明的常数”, 使用宏定义声明

内存初始化

1752211109179-efffcf6f-7fe2-4446-87e7-43a7b57442d1.jpeg

清空缓冲区

while(getchar() != '\n'); // 可以直接清空缓冲区

重写接口层 ps_insert 实现按名字的字典序升序排列

int personCmp(Person* a, Person* b) {
  return strcmp(a->name, b->name);
} // 辅助函数, 下面会用到

int ps_insert(Node* ps, AddrBook* contacts) {
  if (ps == NULL) return -1;
  if (contacts == NULL) return -2;

  Node* prev = NULL;
  Node* next = NULL;
  
  Person* new_person = (Person*)ps->data;

  for (Node* current = contacts->head; current != NULL; current = current->next) {
    Person* current_person = (Person*)current->data;
    prev = current;
    if (personCmp(new_person, current_person) < 0) {
      next = current;
      prev = current->prev;
      break;
    }
  }
  
  ps->next = next;
  ps->prev = prev;

  if (prev != NULL) prev->next = ps;
  if (next != NULL) next->prev = ps;
  if (next == contacts->head) contacts->head = ps;

  contacts->len++;
  return 0;
}

问题

  1. 好像不需要二级指针? ==> 已解决: 要修改的是指针, 我传的就是指针的指针了, 而视频里也需要传
  2. main函数最后的 default: 有没有把内存 free干净? // 没有, 但我已经优化了