编译连接过程

image.png
image.png

union 联合体

在数据解析中的应用
typedef union {
uint8_t buffer [PACKET_SIZE];
struct {
uint8_t size;
uint8_t CMD;
uint8_t payload[PAYLOAD_SIZE];
uint8_t crc;
} fields;
} PACKET_t;

  1. // 函数调用方法:packet_builder(packet.buffer,new_data)
  2. // 将新数据存到 buffer 的时候,还需要一些额外的操作
  3. // 比如应该将 size 存放 buffer[0]中
  4. // 将 cmd 存放到 buffer[1] 中,依次类推
  5. void packet_builder(uint8_t *buffer,uint8_t data)
  6. {
  7. static uint8_t received_bytes = 0;
  8. buffer[received_bytes++] = data;
  9. }

  10. void packet_handler(PACKET_t *packet)
  11. {
  12. if (packet->fields.size > TOO_BIG)
  13. {
  14. //错误
  15. }
  16. if (packet->fields.cmd == CMD)
  17. {
  18. //处理对应的数据
  19. }
  20. }

要理解这个数据解析过程,需要用到 union 中的成员存放在同一个地址这个特性,buffer[PACKET_SIZE]中的元素与 fields 中的元素是一一对应的,用一张图来表示就很清楚
image.jpeg
往 buffer 里写了数据,直接从 fileds 里面读出来就可以了。

链表

  1. https://www.cnblogs.com/skywang12345/p/3562146.html
  2. #define offset(type, member) (size_t)(&((type *)0->member))
  3. #define container_of(ptr, type, member) (type *)((char *)ptr - offset(type, member))
  4. struct list_head {
  5. struct list_head *pre;
  6. struct list_head *next;
  7. };
  8. #ifndef _LIST_HEAD_H
  9. #define _LIST_HEAD_H
  10. // 双向链表节点
  11. struct list_head {
  12. struct list_head *next, *prev;
  13. };
  14. // 初始化节点:设置name节点的前继节点和后继节点都是指向name本身。
  15. #define LIST_HEAD_INIT(name) { &(name), &(name) }
  16. // 定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。
  17. #define LIST_HEAD(name) \
  18. struct list_head name = LIST_HEAD_INIT(name)
  19. // 初始化节点:将list节点的前继节点和后继节点都是指向list本身。
  20. static inline void INIT_LIST_HEAD(struct list_head *list)
  21. {
  22. list->next = list;
  23. list->prev = list;
  24. }
  25. // 添加节点:将new插入到prev和next之间。
  26. static inline void __list_add(struct list_head *new,
  27. struct list_head *prev,
  28. struct list_head *next)
  29. {
  30. next->prev = new;
  31. new->next = next;
  32. new->prev = prev;
  33. prev->next = new;
  34. }
  35. // 添加new节点:将new添加到head之后,是new称为head的后继节点。
  36. static inline void list_add(struct list_head *new, struct list_head *head)
  37. {
  38. __list_add(new, head, head->next);
  39. }
  40. // 添加new节点:将new添加到head之前,即将new添加到双链表的末尾。
  41. static inline void list_add_tail(struct list_head *new, struct list_head *head)
  42. {
  43. __list_add(new, head->prev, head);
  44. }
  45. // 从双链表中删除entry节点。
  46. static inline void __list_del(struct list_head * prev, struct list_head * next)
  47. {
  48. next->prev = prev;
  49. prev->next = next;
  50. }
  51. // 从双链表中删除entry节点。
  52. static inline void list_del(struct list_head *entry)
  53. {
  54. __list_del(entry->prev, entry->next);
  55. }
  56. // 从双链表中删除entry节点。
  57. static inline void __list_del_entry(struct list_head *entry)
  58. {
  59. __list_del(entry->prev, entry->next);
  60. }
  61. // 从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。
  62. static inline void list_del_init(struct list_head *entry)
  63. {
  64. __list_del_entry(entry);
  65. INIT_LIST_HEAD(entry);
  66. }
  67. // 用new节点取代old节点
  68. static inline void list_replace(struct list_head *old,
  69. struct list_head *new)
  70. {
  71. new->next = old->next;
  72. new->next->prev = new;
  73. new->prev = old->prev;
  74. new->prev->next = new;
  75. }
  76. // 双链表是否为空
  77. static inline int list_empty(const struct list_head *head)
  78. {
  79. return head->next == head;
  80. }
  81. // 获取"MEMBER成员"在"结构体TYPE"中的位置偏移
  82. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  83. // 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针
  84. #define container_of(ptr, type, member) ({ \
  85. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  86. (type *)( (char *)__mptr - offsetof(type,member) );})
  87. // 遍历双向链表
  88. #define list_for_each(pos, head) \
  89. for (pos = (head)->next; pos != (head); pos = pos->next)
  90. #define list_for_each_safe(pos, n, head) \
  91. for (pos = (head)->next, n = pos->next; pos != (head); \
  92. pos = n, n = pos->next)
  93. #define list_entry(ptr, type, member) \
  94. container_of(ptr, type, member)
  95. #endif
  96. //双向链表测试代码(test.c)
  97. #include <stdio.h>
  98. #include <stdlib.h>
  99. #include <string.h>
  100. #include "list.h"
  101. struct person
  102. {
  103. int age;
  104. char name[20];
  105. struct list_head list;
  106. };
  107. void main(int argc, char* argv[])
  108. {
  109. struct person *pperson;
  110. struct person person_head;
  111. struct list_head *pos, *next;
  112. int i;
  113. // 初始化双链表的表头
  114. INIT_LIST_HEAD(&person_head.list);
  115. // 添加节点
  116. for (i=0; i<5; i++)
  117. {
  118. pperson = (struct person*)malloc(sizeof(struct person));
  119. pperson->age = (i+1)*10;
  120. sprintf(pperson->name, "%d", i+1);
  121. // 将节点链接到链表的末尾
  122. // 如果想把节点链接到链表的表头后面,则使用 list_add
  123. list_add_tail(&(pperson->list), &(person_head.list));
  124. }
  125. // 遍历链表
  126. printf("==== 1st iterator d-link ====\n");
  127. list_for_each(pos, &person_head.list)
  128. {
  129. pperson = list_entry(pos, struct person, list);
  130. printf("name:%-2s, age:%d\n", pperson->name, pperson->age);
  131. }
  132. // 删除节点age为20的节点
  133. printf("==== delete node(age:20) ====\n");
  134. list_for_each_safe(pos, next, &person_head.list)
  135. {
  136. pperson = list_entry(pos, struct person, list);
  137. if(pperson->age == 20)
  138. {
  139. list_del_init(pos);
  140. free(pperson);
  141. }
  142. }
  143. // 再次遍历链表
  144. printf("==== 2nd iterator d-link ====\n");
  145. list_for_each(pos, &person_head.list)
  146. {
  147. pperson = list_entry(pos, struct person, list);
  148. printf("name:%-2s, age:%d\n", pperson->name, pperson->age);
  149. }
  150. // 释放资源
  151. list_for_each_safe(pos, next, &person_head.list)
  152. {
  153. pperson = list_entry(pos, struct person, list);
  154. list_del_init(pos);
  155. free(pperson);
  156. }
  157. }

链表节点定义

首节点:存放第一个有效数据
尾节点:存放最后一个有效数据
头节点:头节点和首节点的数据类型一致,但并不存放有效数据
头节点是首节点前面的那个节点
设置头结点的目的是为了方便对链表操作

头指针:存放头节点的地址

  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #include<stdbool.h>
  4. /**
  5. **链表节点的定义
  6. */
  7. typedef struct Node{
  8. int data; //数据域
  9. struct Node * PNext;//指针域,存放下一个节点的地址
  10. } Node ,*PNode ;
  11. /**
  12. **创建链表
  13. */
  14. PNode create_list()
  15. {
  16. int len,i;
  17. printf("请输入链表的长度:len=\n");
  18. scanf("%d",&len);
  19. PNode PHead=malloc(sizeof(Node));
  20. PHead->PNext=NULL;
  21. PNode PTail=PHead;//PTail是永远指向尾节点的指针
  22. for(i=0;i<len;i++)
  23. {
  24. int val;
  25. printf("请输入第 %d 个元素的值:", i+1);
  26. scanf("%d",&val);
  27. PNode PNew=malloc(sizeof(Node));
  28. PNew->data=val;
  29. PNew->PNext=NULL;
  30. PTail->PNext=PNew;
  31. PTail=PNew;
  32. }
  33. return PHead;
  34. }
  35. /**
  36. **对链表进行遍历
  37. */
  38. void traverse(PNode pHead)
  39. {
  40. PNode p=pHead->PNext;
  41. while(p!=NULL)
  42. {
  43. printf("%d ",p->data);
  44. p=p->PNext;
  45. }
  46. printf("\n");
  47. }
  48. /**
  49. *判断链表是否为空
  50. */
  51. bool isempty(PNode pHead)
  52. {
  53. if(NULL==pHead->PNext)
  54. {
  55. return true;
  56. }else{
  57. return false;
  58. }
  59. }
  60. /**
  61. **获取链表的长度
  62. */
  63. int list_num (PNode pHead)
  64. {
  65. int num=0;
  66. PNode p=pHead->PNext;
  67. while(p!=NULL)
  68. {
  69. num++;
  70. p=p->PNext;
  71. }
  72. return num;
  73. }
  74. /**
  75. *向链表中插入元素
  76. */
  77. bool insert_list(PNode pHead,int val ,int pos){
  78. //需要找到第pos个位置,并且需要判断这个位置pos是否合法
  79. //i是p所指节点的位置,所以从一开始,为什么要pos-
  80. //1呢,因为用的是while 当i=pos-1时跳出循环
  81. int i=0;
  82. PNode p=pHead;
  83. while(NULL!=p&&i<pos-1)
  84. {
  85. i++;
  86. p=p->PNext;
  87. }
  88. //如果插入位置过大,那么P=NULL,
  89. //如果插入的位置是0或者负数,那么i>pos-1
  90. if(i>pos-1||NULL==p)
  91. {
  92. printf("插入位置不合法\n");
  93. return false;
  94. }
  95. PNode PNew=malloc(sizeof(PNode));
  96. PNew->data=val;
  97. PNode temp=p->PNext;
  98. p->PNext=PNew;
  99. PNew->PNext=temp;
  100. return true;
  101. }
  102. /**
  103. **在链表中删除节点
  104. */
  105. delete (PNode PHead,int pos , int * pval)
  106. {
  107. int i=0;
  108. PNode p=PHead;
  109. //我们要删除p后面的节点,所以p不能指向最后一个节点
  110. p->next!=NULL
  111. while(p->PNext!=NULL&&i<pos-1){
  112. p=p->PNext;
  113. i++;
  114. }
  115. if(i>pos-1||p->PNext==NULL)
  116. {
  117. printf("删除位置不合法\n");
  118. return false;
  119. }
  120. PNode temp=p->PNext;
  121. p->PNext=temp->PNext;
  122. free(temp);
  123. }
  124. int main()
  125. {
  126. PNode PHead = create_list();
  127. if(isempty(PHead))
  128. printf("链表为空\n");
  129. printf("链表的长度为:%d\n",list_num(PHead));
  130. traverse(PHead);
  131. //insert_list(PHead,55,1);
  132. int val;
  133. delete(PHead,6,&val);
  134. traverse(PHead);
  135. return 0;
  136. }

===============================================

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. typedef struct name {
  6. char *name;
  7. struct name *pre;
  8. struct name *next;
  9. } t_name, *pt_name;
  10. static pt_name g_pt_name_head = NULL;
  11. int32_t add_name(pt_name pt_new)
  12. {
  13. pt_name pt_cur;
  14. if (!g_pt_name_head){
  15. g_pt_name_head = pt_new;
  16. } else {
  17. pt_cur = g_pt_name_head;
  18. while (pt_cur->next){
  19. pt_cur = pt_cur->next;
  20. }
  21. pt_cur->next = pt_new;
  22. pt_new->pre = pt_cur;
  23. }
  24. return 0;
  25. }
  26. int32_t add_one_name(void)
  27. {
  28. pt_name pt_new;
  29. char *str;
  30. char name[32];
  31. printf("enter the name:");
  32. scanf("%s", name);
  33. str = malloc(strlen(name)+1);
  34. strcpy(str,name);
  35. pt_new = malloc(sizeof(t_name));
  36. pt_new->name = str;
  37. pt_new->pre = NULL;
  38. pt_new->next = NULL;
  39. return add_name(pt_new);
  40. }
  41. pt_name find_name(char *name)
  42. {
  43. pt_name pt_cur;
  44. if (!g_pt_name_head)
  45. return NULL;
  46. else {
  47. pt_cur = g_pt_name_head;
  48. do {
  49. if (strcmp(pt_cur->name, name) == 0){
  50. return pt_cur;
  51. } else {
  52. pt_cur = pt_cur->next;
  53. }
  54. } while(pt_cur);
  55. }
  56. return NULL;
  57. }
  58. int32_t del_name(pt_name pt_del)
  59. {
  60. pt_name pt_cur;
  61. pt_name pt_pre;
  62. pt_name pt_next;
  63. if (g_pt_name_head == pt_del)
  64. g_pt_name_head = pt_del->next;
  65. /* 释放 */
  66. else {
  67. pt_cur = g_pt_name_head->next;
  68. while (pt_cur){
  69. if (pt_cur == pt_del){
  70. /* 从链表中删除 */
  71. pt_pre = pt_cur->pre;
  72. pt_next = pt_cur->next;
  73. pt_pre->next = pt_next;
  74. if (pt_next){
  75. pt_next->pre = pt_pre;
  76. }
  77. } else {
  78. pt_cur = pt_cur->next;
  79. }
  80. }
  81. }
  82. free(pt_del->name);
  83. free(pt_del);
  84. return 0;
  85. }
  86. int32_t del_one_name(void)
  87. {
  88. pt_name pt_find;
  89. char name[32];
  90. printf("enter the name:");
  91. scanf("%s", name);
  92. pt_find = find_name(name);
  93. if(!pt_find) {
  94. printf("No the name\n\n");
  95. return -1;
  96. }
  97. return del_name(pt_find);
  98. }
  99. int32_t list_all_name(void)
  100. {
  101. pt_name pt_cur;
  102. int i = 0;
  103. pt_cur = g_pt_name_head;
  104. while (pt_cur){
  105. i++;
  106. printf("%02d : %s\r\n", i, pt_cur->name);
  107. pt_cur = pt_cur->next;
  108. }
  109. printf("\n\n");
  110. return 0;
  111. }
  112. int main(int argc, char **argv)
  113. {
  114. char ch = ' ';
  115. while (1) {
  116. printf("<l> List all names\r\n");
  117. printf("<a> add one name\r\n");
  118. printf("<d> del one name\r\n");
  119. printf("<x> exit\r\n");
  120. printf("\r\n");
  121. ch = getchar();
  122. switch (ch){
  123. case 'l':
  124. list_all_name();
  125. break;
  126. case 'a':
  127. add_one_name();
  128. break;
  129. case 'd':
  130. del_one_name();
  131. break;
  132. case 'x':
  133. return 0;
  134. }
  135. }
  136. return 0;
  137. }

结构体初始化

image.png

指针

image.png

浮点数比较

image.png
image.png
image.png
image.png

C-串复制

image.png

斐波那契数列

image.png
image.png