0

Latelly i've been trying to parse a json object using cJSON lib. When implementing the code, i use recursive call to parse json objects inside json objects. The json contains a list of settings, and i saving it in an array of the following struct:

typedef struct {
    char name[50];
    char setting_str[50];
    int setting_int;
    double setting_double; 
}config;

And i have the following code doing the parse

esp_err_t _JSON_Parse(const cJSON * const root) {
_num_elementos = cJSON_GetArraySize(root);
static int recursive_call = 0;

if((cfg_json != NULL && recursive_call == 0) || (cfg_json == NULL)){
    if(cfg_json == NULL)
        free(cfg_json);
    cfg_json = NULL;
    cfg_json = (config *)malloc(sizeof(config)*_num_elementos);
}else if (recursive_call == 1){ 
    cfg_json = (config *)realloc(cfg_json, sizeof(config)*(_num_elementos ));
}

static int i = 0;
cJSON *current_element = NULL;
cJSON_ArrayForEach(current_element, root) {
    if (current_element->string) {
        strcpy(cfg_json[i].name, current_element->string);
        ESP_LOGI(CONFIG, "i = %d - [%s]", i, cfg_json[i].name);
    }
    if (cJSON_IsInvalid(current_element)) {
        ESP_LOGI(CONFIG, "Invalid");
        return ESP_FAIL;
    } else if (cJSON_IsFalse(current_element)) {
        ESP_LOGI(CONFIG, "False");
    } else if (cJSON_IsTrue(current_element)) {
        ESP_LOGI(CONFIG, "True");
    } else if (cJSON_IsNull(current_element)) {
        ESP_LOGI(CONFIG, "Null");
    } else if (cJSON_IsNumber(current_element)) {
        cfg_json[i].setting_int = current_element->valueint;
        cfg_json[i].setting_double = current_element->valuedouble;
        ESP_LOGI(CONFIG, "int=%d double=%f", cfg_json[i].setting_int, cfg_json[i].setting_double);
    } else if (cJSON_IsString(current_element)) {
        strcpy(cfg_json[i].setting_str, current_element->valuestring);
        ESP_LOGI(CONFIG, "%s", cfg_json[i].setting_str);
    } else if (cJSON_IsArray(current_element)) {
        _JSON_Parse(current_element);
    } else if (cJSON_IsObject(current_element)) {
        recursive_call = 1;
        i++;
        _JSON_Parse(current_element);
        i--;
    } else if (cJSON_IsRaw(current_element)) {
        ESP_LOGI(CONFIG, "Raw(Not support)");
        return ESP_FAIL;
    }
    i++;
}
recursive_call = 0;
_num_elementos = i;
cJSON_Delete(current_element);
return ESP_OK;
}

if i use a fixed size vector, everythin goes right, but when i switch to dinamically allocated memory i start to print garbage, so i think the problem is probably how i'm using the realloc function. Am I missing something?

Also, the json file goes like this:

{
"version":0,
"config_num_head":2,
"config_mode":"EC",
"config_num_recipe":16,
"config_num_setores":16,
"config_en_webterminal":1,
"config_send_data_interval":60000,
"config_pwm_step" : 0.1,
"config_pwm_cycle" : 0,
"config_max_pwm_cycle" : 100,
"config_aceptable_err" : 0.05,
"config_web_debug_time" : 5, 
"config_flow_sp_step" : 0.01, 
"config_min_setpoint" : 0,
"config_max_setpoint" : 3.0,
"config_EC_analog_param": {
        "zero_value_uS": 0,
        "zero_value_mv": 150,
        "second_point_value_uS": 136,
        "second_point_value_mv": 2245,
        "ec_sensor_span_uS": 1999  
    },
"recipe_01" : {
        "flow_ratio_01":1,
        "flow_ratio_02":2,
        "recipe_index":0,
        "EC_setpoint":0.5
    },
"recipe_02" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":1,
        "EC_setpoint":0.7
    },
"recipe_03" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":2,
        "EC_setpoint":0.7
    },
"recipe_04" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":3,
        "EC_setpoint":0.7
    },
"recipe_05" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":4,
        "EC_setpoint":0.7
    },
"recipe_06" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":5,
        "EC_setpoint":0.7
    },
"recipe_07" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":6,
        "EC_setpoint":0.7
    },
"recipe_08" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":7,
        "EC_setpoint":0.7
    },
"recipe_09" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":8,
        "EC_setpoint":0.7
    },
"recipe_10" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":9,
        "EC_setpoint":0.7
    },
"recipe_11" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":10,
        "EC_setpoint":0.7
    },
"recipe_12" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":11,
        "EC_setpoint":0.7
    },
"recipe_13" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":12,
        "EC_setpoint":0.7
    },
"recipe_14" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":13,
        "EC_setpoint":0.7
    },
"recipe_15" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":14,
        "EC_setpoint":0.7
    },
"recipe_16" : {
        "flow_ratio_01":2,
        "flow_ratio_02":1,
        "recipe_index":15,
        "EC_setpoint":0.7
    }
}

Thanks in advance.

Mgoulart
  • 31
  • 3
  • 2
    You have `if (cfg_json == NULL) free(cfg_json);`. Shouldn't the condition be `if (cfg_json != NULL)`? Not that it really matters, since you can pass a null-pointer to `free` (the `free` function will simply do nothing then). – Some programmer dude Oct 06 '21 at 12:41
  • 2
    NEVER use the original pointer you handed into `realloc` for the assignment of the return value. In case `realloc` returns NULL, your handle to your original memory is gone. – tofro Oct 06 '21 at 12:41
  • 1
    Also, in C you [should not cast the result of `malloc` (or `realloc`)](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – Some programmer dude Oct 06 '21 at 12:42
  • 2
    And, keep in mind that on platforms without virtual memory, `realloc` can easily use twice as much the memory than you think (because it needs to copy stuff around). You shold really test the return value of `realloc` – tofro Oct 06 '21 at 12:44
  • 1
    And using `static` local variable, or global variable, can really mess things up with recursive calls. It's better to pass arguments indicating recursion *depth*. – Some programmer dude Oct 06 '21 at 12:45
  • On a totally unrelated note: Please read more about [identifiers in C](https://en.cppreference.com/w/c/language/identifier), pay close attention to [the reserved identifiers](https://en.cppreference.com/w/c/language/identifier#Reserved_identifiers) section. It should tell you that a name like `_JSON_Parse` is reserved. – Some programmer dude Oct 06 '21 at 20:27

0 Answers0