Microsoft Developer Network > Forums Home > Visual Studio Express Editions Forums > Visual C++ Express Edition > a function that receives a string and returns an array of strings after some parsing
Ask a questionAsk a question
 

Answera function that receives a string and returns an array of strings after some parsing

  • Wednesday, October 28, 2009 7:55 AMSolange Saad Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Dear All,
    I  wrote a simple function that receives a string and returns an array of strings after some parsing.
    The header of my function:

    int parseXML(char* inputXML, int requestType, char **poutputResponse)

    the function parseXML receive the string inputXML and the requestType, it does some parsing and fill each strings in a different position of    poutputResponse.

    how can i call this function?
    in my code, I called the function as below, but it returned null as values for poutputResponse:

    char* testtest[10];
    ret = parseXML(pXMLresponse, reqType, testtest);
    printf("%s\n", testtest[0]);

    Please I need your help,
    Thank you,
    Solange.

Answers

  • Friday, October 30, 2009 6:49 PMWayneAKing Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Solange Saad:

    Describe what you're trying to do during the parsing. Maybe strstr() or
    sscanf() would be a better match. Show an example of text to be parsed
    and what you want to extract/display from that text.

    As I commented in my first post, parsing XML strings is not a "simple" task
    (unless you're looking for a single value or substring). I concur with Llelan D.
    that using an existing XML parsing library may be the easiest approach.

    The XML C parser and toolkit of Gnome
    http://xmlsoft.org/xml.html

    Recursive XML Parser in C
    http://www.codeguru.com/cpp/data/data-misc/xml/article.php/c4549/

    Parsing XML with Xerces-C C++ API
    http://www.yolinux.com/TUTORIALS/XML-Xerces-C.html

    - Wayne

All Replies

  • Wednesday, October 28, 2009 10:17 AMJijo RajMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Hello Solange,

    One possibility is to declare a double dim array as follows,
       // Declare a double dim array.
       const int MAX_STRINGS    = 10;
       const int MAX_STRING_LEN = 100;
    
       char testtest[MAX_STRINGS][MAX_STRING_LEN];
       ret = parseXML(pXMLresponse, reqType, testtest);
       printf("%s\n", testtest[0]);
    
    


    If possible, avoid raw char** and use std::string array. That will make your life easier.

    Best Regards,
    Jijo.
    http://weseetips.com[^] Visual C++ tips and tricks. Updated daily.
  • Thursday, October 29, 2009 11:35 AMSolange Saad Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thank you Jijo for your response,

    I did as you recommended, but i got the below warning:

    warning C4047: 'function' : 'char ** ' differs in levels of indirection from 'char [10][100]'
    warning C4024: 'parseXML' : different types for formal and actual parameter 3


    And i can't use std::string array, because i'm using C language and not C++.
  • Thursday, October 29, 2009 3:14 PMWayneAKing Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I'm a little puzzled by your problem. You say *you* wrote the function
    but you can't figure out how to call it. Seems implausible. You say it's
    a "simple" function, which apparently parses an XML string - not a
    "simple" task. You say you're using C but give no explanation why you
    can't use C++. If you can't figure out how to use one of your own
    functions, why don't you rework it into something that you *can* use?

    Try this:

    #include <stdlib.h>

    int parseXML(char* inputXML, int requestType, char **poutputResponse);

    #define maxsubstrings 300

    int main(int argc, char* argv[])
    {
        char pXMLresponse[] = "</xml>";
        int x, ret, reqType=1;
        char *testtest[maxsubstrings];
        const unsigned maxstringsize = 500;
        for(x = 0; x<maxsubstrings; ++x)
            {
            testtest[x] = (char*)calloc(maxstringsize, sizeof(char));
            }
        ret = parseXML(pXMLresponse, reqType, testtest);
        return 0;
    }

    - Wayne
  • Thursday, October 29, 2009 4:13 PMLlelan D. Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    <sheesh> Yeah, it's a simple task and lots of contracts require the use of C instead of C++.

    The problem with your question is that it is not possible to tell you why your parseXML function returns a null in your char * *testtest argument without knowing the implementation of that function.

    You are providing an array of character pointers with no array count so the function must assume what that count is. Apparently your function will only return up to 10 strings.

    Your function would have to allocate storage for each string using malloc or calloc, fill that allocated string with characters, and then assign that string to the next index of your testtest argument. Since you only get a null, either you are doing an allocation but it failed and returned a null, or you did not assign the allocated string to the next index of your testtest argument.

    Consider this generic example
    #include <stdlib.h>
    #include <stdio.h>
    
    #define StringArraySize 10
    #define StringBufferLen 9
    
    int getStrings(char * * stringArray)
    {
        int iString;
    
        for (iString = 0; iString < StringArraySize; iString += 1) {
            char *string = (char *)calloc(StringBufferLen, sizeof(char));
            if (string == NULL) return -1;
            sprintf_s(string, StringBufferLen, "String %d", iString);
            stringArray[iString] = string;
        }
    
        return 0;
    }
    
    void main()
    {
        char *strings[StringArraySize];
        int   iString;
    
        getStrings(strings);
    
        for (iString = 0; iString < StringArraySize; iString += 1) {
            puts(strings[iString]);
        }
    }
    
    

    It would, of course, be better if your function required an additional argument with the size of the given char * array so the function knew not to overrun the array, to re-allocate the array to a larger size, or to allocate a new array if the given array pointer was null.

    I hope that helps.
  • Thursday, October 29, 2009 5:42 PMWayneAKing Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Solange Saad: both my example and Llelan D.'s potentially leak memory.

    To eliminate the leak in mine, free() the allocations before leaving
    main. (The allocations will be released automatically by the OS when
    the program terminates - at least for Windows - but it's good practice
    to explicitly free the memory as it avoids developing careless coding
    habits.) Note that successive calls to parseXML may use the same allocations
    without the need to allocate again or free between calls. However, using
    the same allocations may require reinitialization or some other method of
    signaling the end of the substrings if an empty string in the array signals
    the end of the list. If the return value from parseXML gives the number of
    substrings then no reinitializing is needed.

    Llelan D.'s example uses a deprecated design: the function which allocates
    the memory cannot free it, so the onus is passed to the caller to free
    the memory which is allocated within the function each time it is called.
    All calls of getStrings(strings) will leak memory unless the *caller* frees
    the allocations from each invocation.

    Llelan D.'s example may also leak memory if a calloc fails as it does not
    internally free any prior successful allocations before returning.

    Llelan D.'s getStrings() example uses values which are defined external to
    the function and not passed to it as arguments. A better design would pass
    these values as arguments, so the function is "self-contained" and not
    dependent on the existence of external defines or variables/constants.

    Llelan D.:

    Quote>void main()

    <sheesh>

    http://www.research.att.com/~bs/bs_faq2.html#void-main

    http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.3

    http://www.gidnetwork.com/b-66.html

    http://lmgtfy.com/?q=faq+c%2B%2B+void+main

    - Wayne
  • Friday, October 30, 2009 2:47 PMSolange Saad Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Dear All,
    thank you for your time,
    actually, i have a code, that already exists, and it is written in C.
    this application communicate with another application using socket.
    The other application changed it's communication from socket to SOAP XML.
    so i wrote a code, using the wininet library, to send my request and receive the xml soap response.
    the function parseXML, parse the response, and return some useful information.

    int parseXML(char* inputXML, int requestType, char **poutputResponse)
    {
    char* stag = (char *)calloc(MAX_STRINGS, sizeof(char));
    stag = strtok (NULL, "<Price>");
    poutputResponse[0] = stag;
    printf("%s\n", poutputResponse[0]);
    ...
    }


    Note, that for the case of price, one value will be returned, but if the search is for the available services, it will be a list.
    Dear LIelan, my code, is like your code, but the value of the returned is zero.
    Note: the value inside the function parseXML is not value (300$ for example)
  • Friday, October 30, 2009 6:20 PMWayneAKing Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    What are you doing here?

    Quote>stag = strtok (NULL, "<Price>");

    The first argument is supposed to be a pointer to the string to be parsed
    on the first call to strtok. Only subsequent calls to continue parsing the
    same string should use NULL as the first argument.

    Also, when and where do you free the memory allocated by calloc?

    - Wayne
  • Friday, October 30, 2009 6:20 PMLlelan D. Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    You have misunderstood the operation of the strtok function. The first argument should be the string from which you wish to extract the token, and the second is a string of single-character delimiters that separate the tokens. The function modifies the input string, inserting a null after each token and returning a pointer to the start of that token. You are getting a null return because strtok has no input string to search.

    A functioning example of what you wrote would be:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    int parseXML(char* inputXML, int requestType, char **poutputResponse)
    {
        char * stag = strtok(inputXML, "<Price>");
        poutputResponse[0] = stag;
        printf("%s\n", poutputResponse[0]);
    
        return 0;
    }
    
    void main()
    {
        char strXMLInput[] = "<Price>$300</Price>";
        char * testtest[10];
        int ret = parseXML(strXMLInput, 0, testtest);
        printf("%s\n", testtest[0]);
    }
    
    Output:
    $300
    $300
    

    You must supply the input string to strtok instead of NULL , and you do not need to allocate a string since the string pointer returned by strtok points to a character in the input string that has been modified by strtok . Also note that strtok is deprecated as unsecure and you should be using the secure version strtok_s .

    However, this example is misleading in that the second argument to strtok is actually a list of single-character delimiters and not a single delimiting string.. If the text in the Price element included any of those delimiter characters (say "$P300"), strtok would only return a token up to that delimiter character (only "$", up to the 'P').

    XML can not be parsed by simple delimiter characters. It would probably be better if you used an existing XML parsing library instead of trying to reinvent the XML wheel.

    I hope that helps.
    • Edited byLlelan D. Friday, October 30, 2009 6:22 PMDeleted strange HTML <BR>s in code example
    • Edited byLlelan D. Friday, October 30, 2009 6:23 PMSame
    •  
  • Friday, October 30, 2009 6:49 PMWayneAKing Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Solange Saad:

    Describe what you're trying to do during the parsing. Maybe strstr() or
    sscanf() would be a better match. Show an example of text to be parsed
    and what you want to extract/display from that text.

    As I commented in my first post, parsing XML strings is not a "simple" task
    (unless you're looking for a single value or substring). I concur with Llelan D.
    that using an existing XML parsing library may be the easiest approach.

    The XML C parser and toolkit of Gnome
    http://xmlsoft.org/xml.html

    Recursive XML Parser in C
    http://www.codeguru.com/cpp/data/data-misc/xml/article.php/c4549/

    Parsing XML with Xerces-C C++ API
    http://www.yolinux.com/TUTORIALS/XML-Xerces-C.html

    - Wayne