Clarification related to memory mgmt of char * inside a function ...

Discussion in 'C Programming' started by Karthik D, Jul 1, 2003.

  1. Karthik D

    Karthik D Guest

    Hello All,
    Basically I would like to take suggestions from programmers
    about implementation of a function which processes some error
    messages.(fyi:this is not a homework problem)
    Let me explain my problem in detail.I have a function
    which closely emulates dlerror() function.
    The function is as below:

    void dlerror(void *handle, char *err, size_t len)
    {
    char *msg;
    /*
    * I am using some API(Win32)which converts the error number
    * to message and stores it in 'msg'.The memory for msg is
    * allocated by the API.So it needs to be freed before exiting
    * this function.
    */
    /*
    * So I try to copy msg into err using memcpy since I need
    * to have the error message in calling function
    */
    if (msg != NULL)
    {
    memcpy(err,msg,len);
    }
    /* freeing the memory allocated for msg */
    return;
    }


    The function is called as follows :

    int main()
    {
    void *hdl;
    char err[256];
    /*
    * ....
    */
    dlerror(hdl, err, sizeof(err));
    if (err != NULL)
    {
    printf("Error message is %s\n", err);
    }
    else
    printf("Error message is NULL\n");
    return 0;
    }

    Is this a correct way?If I am wrong or if there are any better/good ways
    could someone kindly suggest me how can I go about.

    I am finding difficulty in understanding
    - the memory manangement of char pointers/double char pointers
    inside a function and returning their values to another function
    etc..

    I have read C books.But if someone could provide some real-world
    insights on this,it would be helpful for me.

    Thanks & Regards,
    Karthik
     
    Karthik D, Jul 1, 2003
    #1
    1. Advertisements

  2. Karthik D

    signuts Guest

    I'm not quite sure I understand what you're trying to do here. Maybe we
    could get more information on the arguments and what they mean for
    dlerror(..). As far as error detection and error number <=> error messages
    goes, I personally like checking the return values of the function and
    storing the error messages in a char array.

    const char *err_table[] = { "error1", "error2", "error3" };
    and with the help of an enum you can make the code look nice as well.
    /* I would use strcpy here */
    /* i'm not sure how this is freeing the memory. */
     
    signuts, Jul 1, 2003
    #2
    1. Advertisements

  3. Karthik D

    Dan Pop Guest

    ^^^^^^^^^^^^^
    There is no such need, if the function passes the value of msg back to its
    caller.
    This does NOT ensure that err contains a proper null-terminated string.
    Use something like this instead:

    *err = 0;
    strncat(err, msg, len - 1);

    and make sure that len has a positive value.
    This test is downright idiotic! err is an array and the address of its
    first character is guaranteed not to be a null pointer.

    If dlerror() can't figure out an error message, there are two
    possibilities:

    1. Put a string like "failure of unknown origin" in err.

    2. Return a success/failure indication to its caller, instead of being
    a void function.
    Yes, with the objections mentioned above.
    Simply pass back the pointer obtained from the API to the caller and
    document that it is its responsibility to free it, after using it. It's
    more efficient and you don't have to bother with the size of the string
    containing the message. Your sample program becomes:

    char *dlerror(void *handle)
    {
    char *msg;
    /*
    * I am using some API(Win32)which converts the error number
    * to message and stores it in 'msg'.The memory for msg is
    * allocated by the API.
    */
    return msg;
    }

    int main()
    {
    void *hdl;
    char *err;
    /*
    * ....
    */
    err = dlerror(hdl);
    if (err != NULL) {
    printf("Error message is %s\n", err);
    /* freeing the memory allocated for msg */
    }
    else printf("Failure of unknown origin\n");
    return 0;
    }

    Note that everything is simpler and there is no pointless data copying.

    Dan
     
    Dan Pop, Jul 1, 2003
    #3
  4. Karthik D

    Karthik D Guest

    Hello Dan/Signuts,
    Thanks for your answers/suggestions.Basically what I wanted to achieve
    is porting of dlerror to Windows(may be offtopic to clc).Sorry for bringing
    a offtopic to clc.
    Below is the code which achieves that.It has been suggested in
    MSDN to free the lpMsgBuf allocated by FormatMessage.That's the reason
    I copy it to another string and return it as mentioned in my previous
    posting.

    char *dlerror(void *handle)
    {
    LPVOID lpMsgBuf;
    DWORD lastError,fmtMsgError;
    char *errmsg=NULL;
    int len;

    if ( handle == NULL)
    {
    lastError = GetLastError(); //Get the Error value
    if (!FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    lastError,
    /* Default language */
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpMsgBuf,
    0,
    NULL ))
    {
    /* Handle the error. */
    fmtMsgError = GetLastError();
    errmsg=malloc(256);
    sprintf(errmsg, "Format Message failed with errno:%ld",
    fmtMsgError);
    return errmsg;
    }
    len = strlen(lpMsgBuf);
    errmsg=malloc(len+1);
    strncpy(errmsg,lpMsgBuf,len);
    /* Free the buffer */
    LocalFree(lpMsgBuf);
    return errmsg;
    }
    else
    return errmsg;
    }

    If FormatMessage() fails then I am printing a hardcoded error message.
    The function dlerror is called as follows:
    /*
    * ..... some code ........
    */
    so_error = dlerror(so_handle);
    if (so_error != NULL)
    {
    fprintf(stdout,"%s\n", so_error);
    free(so_error);
    so_error = NULL;
    return r_ERR;
    }

    The variable is so_error is declared as:
    char *so_error;

    Is this correct?

    Thanks & Regards,
    Karthik
     
    Karthik D, Jul 2, 2003
    #4
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.