user3275095
user3275095

Reputation: 1635

Unable to access values from nested structs

I have been working on some C code which is not mine and in the process learning C too. But the code I am stuck right now is little too much for me. I know this would be a trivial question for experts here. What I have is nested structures and I need to assign values to it. Below is the code:

The Structs:

struct _str{
    char* s; /**< string as char array */
    int len; /**< string length, not including null-termination */
};

typedef struct _str str;
typedef str* db_key_t;

typedef enum {
    DB_INT,        /**< represents an 32 bit integer number      */
    DB_BIGINT,     /**< represents an 64 bit integer number      */
    DB_DOUBLE,     /**< represents a floating point number       */
    DB_STRING,     /**< represents a zero terminated const char* */
    DB_STR,        /**< represents a string of 'str' type        */
    DB_DATETIME,   /**< represents date and time                 */
    DB_BLOB,       /**< represents a large binary object         */
    DB_BITMAP      /**< an one-dimensional array of 32 flags     */
} db_type_t;


typedef struct {
    db_type_t type; /**< Type of the value                              */
    int nul;        /**< Means that the column in database has no value */
    int free;       /**< Means that the value should be freed */
    /** Column value structure that holds the actual data in a union.  */
    union {
        int           int_val;    /**< integer value              */
        long long     bigint_val; /**< big integer value          */
        double        double_val; /**< double value               */
        time_t        time_val;   /**< unix time_t value          */
        const char*   string_val; /**< zero terminated string     */
        str           str_val;    /**< str type string value      */
        str           blob_val;   /**< binary object data         */
        unsigned int  bitmap_val; /**< Bitmap data type           */
    } val;
} db_val_t;
typedef struct db_row {
    db_val_t* values;  /**< Columns in the row */
    int n;             /**< Number of columns in the row */
} db_row_t;
struct db_row;
typedef struct db_res {
    struct {
        db_key_t* names;   /**< Column names                    */
        db_type_t* types;  /**< Column types                    */
        int n;             /**< Number of columns               */
    } col;
    struct db_row* rows;   /**< Rows                            */
    int n;                 /**< Number of rows in current fetch */
    int res_rows;          /**< Number of total rows in query   */
    int last_row;          /**< Last row                        */
} db_res_t;

The Sample code what I am doing to understand:

    #include "Util.h"
    #include "cJSON.h"
    int main(void)
    {
        char *json = "[{\"domain\":\"192.168.254.1\",\"username\":\"user1\",\"expires\":123},{\"domain\":\"192.168.254.2\",\"username\":\"user2\",\"expires\":123}]";


    db_res_t *result = NULL;
    int i=0;

    i = parse_json_to_result(json, &result);
 ** I think accessing like below is fine, as we have pointer structs and val is not pointer so '.' **
    printf("result0: %d",result->rows->values->val.int_val);
    printf("result1: %d",result->rows->values->val.int_val);
     return 1;
    }

    int parse_json_to_result(char *json, db_res_t** result)
    {
        cJSON *root,*record;
        int recourdCount = 0;
        int i=0;
        int value=0;

        root =cJSON_Parse(json);
        recourdCount= cJSON_GetArraySize(root);
        printf("array size: %d\n",recourdCount);

        for(i=0;i<recourdCount;i++)
        {
            record = cJSON_GetArrayItem(root, i);
            value =  cJSON_GetObjectItem(record,"expires")->valueint;
            printf("Fetched value: %d\n",value);
** The below line gives segmentation fault**
            ((*result)->rows->values)->val.int_val = value;
        }
    return 1;
    }

I want to assign values to the struct and doing as below:

    ((*result)->rows->values)->val.int_val = value;

result is pointer to pointer, so first I dereference it then rest are pointer to structures so using '->' and val is just struct so '.'

*result->rows->values->val.int_val = value;

When I wrote as above I was getting compilation errors like row is not struct or union and same for val.

I need little help in understanding how to assign values to this long chain of structs.

Also, one thing I am not able to understand is that in the code on which I am working, the rows are accessed as rows[0], rows[1] but I do not see array declaration in the structs. How can I create the array of rows?

Thanks

Upvotes: 0

Views: 257

Answers (1)

Toby Liu
Toby Liu

Reputation: 1267

Firstly, the commenter is right that you need to initialize your result pointer. If it's just pointing to NULL, of course you are going to segfault.

So let's make our result point to some allocated memory

db_res_t *result = malloc(sizeof(db_res_it));

But we are not done. Notice that result->rows is a pointer to another struct. Even though we malloc'd space for the result struct, it only allocated memory for the POINTER to the db_row struct, NOT for the db_row struct itself. So we need to make sure that the rows pointer is also initialized.

result->rows = malloc(sizeof(db_row_t));

Now the same thing happens again with the values field in db_row.

result->rows->values = malloc(sizeof(db_val_t));

After I added these three lines to your program and commenting out the function calls that aren't provided in your original post, I got your program to run without segfaulting.

As for your other question, about accessing the row as array: In C, this is basically a pointer. Hanno Binder provides a good resource for you to follow; this is a important and fundamnetal concept of C to understand.

Good luck on your learning journey!

Upvotes: 3

Related Questions