0

I get a write access violation for the following:

void fun
    (
    char** s,
    //EDIT_START
    bool resize = false
    //EDIT_END
    )
{
    //EDIT_START
    if(resize)
        *s = (char*)calloc(20, 1);
    //EDIT_END
    (*s)[0]='a';
}

int main(void) 
{
    char f1[10];
    char* f2 = (char*)calloc(10, 1);
    fun((char**)&f1);
    fun(&f2);
    return 0;
}

Culprit is

fun((char**)&f1);

Anything I'm missing here?

Cœur
  • 37,241
  • 25
  • 195
  • 267
alexander remus
  • 409
  • 1
  • 4
  • 11

3 Answers3

5

Arrays are not pointers. 2D arrays are not pointer-to-pointers.

There is a rule saying that an array, when used in an expression, "decays" into a pointer to the first element. That is the only relation between arrays and pointers.

The fact that you can use the [] operator on a pointer to give it an array-like behavior does not make it an array.

&f1 gives you the address of the array. The type for that will be a pointer-to-array, an array pointer of type char(*)[10]. That is a distinct pointer type, which is not compatible with char* nor char**. Where you got the idea to use char** from, I don't know. Just forget about using char** together with arrays. See this.

Your code should have been written as:

void fun(char* s)  // or char s[], doesn't matter
{
    s[0]='a';
}

int main(void) 
{
    char f1[10];
    char* f2 = calloc(10, 1);
    fun(f1);
    fun(f2);
    return 0;
}
Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The reason I pass a char** instead of char* is that I need to resize the array in fun(). fun() has another default parameter preventing this, so there is no accidental free() of a local array. Please see the edit. – alexander remus Sep 24 '16 at 12:27
  • 2
    @alexanderremus Named arrays cannot be resized.Only arrays allocated by `malloc` family can be resized. – M.M Sep 24 '16 at 14:18
  • @alexanderremus Again, the presence of `char**` makes no sense and should not be used. – Lundin Sep 26 '16 at 06:15
2

Remove the cast and turn on warnings and the compiler will tell you what's wrong:

a.c: In function 'main':
a.c:13: warning: passing argument 1 of 'fun' from incompatible pointer type
a.c:4: note: expected 'char **' but argument is of type 'char (*)[10]'

The key piece of information is: expected 'char **' but argument is of type 'char (*)[10]'. The function expects a pointer to pointer which is not the same as a pointer to array.

I'm sure you know that arrays decay to pointers when passed to a function. However, pointers to arrays do not decay!

If you have

char arr[10];
char *p;

then p is an lvalue while arr isn't. An lvalue can be on the left side of an assignment:

p = arr;   // OK
arr = p;   // Error: arr is not an lvalue!
Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
-1

Thank you all for your answers and time. I came up with a way to do it and will answer the question myself for self reference.

void f(char** c1, bool resize)
{
    void* v1 = (void*)(*c1);
    cout << "changing memory at "<<v1<<"\n";

    if(resize)
        resize(c1); //defined elsewhere

    (*c1)[0]='a';
    (*c1)[0]='b';
    (*c1)[0]='c';
    (*c1)[0]='\0';
}

int
main
        (
        int argc,
        char *argv[]
        )
{

    char* s2 = (char*)calloc(4, 1);

    char s3[4];
    char* ps3 = s3;

    cout << "passing memory location ["<<(void*)&s2<<"] pointing to ["<<(void*)s2<<"]\n";
    f(&s2, true);
    cout << "passing memory location ["<<(void*)&s3<<"] pointing to ["<<(void*)s3<<"]\n";
    f((char**)&s3, false);
    cout << "passing memory location ["<<(void*)&ps3<<"] pointing to ["<<(void*)ps3<<"]\n";
    f((char**)&ps3, false);
}

Output:

passing memory location [006CFA20] pointing to [0076EAF0]
changing memory at 0076EAF0
passing memory location [006CFA18] pointing to [006CFA18]
changing memory at 006CFA80
passing memory location [006CFA1C] pointing to [006CFA18]
changing memory at 006CFA18

Turns out that s3 == &s3. Did not know that. Live and learn I guess.

alexander remus
  • 409
  • 1
  • 4
  • 11