gSoap generated client-side structure initialization and use

我的未来我决定 提交于 2019-12-04 20:29:12

Note: This was originally posted to address structures generated by gSoap utilities specifically, but it has general applicability to any nested struct with pointers...

The following describes an ANSI C method for initializing, allocating, assigning and freeing members and pointers within a nested structure construct where the number of fields in the nested section is unknown until run-time.

To explain the shape of structs requiring this treatment, The data schema is comprised of a known number of header fields, each field having one value per row. The last field (row) serves as a delimiter ******** between the header and data sections. The data section contains an unknown number of data records, but each record contains a known (and constant) number of comma delimited fields:

Example data:

The two files shown below are fully commented. Together, they will compile and build with any ANSI C compiler:

InitComplexStructs.h:

    //The struct names typical in gSoap generated code
    //are longer and more complicated.  

    //for example, a typical client soap_call___ns...()
    //function prototype may look like this:
    //SOAP_FMAC5 int SOAP_FMAC6 soap_call___ns1__SendLEDF(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _ns3__ledf_send *ns3__xxmtsvclws, struct _ns3__ledf_recv *ns3__xxmtsvclwsResponse)
    //where areguments 4 & 5 are respectively:
    // arg 4: struct _ns3__ledf_send *ns3__xxmtsvclws
    // arg 5: struct _ns3__ledf_recv *ns3__xxmtsvclwsResponse
    //
    //for this project we will assume arg 4 represents a complex (nested)
    //set of data structures, and for illustration purposes, shorten the
    //name to aaa:

    // struct aaa contains members to accomodate a fixed number of strings
    // as well as a pointer to struct bbb
    struct aaa  {
        char *aaaStr1;
        char *aaaStr2;
        char *aaaStr3;
        char *aaaStr4;
        char *aaaStr5;
        struct bbb *pBbb;
    };

    // struct bbb is used to set array order size
    // (or the number of copies necessary of struct ccc)
    // it contains the array size (index value) member "numRows"
    // and a pointer to a struct, which will work like a pointer
    // to array of struct ccc
    struct bbb  {   
        int numRows;
        struct ccc *row;
    };

    // struct ccc contains members to accomodate a variable number of 
    // sets of strings, number of sets determined by the array row[] 
    // initialized to array size "numRows" in struct bbb
    // (see initComplexStructs.c for how this is done)
    struct ccc  {
        char *cccStr1;
        char *cccStr2;
        char *cccStr3;
        char *cccStr4;
        char *cccStr5;
    };

InitComplexStructs.c

    ///////////////////////////////////////////////////////////
    ///// Using nested data structures ////////////////////////
    ///////////////////////////////////////////////////////////
    //
    //  client-side gSoap generated code will often use nested  
    //  data structures to accomodate complex data types 
    //  used in the 4th and 5th arguments of the client
    //  soap_call__ns...() functions.  
    //
    //  This program illustrates how to work with these
    //  structures by a calling application in the 
    //  following way :
    //
    //    - Initialization of structs
    //    - Allocation of structs and members
    //    - Assignment of values to members
    //    - Freeing of allocated memory
    //
    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////

    #include <ansi_c.h>
    #include "InitComplexStructs.h"

    struct aaa _aaa, *p_aaa;
    struct bbb _bbb, *p_bbb;
    struct ccc _row, *p_row;

    void InitializeStructs(void);
    void AllocateStructs(void);
    void AssignStructs(void);
    void FreeStructs(void);

    char typicalStr[]={"aaaStr 1"};
    size_t sizeStr = sizeof(typicalStr);

    void main (void)
    {
        InitializeStructs();
        AllocateStructs();
        AssignStructs();
        FreeStructs();
    }

    void InitializeStructs(void)
    {
        p_aaa = &_aaa;  
        p_bbb = &_bbb;  
        p_row = &_row;
    }
    void AllocateStructs(void)
    {
        int i;
        //allocate members of p_aaa 
        p_aaa->aaaStr1 = calloc(sizeStr, sizeof(char));
        p_aaa->aaaStr2 = calloc(sizeStr, sizeof(char));
        p_aaa->aaaStr3 = calloc(sizeStr, sizeof(char));
        p_aaa->aaaStr4 = calloc(sizeStr, sizeof(char));
        p_aaa->aaaStr5 = calloc(sizeStr, sizeof(char));
        p_aaa->pBbb    = malloc(    sizeof(*p_bbb));

        //Allocate member of next nested struct - pBbb
        //Note:  The order of array is determined
        //by the value assigned to "numRows"  
        //Note also: the value for numRows could be passed in by argument  
        //since the calling function has this information.
        //Just requires prototype mod from void to int argument.
        p_aaa->pBbb->numRows = 3;
        p_aaa->pBbb->row = calloc(p_aaa->pBbb->numRows,sizeof(*p_row));

        //Allocate the innermost struct ccc accessed through *row
        for(i=0;i<p_aaa->pBbb->numRows;i++)
        {
            p_aaa->pBbb->row[i].cccStr1 = calloc(sizeStr, sizeof(char));
            p_aaa->pBbb->row[i].cccStr2 = calloc(sizeStr, sizeof(char));
            p_aaa->pBbb->row[i].cccStr3 = calloc(sizeStr, sizeof(char));
            p_aaa->pBbb->row[i].cccStr4 = calloc(sizeStr, sizeof(char));
            p_aaa->pBbb->row[i].cccStr5 = calloc(sizeStr, sizeof(char));
        }
    }

    void AssignStructs(void)
    {
        int i;
        strcpy(p_aaa->aaaStr1, "aaaStr 1"); 
        strcpy(p_aaa->aaaStr1, "aaaStr 2"); 
        strcpy(p_aaa->aaaStr1, "aaaStr 3"); 
        strcpy(p_aaa->aaaStr1, "aaaStr 4"); 
        strcpy(p_aaa->aaaStr1, "aaaStr 5");

        for(i=0;i<p_aaa->pBbb->numRows;i++)
        {
            strcpy(p_aaa->pBbb->row[i].cccStr1, "bbbStr 1");
            strcpy(p_aaa->pBbb->row[i].cccStr2, "bbbStr 2");
            strcpy(p_aaa->pBbb->row[i].cccStr3, "bbbStr 3");
            strcpy(p_aaa->pBbb->row[i].cccStr4, "bbbStr 4");
            strcpy(p_aaa->pBbb->row[i].cccStr5, "bbbStr 5");
        }
    }

    void FreeStructs(void)
    {
        int i;
        for(i=0;i<p_aaa->pBbb->numRows;i++)
        {
            free(p_aaa->pBbb->row[i].cccStr1);
            free(p_aaa->pBbb->row[i].cccStr2);
            free(p_aaa->pBbb->row[i].cccStr3);
            free(p_aaa->pBbb->row[i].cccStr4);
            free(p_aaa->pBbb->row[i].cccStr5);
        }
        free(p_aaa->pBbb->row);
        free(p_aaa->pBbb);

        free(p_aaa->aaaStr1);
        free(p_aaa->aaaStr2);
        free(p_aaa->aaaStr3);
        free(p_aaa->aaaStr4);
        free(p_aaa->aaaStr5);
    }

Are you aware that gSOAP allocates memory for your data structures for you so that you don't have to do this? You only have to allocate memory for any data in a Request structure, but never the a reply structure.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!