0

With the following code:

char randnum[KEYSIZE + 1];
char temp[3];
char buff[KEYSIZE*2 + 1] = {0};  

for (j = 0; i < KEYSIZE; i++) {
    randnum[i]  = rand()%256;
  
    snprintf(temp, 3, "%.2x", (unsigned char)randnum[i]);
    strcat(buff, &temp);
}

I'm getting incompatible pointer types passing 'char (*)[3]' to parameter of type 'const char * at &temp. This is fixed by using temp instead.

I'm trying to understand the error message. I understand const char * to be a pointer but I'm not sure what char (*)[3] is referring to; specifically the (*). From what I can infer from the fix, I assume this to be a pointer to a pointer (EDIT: pointer). Is this correct?

jjkl
  • 353
  • 6
  • 15

6 Answers6

2

&temp is the address of the whole array. The array is of type char [3], so the type of the address (pointer) is a pointer to that array, which is expressed as char (*) [3], read it as "pointer to an array of 3 chars".

I assume this to be a pointer to a pointer.

No, it's pointer to an array.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
2

&temp is a pointer to the array itself, and it does indeed have the type char (*)[3] (it's a pointer to an array of three char elements).

You should pass a pointer to the first element of the string, i.e. &temp[0], which is what plain temp decay to.

So:

strcat(buff, temp);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

The function strcat is declared the following way

char *strcat(char * restrict s1, const char * restrict s2);

As you can see the both its parameters expect expressions of the type char * or const char *.

In this call of the function

strcat(buff, &temp);

The first argument expression is indeed has the type char * due to the implicit conversion of the array designator buff declared like

char buff[KEYSIZE*2 + 1] = {0};  

to a pointer to its first element.

While the second argument expression has the type char ( * )[3] because you used the address of operator & for the array temp

&temp

You need also to use as the argument the array designator temp. In this case it will be implicitly converted to a pointer to its first element the similar way as with the array buff.

strcat(buff, temp);

Pay attention to that initially the array random should be declared as having the element type unsigned char.

unsigned char randnum[KEYSIZE + 1];

Moreover as the array is not designed to contain a string then it may be declared also like

unsigned char randnum[KEYSIZE];

char randnum[KEYSIZE + 1];

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Arrays decay to pointers.

char temp[3];
  • temp decays to pointer to char (char *) referring the first element of the array
  • &temp decays to pointer to array of 3 characters (char (*)[3]) referring beginning of the array
  • &temp[n] decays to pointer to char (char *) referring the n-th element of the array
0___________
  • 60,014
  • 4
  • 34
  • 74
0

The strcat function is declared as (C17 7.24.3.1):

char *strcat(char * restrict s1,
             const char * restrict s2);

Where the important part for the sake of this discussion is that the function expects char* for both parameters. Though we can note that a char* can be assigned to a const char*, but not the other way around.

If we look at the correct use, strcat(buff, temp);, then both buff and temp in that expression are arrays. But in most cases when an array is used in an expression, it "decays" into a pointer to it's first element, it becomes a char* in this case.

Formally this "decay" is defined as (C17 6.3.2.1):

Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

However when you type &temp, you stumble upon one of the above mentioned exceptions to this "array decay" rule, namely when used with the unary &.

So instead of a char* we end up with "address of a char [3]". Which has to be expressed with a special pointer type used when pointing at arrays, char (*)[3], known as "pointer to array" or "array pointer".

C has pretty strict rules regarding implicit pointer conversions - it will not accept that a char(*)[3] is passed to a parameter expected to be const char* - they are incompatible pointer types - it is not a valid form of assignment.

When you know all of this, the compiler error is actually quite self-explanatory.

Lundin
  • 195,001
  • 40
  • 254
  • 396
-1

char (*)[3] is a pointer to an array of size 3.

temp in its most "natural" form is of type char[3]. However, because temp also points to the first element of the array (which is a char), it is allowed to "decay" into a char*.

When you take &temp, that gives the address of the temp variable, not an address is located in the array. Again, in its most "natural" form, &temp is of type char (*)[3] because it is a pointer to a char[3]. However, note that it is no longer an array type (rather a pointer-to-array), so it is not allowed to decay to char**.

strcat(buff, temp); fixes this because strcat wants a char*, not a char (*)[3].

0x5453
  • 12,753
  • 1
  • 32
  • 61
  • No, `char(*)[3]` and `char**` are fundamentally different and the former cannot decay to the latter. `char**` is a pointer to something that is a `char*`, it might be an array of `char*`, but that's not an array of `char` of length 3. – Aconcagua Oct 26 '21 at 12:56
  • `char *[]`, `char (*)[]` and `char **` are completely different – 0___________ Oct 26 '21 at 12:59
  • For comparison: With `char** pp; char(*pa)[3];` you get `sizeof(*pp)` being equal to the size of a pointer (usually 4 or 8 depending on system) whereas `sizeof(*pa)` equals to 3! – Aconcagua Oct 26 '21 at 13:01
  • You're right, see my edit. @Aconcagua I'm not sure that's a valid example since you are dereferencing `pa` and `pp`, so really you are just comparing `char*` vs `char[3]`, not `char**` vs `char(*)[3]`. – 0x5453 Oct 26 '21 at 13:03
  • Extending on @0___________ 's comment: Note that a `char*[]`, though, can decay to `char**`... – Aconcagua Oct 26 '21 at 13:03
  • @0x5453 Its fully legal to dereference, `sizeof` is not an evaluated context. *Elsewhere* they indeed need to be assigned to valid addresses so that they can be legally dereferenced. – Aconcagua Oct 26 '21 at 13:06
  • Actually `char(*)[3]` *can* refer to an array itself (does not in given case, though)! Consider `char array[7][3]; char(*pointer)[3] = array;`... – Aconcagua Oct 26 '21 at 13:09