-2

I am attempting to create a function that assigns memory and checks to see if the memory allocation has been accomplished. To allow any memory type to be assigned I have set the function to accept void like so: foo(void ***memory, size_t pointer_type). The intention here is to allow the user to input any pointer into the first section and then the size of the pointer type in the second to allocate correctly, such as:

int foo(void ***memory,size_t pointer_type)
{
    void **temp;
    if((temp=calloc(10,pointer_type))==NULL)
    {
        return(-1);
    }
    for(i=0;i<10;i++)
    {
        if((temp[i]=calloc(10,pointer_type))==NULL)
        {
            // free array as can't be used
            for(i;i>=0;i--)
            {
                free(temp[i]);
                temp[i]=NULL;
            }
            free(temp);
            temp=NULL;
            return(-1);
        }
    }
    *memory=temp;
    return(0);
}

int main()
{

    double **pointer;
    if(foo(&pointer, sizeof(double))==-1)
    {
        return(-1);
    }


    //do stuff then free memory


    return (0);
}

In this example an array of doubles should be created. I came upon this idea when reading other SE posts explaining that this allows any array type to be created, however the compiler gives the following warning :

warning: passing argument 1 of 'foo' from incompatible pointer type note: expected void ***'but argument is of type 'double ***'

This suggests to me that something I have done is incorrect, however when treating the array as a double array after allocation everything works fine so I am lost as to what to do.

EDIT: Ok so the use of the 3-star is to assign the memory from a separate function for a 2D array and was how I was shown to do it, ie if I used pointer[a][b]=10 then it would act like a 2D array. If there are better ways then please do show an example, however I still require the array to be of any type which currently is the pressing matter.

alk
  • 69,737
  • 10
  • 105
  • 255
  • `temp=calloc(10,pointer_type)`...do you smell something? – Sourav Ghosh Feb 22 '17 at 17:25
  • There are also other problems that will not be caught by the compiler, like you not allocating the right size for your arrays. To allocate an array of arrays of `double`, you start with e.g. `calloc(10, sizeof(double*))`. – Some programmer dude Feb 22 '17 at 17:25
  • @Someprogrammerdude Shouldn't this be achieved by pointer_type=sizeof(double) as I am still giving the correct size? – Industrialactivity Feb 22 '17 at 17:27
  • 2
    Being a 3-star C programmer is not a compliment. Something like `void ***` is almost always a signal of bad interface design. – too honest for this site Feb 22 '17 at 17:38
  • @Olaf Is there another way of assigning a 2D dynamic array in a separate function from main without passing in the address of a double pointer? If so please explain – Industrialactivity Feb 22 '17 at 17:42
  • 2
    @Hobojoe: `void ***` is not a 2D (or nD) array, nor can it point to one or in any way used as one! If you need a 2D array,, pass a pointer to a 1D array (a pointer to a 2D array would also work, but is less intuitiv in usage and not ideomatic). And don't get too fancy with `void *`, if you ned a `double` array, use a `double` array! – too honest for this site Feb 22 '17 at 17:45
  • `sizeof(double)` doesn't have to be equal to `sizeof(double*)`. Notice the difference? – Some programmer dude Feb 22 '17 at 17:45
  • 1
    Remember: [3-Star Programmer](http://c2.com/cgi/wiki?ThreeStarProgrammer) is not a compliment. – Jonathan Leffler Feb 22 '17 at 17:46
  • @Olaf From what I have tested if I called `pointer[a][b]= a value` after assigning this way it works like a 2D array. How is this not a 2D array? – Industrialactivity Feb 22 '17 at 17:47
  • @Someprogrammerdude Ah so the size of a double pointer is not the size of a double – Industrialactivity Feb 22 '17 at 17:50
  • 1
    @Hobojoe: A pointer is not an array! Identical syntax does not imply identical semantics; it **looks** like a 2D array, but _works_ very different. There are hundreds of Q&A about this already alone on SO, read them! I have a related answer [here](http://stackoverflow.com/a/35615201/4774918) – too honest for this site Feb 22 '17 at 17:51
  • @Olaf thank you for the link, Ill try and make sense of it – Industrialactivity Feb 22 '17 at 17:56
  • @Olaf , assuming I understood [this](http://www.drdobbs.com/the-new-cwhy-variable-length-arrays/184401444) correctly, the array should be allocated as a 1D array with the same number of "cells" as the 2D array. Then to access it you access as if each dimension is end to end, i.e if the array was a[2][2] it would be allocated as a=malloc(4*sizeof(type), then to access cell "a[1][1]" i should treat it as if the cells are set out as [0,0][0,1][1,0][1,1] and so I can say a[3] and retrieve the correct cell. Is this the correct way of performing this? – Industrialactivity Feb 22 '17 at 18:25
  • @Hobojoe: Not exactly clear, but it seems to be correct. Note that the layout **is** like the mentioned, which is exactly the difference to your pointer-pointer approach. Just keep in mind that a 2D array only has **one** indirection (i.e. `*'`) at most in the declaration (simplified, more complex constructs are often also not good design). – too honest for this site Feb 22 '17 at 18:35
  • @Olaf, brilliant, one more question if I may. Given that the pointer-pointer method works as intended, is the only reason to use the 1D method because it assigns memory so it is all next to each other, allowing pointer arithmetic to work? – Industrialactivity Feb 22 '17 at 18:48
  • 1
    That is no "1D method", but using a 2D array - read how arrays and pointers are related in C, this is vital & basic knowledge. The pointer-to-pointer is a completely different datastructure. Both have their use-case, but if you need a rectangular object of (after allocation) fixed size, you use a 2D array (aka matrix). For example, you only need a single `malloc` and `free`, which makes your `foo` completely unnecessary. – too honest for this site Feb 22 '17 at 18:52
  • Sidenote: `return` is a statement, not a function. Don't parenthesise the expression, that can make finding syntax errors difficult. – too honest for this site Feb 22 '17 at 18:54
  • @Olaf , something I noticed you said: "if you need a rectangular object of (after allocation) fixed size, you use a 2D array", seeing as later in the program I need to change the size of the array, would this mean the pointer-pointer structure is a better option? – Industrialactivity Feb 22 '17 at 19:31
  • @Hobojoe: It depends. Please understand this is not the place (nor do I have to time, to be honest) to tutor. I'd recommend you dig deeper into arrays and pointers before you start messing with them. C is a bad language for trial and error, as it does not prevent you from sooting your feet, arms and - finally - head. – too honest for this site Feb 22 '17 at 23:20

2 Answers2

1

Only a void* is considered a void-pointer, to and from conversion of other pointers is done implicitly (in C).

void** is a pointer to a void-pointer, which is not a void-pointer. The same applies to void***.

So to fix the error you cite change

int foo(void ***memory,size_t pointer_type)

to be

int foo(void *memory, size_t pointer_type)
alk
  • 69,737
  • 10
  • 105
  • 255
-2

The compiler produces the right warning because the type

void ***

is different from the type

double ***

An explicit casting will fix the warning:

if (foo((void ***)&pointer, sizeof(double))==-1)
Marco
  • 783
  • 5
  • 21