Thread: how to properly pass address of an address of different data types

  1. #1
    Registered User
    Join Date
    Aug 2020
    Posts
    2

    how to properly pass address of an address of different data types

    In my routine I need "grow" an array by expanding and adding a new item at the end. This add2arr routine handles different type of data, for this reason I code the parameter as void. The code works but compiler shows warning, which makes my assumption about void type questionable.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int add2arr(void **arr, void *item, int sz, int *cnt)
    {
      const int     newsz   = sz * (*cnt + 1);
      const int     offset  = sz * (*cnt);
    
            if(*cnt == 0)
                    *arr = malloc(sz);
            else
                    *arr = realloc(*arr, newsz);
    
            if(*arr == NULL)
                    return(-1);
    
            memcpy(*arr + offset, item, sz);
            *cnt = *cnt + 1;
            return(0);
    }
    
    typedef struct  _STR {
            int     n;
            float   f;
            double  d;
            char    s[20];
    } STR;
    
    int main(int argc, char *argv[])
    {
      const int cnt = (argc == 2) ? atoi(argv[1]) : 10;
      int   n;
      STR   item;
      STR   *str = NULL;
      int   scnt = 0;
    
            for(n = 0; n < cnt; n++)
            {
                    item.n = n; item.f = n * 1.1; item.d = n *10.1;
                    sprintf(item.s, "%i:%.1f:%.2f", item.n, item.f, item.d);
                    if(add2arr(&str, &item, sizeof(item), &scnt) == -1)
                    {
                            printf("Abort\n");
                            return(1);
                    }
            }
            for(n = 0; n < cnt; n++)
            {
                    printf("%6i %8.2f %10.2f %s\n",
                            str[n].n, str[n].f, str[n].d, str[n].s);
            }
            return(0);
    }

    Compile warnings are:
    Code:
    cc -c c.c
    c.c: In function ‘main’:
    c.c:42:14: warning: passing argument 1 of ‘add2arr’ from incompatible pointer type [-Wincompatible-pointer-types]
       42 |   if(add2arr(&str, &item, sizeof(item), &scnt) == -1)
          |              ^~~~
          |              |
          |              STR ** {aka struct _STR **}
    c.c:5:20: note: expected ‘void **’ but argument is of type ‘STR **’ {aka ‘struct _STR **’}
        5 | int add2arr(void **arr, void *item, int sz, int *cnt)
          |             ~~~~~~~^~~
    My compiler is:
    Code:
    cc --version
    cc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
    How should I code patameters in my add2arr so compiler is not complaining?

    Just a note - when I compile under Solaris 11 / GCC 4.5.2 there are no warnings.
    Last edited by laserlight; 08-20-2020 at 07:49 PM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I have removed the additional syntax highlighting from your code. Next time, when you want to post code, post it as plain text within the code tags. The forum will detect the code tags and add its own syntax highlighting, where applicable.

    As for your issue: the compiler warning is basically telling you that a STR ** is not implicitly convertible to a void**. This is true, but it doesn't mean that your approach of using void* cannot work. What I would suggest is changing your function to this:
    Code:
    void *add2arr(void *arr, void *item, size_t sz, size_t *cnt)
    The idea is to copy realloc: return a pointer to the new or expanded region of memory, or a null pointer on error. You can thus change arr to be a void* since it will only be a pointer to the first element of the array, rather than a pointer to a pointer so that you can change the pointer in the caller (since the pointer in the caller is now the caller's responsibility to update).

    I have also changed sz to be a size_t since that is the appropriate type for a size, and similiarly for cnt.

    Another thing: you should be aware that pointer arithmetic on pointers to void is not permitted, although your compiler might allow it as a language extension. Since you are operating on bytes, the solution is to cast the pointer to void to be a pointer to char, then do the pointer arithmetic on the pointer to char.

    A note on efficiency though: calling realloc each time you wish to append to the dynamic array can be expensive. It would be better to keep track of both size (number of elements in use) and capacity (number of elements for which memory has been allocated), then expand the dynamic array only when size is about to exceed capacity. Depending on the characteristics of your array expansion and memory usage, you could expand by a factor (e.g., doubling the array) or by some sufficiently large constant.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Aug 2020
    Posts
    2
    Quote Originally Posted by laserlight View Post
    As for your issue: the compiler warning is basically telling you that a STR ** is not implicitly convertible to a void**. This is true, but it doesn't mean that your approach of using void* cannot work. What I would suggest is changing your function to this:
    Code:
    void *add2arr(void *arr, void *item, size_t sz, size_t *cnt)
    Thanks for your suggestion I will try

    Another thing: you should be aware that pointer arithmetic on pointers to void is not permitted, although your compiler might allow it as a language extension. Since you are operating on bytes, the solution is to cast the pointer to void to be a pointer to char, then do the pointer arithmetic on the pointer to char.
    Yes, I greatly simplified my code just for brevity
    A note on efficiency though: calling realloc each time you wish to append to the dynamic array can be expensive. It would be better to keep track of both size (number of elements in use) and capacity (number of elements for which memory has been allocated), then expand the dynamic array only when size is about to exceed capacity. Depending on the characteristics of your array expansion and memory usage, you could expand by a factor (e.g., doubling the array) or by some sufficiently large constant.
    Absolutely, I allocate chunks of size = sysconf(_SC_PAGESIZE)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. comparing the address of a pointer to an array address for size
    By ridgerunnersjw in forum C Programming
    Replies: 4
    Last Post: 04-17-2020, 06:25 PM
  2. pass by address program
    By vajra11 in forum C Programming
    Replies: 5
    Last Post: 11-29-2019, 11:04 PM
  3. Replies: 1
    Last Post: 08-24-2015, 07:43 AM
  4. Replies: 1
    Last Post: 11-07-2010, 11:39 PM
  5. Block address from word address
    By xddxogm3 in forum Tech Board
    Replies: 0
    Last Post: 04-25-2007, 09:02 PM

Tags for this Thread