使用cJSON解析JSON字符串失败:无法提取嵌套节点数据
问题排查:cJSON提取嵌套JSON数据失败
问题描述
传入的JSON字符串:
char *json = "{\"cmd\":{\"C\":1,\"X\":1000,\"Zcmd\":\"GET POS\"}}";
提取数据的代码执行后,pDat无数据,cJSON_IsNumber和cJSON_IsString均返回false。原提取代码如下:
int rv = OK; if (!pStr || !pDat) return EINVAL; // parse the JSON data cJSON *json = cJSON_Parse(pStr); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { printf("Error: %s\n", error_ptr); } cJSON_Delete(json); return ENOMSG; } // access the JSON data cJSON *cmd = cJSON_GetObjectItemCaseSensitive(json, "cmd"); if ( cmd ) { cJSON *C = cJSON_GetObjectItemCaseSensitive(json, "C"); if (cJSON_IsNumber(C) && (C->valueint < CMD_NUM)) { pDat->C = C->valueint; } cJSON *X = cJSON_GetObjectItemCaseSensitive(json, "X"); if (cJSON_IsNumber(X) && (X->valueint)) { pDat->X = X->valueint; } cJSON *Zcmd = cJSON_GetObjectItemCaseSensitive(json, "Zcmd"); if (cJSON_IsString(Zcmd) && (Zcmd->valuestring)) { strcpy(pDat->Zcmd,Zcmd->valuestring); } } // delete the JSON object cJSON_Delete(json); return rv; }
错误原因
核心问题是嵌套字段提取路径错误:C、X、Zcmd是cmd对象的子字段,但代码中始终从根json对象获取这些字段,导致返回的C、X、Zcmd均为NULL,后续的类型检查自然全部失败。
修复后的代码
将提取子字段的对象从json改为cmd,同时补充空指针检查与安全优化:
int rv = OK; if (!pStr || !pDat) return EINVAL; // parse the JSON data cJSON *json = cJSON_Parse(pStr); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { printf("Error: %s\n", error_ptr); } // json为NULL时无需调用cJSON_Delete,避免未定义行为 return ENOMSG; } // access the JSON data cJSON *cmd = cJSON_GetObjectItemCaseSensitive(json, "cmd"); if (cmd != NULL && cJSON_IsObject(cmd)) { // 额外校验cmd是对象类型 cJSON *C = cJSON_GetObjectItemCaseSensitive(cmd, "C"); if (C != NULL && cJSON_IsNumber(C) && (C->valueint < CMD_NUM)) { pDat->C = C->valueint; } cJSON *X = cJSON_GetObjectItemCaseSensitive(cmd, "X"); if (X != NULL && cJSON_IsNumber(X)) { pDat->X = X->valueint; } cJSON *Zcmd = cJSON_GetObjectItemCaseSensitive(cmd, "Zcmd"); if (Zcmd != NULL && cJSON_IsString(Zcmd) && Zcmd->valuestring != NULL) { // 用strncpy避免缓冲区溢出,需确保pDat->Zcmd有足够空间 strncpy(pDat->Zcmd, Zcmd->valuestring, sizeof(pDat->Zcmd) - 1); pDat->Zcmd[sizeof(pDat->Zcmd) - 1] = '\0'; // 手动添加字符串终止符 } } // delete the JSON object cJSON_Delete(json); return rv; }
额外注意事项
- 空指针校验:获取每个子节点后必须先检查是否为
NULL,避免触发空指针异常。 - 类型校验:获取
cmd后建议校验其为对象类型,避免非对象类型导致的后续错误。 - 字符串拷贝安全:
strcpy存在缓冲区溢出风险,优先使用strncpy并手动添加终止符。 - 资源释放:
cJSON_Parse返回NULL时,无需调用cJSON_Delete,否则会触发未定义行为。
内容的提问来源于stack exchange,提问作者stdcerr
相关产品推荐
相关产品推荐

