JSON格式,C语言自己实现,以及直接调用库函数(一)
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。以下为你提供不同场景下常见的 JSON 格式示例。
1. 简单对象
JSON 对象是由键值对组成,用花括号 {} 包裹,键和值之间用冒号 : 分隔,多个键值对之间用逗号 , 分隔。
{"name": "John Doe","age": 30,"isStudent": false,"hometown": null
}
2. 嵌套对象
JSON 对象可以嵌套,即一个对象的键对应的值可以是另一个对象。
json
{"person": {"name": "Alice","age": 25,"contact": {"email": "alice@example.com","phone": "123-456-7890"}}
}
3. 数组
JSON 数组是由值组成的有序列表,用方括号 [] 包裹,值之间用逗号 , 分隔。数组中的值可以是不同的数据类型,也可以是对象或数组。
["apple","banana","cherry"
]
4. 对象数组
数组中的元素可以是 JSON 对象。
[{"id": 1,"name": "Product A","price": 19.99},{"id": 2,"name": "Product B","price": 29.99}
]
5. 复杂嵌套结构
结合对象和数组可以形成更复杂的嵌套结构。
{"employees": [{"name": "Bob","department": "Sales","projects": [{"projectName": "Project X","startDate": "2023-01-01"},{"projectName": "Project Y","startDate": "2023-06-01"}]},{"name": "Eve","department": "Marketing","projects": [{"projectName": "Project Z","startDate": "2023-03-01"}]}]
}
6. 包含不同数据类型的对象
{"title": "Sample Document","author": {"firstName": "Jane","lastName": "Smith"},"tags": ["document", "sample"],"views": 1234,"isPublished": true
}
二、
如果没有现成的 JSON 库,要自己实现 JSON 数据的解析和生成,可以按照 JSON 数据的结构特点,通过字符串处理来完成。以下分别介绍如何手动实现 JSON 对象和数组的解析与生成。
1. JSON 解析
解析思路
JSON 对象:JSON 对象由键值对组成,键和值之间用冒号 : 分隔,键值对之间用逗号 , 分隔,整体用花括号 {} 包裹。解析时需要识别键和值,处理嵌套对象和数组。
JSON 数组:JSON 数组由值组成,值之间用逗号 , 分隔,整体用方括号 [] 包裹。解析时需要逐个提取数组元素。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 跳过空白字符
void skip_whitespace(const char **json) {while (**json == ' ' || **json == '\t' || **json == '\n' || **json == '\r') {(*json)++;}
}// 解析字符串
char *parse_string(const char **json) {(*json)++; // 跳过起始的双引号const char *start = *json;while (**json != '\0' && **json != '"') {(*json)++;}size_t len = *json - start;char *str = (char *)malloc(len + 1);if (str == NULL) {return NULL;}memcpy(str, start, len);str[len] = '\0';(*json)++; // 跳过结束的双引号return str;
}// 解析数字
int parse_number(const char **json) {int num = 0;while (**json >= '0' && **json <= '9') {num = num * 10 + (**json - '0');(*json)++;}return num;
}// 解析 JSON 对象
void parse_object(const char **json) {(*json)++; // 跳过起始的花括号skip_whitespace(json);while (**json != '}') {char *key = parse_string(json);skip_whitespace(json);(*json)++; // 跳过冒号skip_whitespace(json);if (**json == '"') {char *value = parse_string(json);printf("Key: %s, Value: %s\n", key, value);free(value);} else if (**json >= '0' && **json <= '9') {int value = parse_number(json);printf("Key: %s, Value: %d\n", key, value);}free(key);skip_whitespace(json);if (**json == ',') {(*json)++;skip_whitespace(json);}}(*json)++; // 跳过结束的花括号
}// 解析 JSON 数组
void parse_array(const char **json) {(*json)++; // 跳过起始的方括号skip_whitespace(json);while (**json != ']') {if (**json == '"') {char *value = parse_string(json);printf("Array value: %s\n", value);free(value);} else if (**json >= '0' && **json <= '9') {int value = parse_number(json);printf("Array value: %d\n", value);}skip_whitespace(json);if (**json == ',') {(*json)++;skip_whitespace(json);}}(*json)++; // 跳过结束的方括号
}// 主解析函数
void parse_json(const char *json) {skip_whitespace(&json);if (*json == '{') {parse_object(&json);} else if (*json == '[') {parse_array(&json);}
}int main() {const char *json_str = "{\"name\": \"John\", \"age\": 30}";parse_json(json_str);return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 生成 JSON 字符串表示的对象
char *generate_json_object(const char *key, const char *value) {size_t key_len = strlen(key);size_t value_len = strlen(value);size_t json_len = 2 + key_len + 2 + 1 + 2 + value_len + 2; // {} "" : ""char *json = (char *)malloc(json_len);if (json == NULL) {return NULL;}sprintf(json, "{\"%s\": \"%s\"}", key, value);return json;
}// 生成 JSON 字符串表示的数组
char *generate_json_array(const char **values, int count) {size_t total_len = 2; // []for (int i = 0; i < count; i++) {total_len += strlen(values[i]) + 2; // ""if (i < count - 1) {total_len++; // ,}}char *json = (char *)malloc(total_len);if (json == NULL) {return NULL;}json[0] = '[';size_t index = 1;for (int i = 0; i < count; i++) {json[index++] = '"';strcpy(json + index, values[i]);index += strlen(values[i]);json[index++] = '"';if (i < count - 1) {json[index++] = ',';}}json[index] = ']';json[index + 1] = '\0';return json;
}int main() {const char *key = "name";const char *value = "John";char *json_obj = generate_json_object(key, value);if (json_obj != NULL) {printf("JSON object: %s\n", json_obj);free(json_obj);}const char *values[] = {"apple", "banana", "cherry"};int count = sizeof(values) / sizeof(values[0]);char *json_arr = generate_json_array(values, count);if (json_arr != NULL) {printf("JSON array: %s\n", json_arr);free(json_arr);}return 0;
}
2
{"employees": [{"name": "Bob","department": "Sales","projects": [{"projectName": "Project X","startDate": "2023-01-01"},{"projectName": "Project Y","startDate": "2023-06-01"}]},{"name": "Eve","department": "Marketing","projects": [{"projectName": "Project Z","startDate": "2023-03-01"}]}]
}
下面是解析该 JSON 数据的 C 语言代码:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"int main() {const char *json_str = "{\"employees\": [{\"name\": \"Bob\", \"department\": \"Sales\", \"projects\": [{\"projectName\": \"Project X\", \"startDate\": \"2023-01-01\"}, {\"projectName\": \"Project Y\", \"startDate\": \"2023-06-01\"}]}, {\"name\": \"Eve\", \"department\": \"Marketing\", \"projects\": [{\"projectName\": \"Project Z\", \"startDate\": \"2023-03-01\"}]}]}";// 解析 JSON 字符串cJSON *root = cJSON_Parse(json_str);if (root == NULL) {const char *error_ptr = cJSON_GetErrorPtr();if (error_ptr != NULL) {fprintf(stderr, "Error before: %s\n", error_ptr);}return 1;}// 获取 employees 数组cJSON *employees = cJSON_GetObjectItem(root, "employees");if (cJSON_IsArray(employees)) {int array_size = cJSON_GetArraySize(employees);for (int i = 0; i < array_size; i++) {cJSON *employee = cJSON_GetArrayItem(employees, i);cJSON *name = cJSON_GetObjectItem(employee, "name");cJSON *department = cJSON_GetObjectItem(employee, "department");if (cJSON_IsString(name) && cJSON_IsString(department)) {printf("Employee Name: %s\n", name->valuestring);printf("Department: %s\n", department->valuestring);}// 获取 projects 数组cJSON *projects = cJSON_GetObjectItem(employee, "projects");if (cJSON_IsArray(projects)) {int project_size = cJSON_GetArraySize(projects);printf("Projects:\n");for (int j = 0; j < project_size; j++) {cJSON *project = cJSON_GetArrayItem(projects, j);cJSON *projectName = cJSON_GetObjectItem(project, "projectName");cJSON *startDate = cJSON_GetObjectItem(project, "startDate");if (cJSON_IsString(projectName) && cJSON_IsString(startDate)) {printf(" - Project Name: %s\n", projectName->valuestring);printf(" Start Date: %s\n", startDate->valuestring);}}}printf("\n");}}// 释放 cJSON 对象占用的内存cJSON_Delete(root);return 0;
}
- 生成 JSON 数据
下面的代码展示了如何使用 cJSON 库生成一个包含不同数据类型的 JSON 对象:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"int main() {// 创建根 JSON 对象cJSON *root = cJSON_CreateObject();if (root == NULL) {fprintf(stderr, "Failed to create JSON object\n");return 1;}// 添加字符串类型的键值对cJSON_AddStringToObject(root, "title", "Sample Document");// 创建嵌套的 author 对象cJSON *author = cJSON_CreateObject();if (author == NULL) {fprintf(stderr, "Failed to create author object\n");cJSON_Delete(root);return 1;}cJSON_AddStringToObject(author, "firstName", "Jane");cJSON_AddStringToObject(author, "lastName", "Smith");cJSON_AddItemToObject(root, "author", author);// 创建 tags 数组cJSON *tags = cJSON_CreateArray();if (tags == NULL) {fprintf(stderr, "Failed to create tags array\n");cJSON_Delete(root);return 1;}cJSON_AddItemToArray(tags, cJSON_CreateString("document"));cJSON_AddItemToArray(tags, cJSON_CreateString("sample"));cJSON_AddItemToObject(root, "tags", tags);// 添加数字类型的键值对cJSON_AddNumberToObject(root, "views", 1234);// 添加布尔类型的键值对cJSON_AddBoolToObject(root, "isPublished", 1);// 将 JSON 对象转换为字符串char *json_str = cJSON_Print(root);if (json_str == NULL) {fprintf(stderr, "Failed to print JSON object\n");cJSON_Delete(root);return 1;}// 打印 JSON 字符串printf("%s\n", json_str);// 释放内存free(json_str);cJSON_Delete(root);return 0;
}
下面为你展示如何使用 C 语言结合 cJSON 库,以文件形式读写和保存 JSON 数据。我们会提供两个示例,一个是从文件中读取 JSON 数据并解析,另一个是将生成的 JSON 数据保存到文件中。
1. 从文件读取并解析 JSON 数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"// 从文件读取内容到字符串
char* read_file(const char* filename) {FILE* file = fopen(filename, "r");if (file == NULL) {perror("Failed to open file");return NULL;}// 获取文件大小fseek(file, 0, SEEK_END);long size = ftell(file);fseek(file, 0, SEEK_SET);// 分配内存来存储文件内容char* buffer = (char*)malloc(size + 1);if (buffer == NULL) {perror("Failed to allocate memory");fclose(file);return NULL;}// 读取文件内容fread(buffer, 1, size, file);buffer[size] = '\0';fclose(file);return buffer;
}int main() {const char* filename = "input.json";char* json_str = read_file(filename);if (json_str == NULL) {return 1;}// 解析 JSON 字符串cJSON* root = cJSON_Parse(json_str);if (root == NULL) {const char* error_ptr = cJSON_GetErrorPtr();if (error_ptr != NULL) {fprintf(stderr, "Error before: %s\n", error_ptr);}free(json_str);return 1;}// 示例:获取并打印 "name" 字段的值cJSON* name = cJSON_GetObjectItem(root, "name");if (cJSON_IsString(name)) {printf("Name: %s\n", name->valuestring);}// 释放资源free(json_str);cJSON_Delete(root);return 0;
}
2. 生成 JSON 数据并保存到文件
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"int main() {// 创建根 JSON 对象cJSON* root = cJSON_CreateObject();if (root == NULL) {fprintf(stderr, "Failed to create JSON object\n");return 1;}// 添加键值对cJSON_AddStringToObject(root, "name", "John Doe");cJSON_AddNumberToObject(root, "age", 30);// 将 JSON 对象转换为字符串char* json_str = cJSON_Print(root);if (json_str == NULL) {fprintf(stderr, "Failed to print JSON object\n");cJSON_Delete(root);return 1;}// 打开文件以写入模式FILE* file = fopen("output.json", "w");if (file == NULL) {perror("Failed to open file");free(json_str);cJSON_Delete(root);return 1;}// 将 JSON 字符串写入文件fputs(json_str, file);// 关闭文件fclose(file);// 释放内存free(json_str);cJSON_Delete(root);return 0;
}
相关文章:

JSON格式,C语言自己实现,以及直接调用库函数(一)
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。以下为你提供不同场景下常见的 JSON 格式示例。 1. 简单对象 JSON 对象是由键值对组成,用花括号 {} 包裹&…...

MinkowskiEngine安装(CUDA11.8+torch2.0.1+RTX4070TI)
1、背景 1)因为项目要用这个库:MinkowskiEngine,Minkowski Engine — MinkowskiEngine 0.5.3 documentation 然后就用了之前安装好 MinkowskiEngine 的torch1.8.1,cuda11.1的环境。 2)自己的代码出现cuda不支持torch用gpu进行矩…...

Spring监听器Listener
目录 1、Spring监听器简介 2、事件(Event) 3、监听器(Listener) 3、事件发布器 4、监听器使用 4.1、自定义事件 4.2、自定义监听器 4.3、发布事件 4.4、测试 4.5、使用注解方式监听 4.6、异步事件处理 5、总结 1、Spri…...
【深度学习在图像配准中的应用与挑战】
图像配准在深度学习中的解决方案越来越多,尤其是通过卷积神经网络(CNN)和生成对抗网络(GAN)等方法,可以显著提升图像配准的效果,尤其是在处理复杂的非刚性变换和大范围的图像差异时。 1. 基于深…...
使用 Docker-compose 部署 MySQL
使用 Docker Compose 部署 MySQL 本文将详细指导如何使用 docker-compose 部署 MySQL,包括基本配置、启动步骤、数据持久化以及一些高级选项。通过容器化部署 MySQL,你可以快速搭建一个隔离的数据库环境,适用于开发、测试或小型生产场景。 关…...

blender笔记2
一、物体贴地 物体->变换->对齐物体 ->对齐弹窗(对齐模式:反方,相对于:场景原点,对齐:z)。 之后可以设置原点->原点--3d游标 二、面上有阴影 在编辑模式下操作过后,物体面有阴影。 数据-&g…...
特殊符号_符号图案_特殊符号大全
特殊符号↑返回顶部 © ℗ ร ಗ ย ☫ ౖ ஃ ⁜ ☊ ☋ ❡ ๑ ి ▧ ◘ ▩ ▣ ◙ ▨ ۞ ۩ ಔ ృ ☎ ☏ ⍝ ⍦ ▤ ▥ ▦ ✠ @ ಓ ↂ ూ ☮ ி ﺴ ✈ ✉ ✁ ✎ ✐ 〄 # ‡ ☪ ⌚ ☢ ▪ ▫ ✆ ✑ ✒ ☌ ❢ ▬ ☍ □ ■ ؟ ‼ ‽ ☭ ✏ ⌨…...

Unity学习part4
1、ui界面的基础使用 ui可以在2d和矩形工具界面下操作,更方便,画布与游戏窗口的比例一般默认相同 如图所示,图片在画布上显示的位置和在游戏窗口上显示的位置是相同的 渲染模式:屏幕空间--覆盖,指画布覆盖在游戏物体渲…...

【AI绘画】大卫• 霍克尼风格——自然的魔法(一丹一世界)
大卫• 霍克尼,很喜欢这个老头,“艺术是一场战斗”。老先生零九年有了iphone,开始用iphone画画,一零年开始用ipad画画,用指头划拉,据说五分钟就能画一幅,每天早上随手画几幅送给身边的朋友。很c…...

MySQL日志undo log、redo log和binlog详解
MySQL 日志:undo log、redo log、binlog 有什么用? 一、前言 在MySQL数据库中,undo log、redo log和binlog这三种日志扮演着至关重要的角色,它们各自承担着不同的功能,共同保障了数据库的正常运行和数据的完整性。了解…...

C++中的指针
一.指针的定义 在C中,指针是一种特殊的变量,它存储另一个变量的内存地址。简单的说,指针是指向另一个数据类型的“指针”或“引用”,我们可以通过指针来间接操作其他变量的值。 指针的基本语法: 数据类型 *指针变量名 …...

拆解微软CEO纳德拉战略蓝图:AI、量子计算、游戏革命如何改写未来规则!
2025年2月19日 知名博主Dwarkesh Patel对话微软CEO萨蒂亚纳德拉 在最新访谈释放重磅信号:AI将掀起工业革命级增长,量子计算突破引爆材料科学革命,游戏引擎进化为世界模拟器。 整个视频梳理出几大核心观点,揭示科技巨头的未来十年…...

智能算法如何优化数字内容体验的个性化推荐效果
内容概要 在数字内容体验的优化过程中,个性化推荐系统的核心价值在于通过数据驱动的技术手段,将用户需求与内容资源进行高效匹配。系统首先基于用户行为轨迹分析,捕捉包括点击频次、停留时长、交互路径等关键指标,形成对用户兴趣…...

MATLAB在数据分析和绘图中的应用:从基础到实践
引言 股票数据分析是金融领域中的重要研究方向,通过对历史价格、成交量等数据的分析,可以帮助投资者更好地理解市场趋势和做出决策。MATLAB作为一种强大的科学计算工具,提供了丰富的数据处理和可视化功能,非常适合用于股票数据的…...

AI客服-接入deepseek大模型到微信(本地部署deepseek集成微信自动收发消息)
1.本地部署 1.1 ollama Ollama软件通过其高度优化的推理引擎和先进的内存管理机制,显著提升了大型语言模型在本地设备上的运行效率。其核心采用了量化技术(Quantization)以降低模型的计算复杂度和存储需求,同时结合张量并行计算&…...
Host文件没有配置ip解析,导致请求接口速度慢
Linux访问第三方接口速度慢 现象 在测试环境,Linux的服务器中,要访问第三方接口;速度有时快,有时慢。 有时候第一次访问比较慢,第二次访问比较快。第三方人员,排查之后,第三方接口没有问题&am…...

excel导入Mysql中时间格式异常
问题描述: 当使用xls/xlsx/csv导入mysql中,如果列是时间类型比如excel表中显示2024/02/20 09:18:00,导入后时间可能就会变成1900-01-01 09:18:00这样。 问题原因: 这是由于excel表中和数据库中的时间类型不匹配导致。 问题解决…...
vue 判断一个属性值,如果是null或者空字符串或者是空格没有值的情况下,赋值为--
在 Vue 中,可以通过多种方式来判断一个属性值是否为 null、空字符串或者仅包含空格,如果满足这些条件则将其赋值为 --。下面分别介绍在模板和计算属性、方法中实现的具体做法。 1. 在模板中直接判断 如果只需要在模板中对属性值进行显示处理,…...

JavaWeb-Tomcat服务器
文章目录 Web服务器存在的意义关于Web服务器软件Tomcat服务器简介安装Tomcat服务器Tomcat服务器源文件解析配置Tomcat的环境变量启动Tomcat服务器一个最简单的webapp(不涉及Java) Web服务器存在的意义 我们之前介绍过Web服务器进行通信的原理, 但是我们当时忘记了一点, 服务器…...
vue语法---样式操作-行内样式
文章目录 直接写死的行内样式v-bind绑定对象(静态样式)对象数组 直接写死的行内样式 <template><div v-bind:style"{color:red}">睡觉</div> </template><script>export default{data() {return {}},methods:{}, mounted(){},} </…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...