C语言如何接收JSON格式数据:从入门到实践
在当今的软件开发中,JSON(JavaScript Object Notation)已成为轻量级数据交换的主流格式,因其易读、易解析的特性,广泛应用于Web API、配置文件、数据存储等场景,C语言作为一门底层高效的语言,本身并没有内置JSON解析的支持,开发者需要借助第三方库来实现JSON数据的接收与解析,本文将详细介绍C语言接收JSON格式数据的完整流程,包括常用库的选择、环境搭建、数据解析及错误处理,帮助开发者快速这一技能。
选择合适的JSON解析库
C语言生态中有多个成熟的JSON解析库,各有特点,开发者可根据需求选择:
cJSON
- 特点:轻量级、单文件实现(仅
cJSON.h和cJSON.c)、API简单易用,适合嵌入式系统或对依赖敏感的项目。 - 支持功能:JSON解析/生成、支持嵌套结构、动态内存管理。
- GitHub:https://github.com/DaveGamble/cJSON
Jansson
- 特点:功能丰富、类型安全、支持UTF-8,适合需要复杂JSON操作的场景。
- 依赖:需C标准库(
<stdio.h>、<stdlib.h>等),无外部依赖。 - 官网:https://jansson.readthedocs.io/
yajl
- 特点:流式解析(SAX风格),内存占用低,适合处理大JSON文件。
- 支持功能:增量解析、回调机制,适合实时数据流场景。
本文以cJSON为例,因其轻量和易用性,是初学者的首选。
环境搭建:以cJSON为例
获取cJSON源码
从GitHub下载最新版cJSON(本文以cJSON v1.7.16为例):
git clone https://github.com/DaveGamble/cJSON.git
或直接下载cJSON.h和cJSON.c文件,放入项目目录。
编译与链接
将cJSON.c和项目源码一起编译,以GCC为例:
gcc your_program.c cJSON.c -o your_program -lm
-lm是链接数学库(cJSON中可能涉及浮点数运算)。
C语言接收JSON数据的完整流程
接收JSON数据通常分为三个步骤:
- 获取JSON字符串(如从网络、文件或用户输入);
- 解析JSON字符串,转换为C语言可操作的数据结构;
- 提取数据,根据业务逻辑处理字段。
步骤1:获取JSON字符串
JSON数据在C语言中本质是char*类型的字符串,常见来源包括:
(1)从文件读取
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* read_json_file(const char* filename) {
FILE* file = fopen(filename, "rb");
if (!file) {
perror("Failed to open file");
return NULL;
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
char* json_str = (char*)malloc(file_size + 1);
if (!json_str) {
perror("Failed to allocate memory");
fclose(file);
return NULL;
}
fread(json_str, 1, file_size, file);
json_str[file_size] = '\0';
fclose(file);
return json_str;
}
(2)从网络接收(以HTTP为例)
需使用网络库(如libcurl),以下为伪代码:
#include <curl/curl.h>
size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t realsize = size * nmemb;
char* buffer = (char*)userp;
strncat(buffer, contents, realsize);
return realsize;
}
char* fetch_json_from_url(const char* url) {
CURL* curl = curl_easy_init();
if (!curl) return NULL;
char buffer[4096] = {0};
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return NULL;
}
return strdup(buffer); // 返回动态分配的字符串
}
(3)硬编码或用户输入
const char* json_str = "{\"name\":\"Alice\",\"age\":25,\"is_student\":true}";
// 或从用户输入读取
// char json_str[1024];
// fgets(json_str, sizeof(json_str), stdin);
步骤2:解析JSON字符串
使用cJSON解析JSON字符串,核心API包括:
cJSON_Parse():解析JSON字符串,返回cJSON*对象;cJSON_GetObjectItem():根据键名获取字段;cJSON_IsString()/cJSON_IsNumber()等:判断字段类型;cJSON_Delete():释放解析后的JSON对象。
示例:解析简单JSON
假设JSON字符串为:
{
"name": "Bob",
"age": 30,
"is_student": false,
"courses": ["Math", "Physics"]
}
解析代码:
#include "cJSON.h"
void parse_simple_json(const char* json_str) {
// 1. 解析JSON字符串
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("Error parsing JSON: %s\n", cJSON_GetErrorPtr());
return;
}
// 2. 获取字段(按键名)
cJSON* name_item = cJSON_GetObjectItem(root, "name");
cJSON* age_item = cJSON_GetObjectItem(root, "age");
cJSON* is_student_item = cJSON_GetObjectItem(root, "is_student");
cJSON* courses_item = cJSON_GetObjectItem(root, "courses");
// 3. 提取数据并判断类型
if (cJSON_IsString(name_item)) {
printf("Name: %s\n", name_item->valuestring);
}
if (cJSON_IsNumber(age_item)) {
printf("Age: %d\n", age_item->valueint);
}
if (cJSON_IsBool(is_student_item)) {
printf("Is student: %s\n", cJSON_IsTrue(is_student_item) ? "true" : "false");
}
if (cJSON_IsArray(courses_item)) {
printf("Courses: ");
cJSON* course = NULL;
cJSON_ArrayForEach(course, courses_item) {
if (cJSON_IsString(course)) {
printf("%s ", course->valuestring);
}
}
printf("\n");
}
// 4. 释放JSON对象(避免内存泄漏)
cJSON_Delete(root);
}
步骤3:处理嵌套JSON
JSON支持嵌套对象(如"address": {"city": "New York"}),解析时需递归处理:
示例JSON:
{
"name": "Charlie",
"address": {
"city": "Shanghai",
"zip_code": "200000"
},
"scores": {"math": 95, "english": 88}
}
解析代码:
void parse_nested_json(const char* json_str) {
cJSON* root = cJSON_Parse(json_str);
if (!root) return;
// 解析嵌套对象address
cJSON* address_item = cJSON_GetObjectItem(root, "address");
if (cJSON_IsObject(address_item)) {
cJSON* city_item = cJSON_GetObjectItem(address_item, "city");
cJSON* zip_item = cJSON_GetObjectItem(address_item, "zip_code");
if (cJSON_IsString(city_item) && cJSON_IsString(zip_item)) {
printf("Address: %s, %s\n", city_item->valuestring, zip_item->valuestring);
}
}
// 解析嵌套对象scores
cJSON* scores_item = cJSON_GetObjectItem(root, "scores");
if (cJSON_IsObject(scores_item)) {
cJSON* math_item = cJSON_GetObjectItem(scores_item, "math");
cJSON* english_item = cJSON_GetObjectItem(scores_item, "english");
if (cJSON_IsNumber(math_item) && cJSON_IsNumber(english_item)) {
printf("Scores: Math=%d, English=%d\n", math_item->valueint, english_item->valueint);
}
}
cJSON_Delete(root);
}
错误处理与内存管理
错误处理
cJSON通过



还没有评论,来说两句吧...