1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节{trailing padding}。
1
内核链表:
链表:增删改查
单向链表 双向链表。。。
线性数据结构:
数组、链表、堆、栈
数组:连续(物理空间),随机存取,插入删除慢,复杂,会整体偏移
链表:连续(逻辑),无法随机存取,插入和删除方便
堆:malloc() free()
栈:先进后出
队列:先进先出
非线性:
树、图
树:文件系统(开发)
图:路径规划(百度地铁、高德、路由器(路由算法))
插入的代码是重点!!!!
#include <stdio.h>
#include <string.h>
#include "list.h"
struct student
{
int age;
char name[64];
struct list_head list;
};
void main()
{
struct list_head head;
INIT_LIST_HEAD(&head);
struct student stu1;
strcpy(stu1.name, "zhangsan");
stu1.age = 1;
struct student stu2;
strcpy(stu2.name, "lisi");
stu2.age = 2;
struct student stu3;
strcpy(stu3.name, "wangwu");
stu3.age = 3;
list_add(&stu1.list, &head); //插入
list_add(&stu2.list, &head);
list_add(&stu3.list, &head);
struct list_head *pos;
struct student *tmp;
printf("init list\n");
list_for_each(pos, &head) //遍历
{
tmp = list_entry(pos, struct student, list);
//list 为 struct list_head 的名字 struct list_head list
printf("name = %s, age = %d\n", tmp->name, tmp->age);
}
printf("\n");
pos = get_first(&head);
tmp = list_entry(pos, struct student, list);
printf("first is %s\n\n", tmp->name);
pos = get_last(&head);
tmp = list_entry(pos, struct student, list);
printf("last is %s\n\n", tmp->name);
puts("del last");
list_del(pos);
printf("after del:");
list_for_each(pos, &head)
{
tmp = list_entry(pos, struct student, list);
printf("%d ", tmp->age);
}
puts("\n");
}
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "list.h"
typedef int BOOL;
union val
{
BOOL b_val;
int i_val;
float f_val;
};
struct data
{
int key;
int type;
union val val_t;
struct list_head list;
};
void main()
{
struct list_head head;
INIT_LIST_HEAD(&head);
struct data data1;
data1.key = 1;
data1.type = 2;
data1.val_t.b_val = 10;
struct data data2;
data2.key = 2;
data2.type = 1;
data2.val_t.i_val = 0;
struct data data3;
data3.key = 3;
data3.type = 3;
data3.val_t.f_val = 22.5;
list_add(&data1.list, &head);
list_add(&data2.list, &head);
list_add(&data3.list, &head);
struct list_head *pos;
struct data *tmp;
printf("init list\n");
list_for_each(pos, &head)
{
tmp = list_entry(pos, struct data, list);
if(1==tmp->type)
{
printf("%d %d %d\n",tmp->key,tmp->type,tmp->val_t.b_val);
}
else if(2==tmp->type)
{
printf("%d %d %d\n",tmp->key,tmp->type,tmp->val_t.i_val);
}
else if(3==tmp->type)
{
printf("%d %d %.2f\n",tmp->key,tmp->type,tmp->val_t.f_val);
}
}
puts("\n");
}
JSON
是一种数据交换格式
在JSON之前用XML来传递数据,XML很复杂,雅虎的高级架构师道格拉斯发明JSON,是JavaScript的一个子集。
json数据类型
- number:和JavaScript的number完全一致;相当于C中的int类型(数字型)
- boolean:就是JavaScript的true或false;相当于c++中的bool类型
- string:就是JavaScript的string;相当于c++的string类型(字符串)
- null:就是JavaScript的null;相当于C的NULL类型
- array:就是JavaScript的Array表示方式——[];相当于C的数组
- object:就是JavaScript的{ ... }表示方式。相当于C++的类或者C的结构体(对象)
注意:json的数据类型在源码实现中和具体的编程语言有关,比如boolean在C中并没有相应的类型,C相关的实现库可能会用0和1表示。
格式规范
●json以大括号起始和结尾
●内容都是以键值对的形式存在
●所有的键都是字符串
●值的类型不一定,属于JavaScript 的基本数据类型
●每个键值对以,分割
●最后一个键值对不加逗号
{
"name": "小明", //键值 "name"键都是字符串
"age": 14, //number
"gender": true, //boolean
"height": 1.65,
"grade": null, //null
"middle-school": "\"W3C\" Middle School",
"skills": [ //array
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
序列化与反序列化
序列化:生成JSON字符串,多为发送端-----可以理解为利用程序生成Json字符串的过程。
反序列化:解析JSON字符串,拿到数据,多为接收端---可以理解为利用程序将已有的Json字符串解析出我们需要的值的过程。
使用cjson
cjson是个库
{
"ver": "1.0",
"login": {
"user": "zhangsan",
"pwd": "123456"
},
"data": [{
"key": 1,
"type": 2,
"val": "10"
},
{
"key": 2,
"type": 1,
"val": "0"
},
{
"key": 3,
"type": 3,
"val": "22.5"
}
]
}
反序列化:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cJSON.h"
#include "list.h"
typedef int BOOL;
union val
{
BOOL b_val;
int i_val;
float f_val;
};
struct data
{
int key;
int type;
union val val_t;
struct list_head list;
};
int main(void)
{
char buf[800]="";
FILE *fp = fopen("./test.json","r");
if(fp == NULL){
perror("fopen err\n");
return -1;
}
printf("fopen success\n");
fread(buf,800,1,fp);
//1.取出对象json
cJSON *json = cJSON_Parse(buf);
//2.取出json下的ver和login
cJSON *node = NULL;
node = cJSON_GetObjectItem(json,"ver");
if(node == NULL){
printf("ver node == NULL\n");
}
else{
printf("found ver node\n");
}
printf("ver: %s\n",node->valuestring);
cJSON *node2 = NULL;
node2 = cJSON_GetObjectItem(json,"login");
if(node2 == NULL){
printf("login node == NULL\n");
}
else{
printf("found login node\n");
}
//3.从login节点取出user和key子节点
node = cJSON_GetObjectItem(node2,"user");
printf("user: %s\n",node->valuestring);
node = cJSON_GetObjectItem(node2,"pwd");
printf("pwd: %s\n",node->valuestring);
//4.取出json下节点data
node = cJSON_GetObjectItem(json, "data");
//5.链表初始化
struct list_head head;
INIT_LIST_HEAD(&head);
//6.遍历出数组加到链表
cJSON *value = NULL;
cJSON *value1k = NULL;
cJSON *value2t = NULL;
cJSON *value3v = NULL;
int size = cJSON_GetArraySize(node);
int i;
for(i=0;i<size;i++)
{
//取出i个节点
value = cJSON_GetArrayItem(node,i);
//从i个节点取出key和type
value1k = cJSON_GetObjectItem(value,"key");
value2t = cJSON_GetObjectItem(value,"type");
//malloc指针node
struct data *node = (struct data *)malloc(sizeof(struct data));
//用指针赋值
node->key = value1k->valueint;
node->type = value2t->valueint;
value3v = cJSON_GetObjectItem(value,"val");
switch (value1k->valueint){
case 1:
node->val_t.i_val = atoi(value3v->valuestring);
break;
case 2:
node->val_t.b_val = atoi(value3v->valuestring);
break;
case 3:
node->val_t.f_val = atof(value3v->valuestring);
break;
}
//7.加到链表存储
list_add(&node->list,&head);
}
//8.遍历输出
struct list_head *pos;
struct data *tmp;
printf("init list\n");
list_for_each(pos, &head)
{
tmp = list_entry(pos, struct data, list);
if(1==tmp->key)
{
printf("key:%d type:%d val:%d\n",tmp->key,tmp->type,tmp->val_t.i_val);
}
else if(2==tmp->key)
{
printf("key:%d type:%d val:%d\n",tmp->key,tmp->type,tmp->val_t.b_val);
}
else if(3==tmp->key)
{
printf("key:%d type:%d val:%.1f\n",tmp->key,tmp->type,tmp->val_t.f_val);
}
}
return 0;
}
序列化:
// 1.构造根节点root
cJSON * root = cJSON_CreateObject();
// 2.给 root 添加 ver 的子节点,子节点类型是 string
cJSON_AddItemToObject(root, "ver", cJSON_CreateString("1.0"));
// 3.给 root 添加 login 的子节点,子节点类型是 object
cJSON * object1 = cJSON_CreateObject();
cJSON_AddItemToObject(root, "login", object1);
// 4.给 login 节点添加 user 和 key 节点
cJSON_AddItemToObject(object1, "user", cJSON_CreateString("zhangsan"));
cJSON_AddItemToObject(object1, "key", cJSON_CreateString("123456"));
// 5.创建数组节点
cJSON *array = cJSON_CreateArray();
// 6.将数组data加入根节点中
cJSON_AddItemToObject(root, "data", array);
// 7.往data数组节点遍历增加项
list_for_each(p, &head)
{
tmp = list_entry(p, struct data, list);
// 7.1 创建数组data的子节点(此时还没放进数组data中)
cJSON *tmp_son = cJSON_CreateObject();
// 7.2 往数组data字节点中增加key和type
cJSON_AddItemToObject(tmp_son, "key", cJSON_CreateNumber(tmp->key));
cJSON_AddItemToObject(tmp_son, "type", cJSON_CreateNumber(tmp->type));
// 7.3 往数组data字节点中增加val
// 7.3.1 处理val
char buf_tmp[32] = "";
switch (tmp->type)
{
case 1:
sprintf(buf_tmp, "%d", tmp->val.b);
break;
case 2:
sprintf(buf_tmp, "%d", tmp->val.i);
break;
case 3:
sprintf(buf_tmp, "%0.2f", tmp->val.f);
break;
}
// 7.3.2 将处理好的val即string基本类型添加到数组data的字节点中
cJSON_AddItemToObject(tmp_son, "val", cJSON_CreateString(buf_tmp));
// 7.3.3 将字节点tmp_son增加到数组data中
cJSON_AddItemToArray(array, tmp_son);
}
// 8.打印cJSON验证
printf("\n打印Json字符串验证:\n");
printf("%s\n", cJSON_Print(root));