Incompatible pointer type during function call - c

I have reduced my code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_data (char *data);
int main (int argc, char *argv[])
{
char data[20] = {0};
strcpy(data, "This is a test.");
change_data(&data);
exit(EXIT_SUCCESS);
}
void change_data (char *data)
{
printf("%s\n", data);
}
I want to be able to change the main variable in the function. I thought that using & means sending the address rather than copying the data. But I get the following error when I compile:
tt.c: In function 'main':
tt.c:13:14: warning: passing argument 1 of 'change_data' from incompatible pointer type [-Wincompatible-pointer-types]
change_data(&data);
^
tt.c:5:6: note: expected 'char *' but argument is of type 'char (*)[20]'
void change_data (char *data);
^~~~~~~~~~~
Can someone show me what I'm doing wrong, because I don't have a clue. Ty.

Remove the &. data has type char[20], so a pointer to it has type char (*)[20]. An array will decay to a pointer type when it needs to do so, so simply passing data will pass it as char*.

Related

Why is there a warning for casting from char** to void**, but not from char* to void*?

I am quite new to C, and have been practicing with pointers. I understand that a void * pointer accepts a pointer of any kind, so this works fine:
void functionWithSingleVoidPointer(void *simplePointer)
{
free(simplePointer);
}
int main()
{
char *simplePointer = malloc(sizeof *simplePointer);
functionWithSingleVoidPointer(simplePointer); //No warnings
return 0;
}
However, I don't understand why this:
void functionWithDoubleVoidPointer(void **doublePointer)
{
free(*doublePointer);
}
int main()
{
char *simplePointer = malloc(sizeof *simplePointer);
char **doublePointer = &simplePointer;
functionWithDoubleVoidPointer(doublePointer);
}
gives me a warning:
warning: passing argument 1 of ‘functionWithDoubleVoidPointer’ from incompatible pointer type [-Wincompatible-pointer-types] ... note: expected ‘void **’ but argument is of type ‘char **’
Why doesn't the casting from char * to void * give any warning, but the casting from char ** to void ** does?
A char* value points to a char object; a void* object can point to any kind of object. The conversion is safe (as long you don't do anything unsafe with the result).
A char** pointer value must point to a pointer object of type char* somewhere in memory. A void** pointer value must point to an object of type void*. Since char* and void* are different types, you can't just assume that you can safely treat an object of one type as if it were an object of the other type. (Most likely they have the same representation, but the language doesn't guarantee that.)
A void** is not a void pointer, that's it.
void** is a pointer to a void pointer, which only accept void pointers.

correct return type for C function?

I am using an array of strings inside my function declared like this
char (*array)[PATH_MAX] = malloc (1000 * sizeof *array);
Allocating 1000 char pointers of size PATH_MAX (1024).
I want the function to return that specific data structure, i.e. return the pointer array. But I can't manage to choose the correct return type.
warning: returning 'char (*)[1024]' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
I get that I can't have int as return type, but char** doesn't work either.
warning: returning 'char (*)[1024]' from a function with incompatible return type 'char **' [-Wincompatible-pointer-types]
I've tried using char (*)[1024] as return type, but it gives me generic C error messages, leading me to believe that I am not using the correct syntax.
error: expected identifier or '(' before ')' token
38 | char (*)[1024] read_dir (char *path) {
| ^
Is there a correct syntax for achieving this or am I just doing it wrong?
You need to define the function as follows:
char (*read_dir(char *path))[PATH_MAX] {
This specifies the return type as a pointer to an array of size PATH_MAX of char *.
Time for typedef
typedef char arr1k_char[1000];
arr1k_char *foo(int n) {
arr1k_char *x = malloc(n * sizeof *x);
return x;
}
https://ideone.com/Cqxa61

Incompatible pointer types (double pointers)

In a function that asks a double pointer like this one:
#include <stdlib.h>
void prueba(void **ap)
{
*ap = NULL;
}
compiled with the following main:
#include <stdlib.h>
#include <stdio.h>
void prueba(void **ap);
int main(void)
{
char *str;
str = (char *)malloc(sizeof(char) * 5);
prueba(&str);
if (str == NULL)
printf("NULL");
return (0);
}
I get this warning with gcc:
main2.c:11:9: warning: incompatible pointer types passing 'char **' to parameter of type 'void **' [-Wincompatible-pointer-types]
prueba(&str);
^~~~
main2.c:4:23: note: passing argument to parameter 'ap' here
void prueba(void **ap);
But if i do the same but with simple pointers, that is give a pointer to char to a function who asks for a void pointer, gcc compiles without warnings, for example, the following compiles right:
function:
#include <stdlib.h>
void prueba(void *ap)
{
ap = NULL;
}
main:
#include <stdlib.h>
#include <stdio.h>
void prueba(void *ap);
int main(void)
{
char *str;
str = (char *)malloc(sizeof(char) * 5);
prueba(str);
if (str == NULL)
printf("NULL");
return (0);
}
So my question is, why it works with simple pointers but it does not work with double pointers (or greater i guess)?
According to the C Standard (6.3.2.3 Pointers)
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
So in the second code snippet a pointer of the type char * is implicitly converted to the type void * though the function does not make sense because it deals with a copy of its argument and therefore does not changes the original pointer.
However the type void ** is not the same as the type void *. So the quote is not applicable for the type void ** and the compiler issues a diagnostic message because there is no implicit conversion from a pointer to any object type to a pointer of the type void **.
A void * can freely be assigned to or from any object pointer freely. This freedom does not extends to void **, as that is a distinct type.
Also, your fixed program won't work as expected, since ap = NULL; only changes the local variable inside of prueba and not the parameter passed in.
Change your original program to accept a char ** instead of a void **.

Explain difference between the use of void pointer

My code needs to pass an array to a void pointer (The struct has (void *) that cannot be modified). The two versions of code below produce the same output but the latter has two warnings. My question is which of the two methods is preferred? Is there a way to typecast to remove the warnings?
This version does not have warnings and produces the output as expected:
#include <stdio.h>
void test(void *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(void *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
Hello, World!
The data values are : 3
The data values are : 7
The data values are : 5
This version below has two warnings but compiles and produces the output expected:
Warning(s):
source_file.c: In function ‘main’:
source_file.c:17:10: warning: passing argument 1 of ‘test’ from incompatible pointer type
test(&test_array, var_1);
^
source_file.c:3:6: note: expected ‘int ’ but argument is of type ‘int ()[3]’
void test(int *var_arr, char var_1);
#include <stdio.h>
void test(int *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(int *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = (void *)var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
The lower version tells you what the problem was in the first one: passing a pointer to the array instead of a pointer to the first element.
Passing a pointer to the array, which has the type int(*)[3]:
test(&test_array, var_1);
Passing a pointer to the first element, which has the type int*:
test(test_array, var_1);
The code happens to work because the two pointers points to the same address, so the pointer to the array appears to work, but the code is still undefined.
Passing a pointer to the first element is correct, as the array test_array, which has the type int[3] decays to type int* when it is passed to the function.
The warnings are shown because the compiler does static analysis on the code and identified a possible cause of bugs.
When using the void pointer the compiler cannot do this static analysis since it does not know what type is used.
If the datatype is known I would always prefer using this type as pointer instead of the void pointer. I would only use the void pointer when it is acceptable that the pointer can point to anything. In the end this is about personal taste and the code guidelines you follow.

Pass a char pointer array to a function in C?

I have the following code:
int main(){
char **array;
char a[5];
int n = 5;
array = malloc(n *sizeof *array);
/*Some code to assign array values*/
test(a, array);
return 0;
}
int test(char s1, char **s2){
if(strcmp(s1, s2[0]) != 0)
return 1;
return 0;
}
I'm trying to pass char and char pointer array to a function, but the above code results in the following errors and warnings:
temp.c: In function ‘main’:
temp.c:6:5: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
temp.c:6:13: warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default]
temp.c:10:5: warning: implicit declaration of function ‘test’ [-Wimplicit-function-declaration]
temp.c: At top level:
temp.c:15:5: error: conflicting types for ‘test’
temp.c:15:1: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
temp.c:10:5: note: previous implicit declaration of ‘test’ was here
temp.c: In function ‘test’:
temp.c:16:5: warning: implicit declaration of function ‘strcmp’ [-Wimplicit-function-declaration]
I'm trying to understand what the problem is.
First of all, you should include the necessary header files. For strcmp you need <string.h>, for malloc <malloc.h>. Also you need to at least declare test before main. If you do this you'll notice the following error:
temp.c: In function ‘test’:
temp.c:20:5: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast [enabled by default]
/usr/include/string.h:143:12: note: expected ‘const char *’ but argument is of type ‘char’
This indicates that test() should have a char * as first argument. All in all your code should look like this:
#include <string.h> /* for strcmp */
#include <malloc.h> /* for malloc */
int test(char*,char**); /* added declaration */
int main(){
char **array;
char a[5];
int n = 5;
array = malloc(sizeof(*array));
array[0] = malloc(n * sizeof(**array));
/*Some code to assign array values*/
test(a, array);
free(*array); /* free the not longer needed memory */
free(array);
return 0;
}
int test(char * s1, char **s2){ /* changed to char* */
if(strcmp(s1, s2[0]) != 0) /* have a look at the comment after the code */
return 1;
return 0;
}
Edit
Please notice that strcmp works with null-terminated byte strings. If neither s1 nor s2 contain a null byte the call in test will result in a segmentation fault:
[1] 14940 segmentation fault (core dumped) ./a.out
Either make sure that both contain a null byte '\0', or use strncmp and change the signature of test:
int test(char * s1, char **s2, unsigned count){
if(strncmp(s1, s2[0], count) != 0)
return 1;
return 0;
}
/* don' forget to change the declaration to
int test(char*,char**,unsigned)
and call it with test(a,array,min(sizeof(a),n))
*/
Also your allocation of memory is wrong. array is a char**. You allocate memory for *array which is itself a char*. You never allocate memory for this specific pointer, you're missing array[0] = malloc(n*sizeof(**array)):
array = malloc(sizeof(*array));
*array = malloc(n * sizeof(**array));
Error 1
temp.c:6:13: warning: incompatible implicit declaration of
built-in function ‘malloc’ [enabled by default]
Did you mean this?
array = malloc(n * sizeof(*array));
Error 2
temp.c:15:5: error: conflicting types for ‘test’
temp.c:15:1: note: an argument type that has a default promotion can’t
match an empty parameter name list declaration
temp.c:10:5: note: previous implicit declaration of ‘test’ was here
You are passing the address of the first element of an array a:
test(a, array);
So the function signature should be:
int test(char* s1, char** s2)
You have several problems. The first is that the prototype is wrong. The data type for a decays to a char pointer when passing to a function, so you need:
int test (char* s1, char** s2) { ... }
However, even when you fix this, the test declaration isn't in scope when you first use it. You should either provide a prototype:
int test (char* s1, char** s2);
before main, or simply move the whole definition (function) to before main.
In addition, don't forget to #include the string.h and stdlib.h headers so that the prototypes for strcmp and malloc are available as well.
When you pass an array of char to your function, the argument decays to a pointer. Change your function arguments to
int test(char* s1, char **s2);
^
^
and your code should at least compile

Resources