You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:54:55