cannot understand this error - c

As I am a beginner in C
When I run the following C code :
#include<stdio.h>
void f(int *p)
{
*p=3;
}
int main()
{
int *p;
f(&p);
return 0;
}
I get these messages after compilation:
1) warning:passing arg 1 of 'f' from incompatible pointer type f(&p)
2) note: expected 'int *' but argument is of type 'int **' void
f(int *p)

Please note:
&p is the memory address of a variable
*p is the actual value of the variable
So what you are doing is:
In main: You are generating a variable pointer p. And you are passing this pointers address to a function f.
f thinks it gets a pointer as parameter but it gets a memory address and obviusly can't handle it.
More information is here
Hope I could help!

You're passing a pointer to a pointer as an argument to a function expecting a pointer to an int. They're two different types and the compiler will complain.
There is another issue where you have the 'pointer' to the int but not the space allocated to store it. There are a couple solutions to this situation.
1)
{
int q; // add a new int, to which p points to. this allocates memory for an int
int *p = &q;
f(p); // don't pass a pointer to a pointer, just the pointer
return 0;
}
2)
{
int p; // have p be the int in the first place, not a pointer
f(&p); // your original call is unchanged and works now
return 0;
}

It's hard to think about this, because there are multiple levels of pointers.
Here's a simpler example. This is what we might call "pass by reference":
#include <stdio.h>
void f(int *ip)
{
*ip = 5;
}
int main(){
{
int i = 7;
printf("%d\n", i);
f(&i);
printf("%d\n", i);
}
Function f accepts a pointer to an int. It modifies that int. In main, we have an int variable i. We take the address of that variable using &, and pass the resulting pointer to function f. In this way, function f is able to modify i in the caller. Note that function f takes a pointer to something, and that what it takes a pointer to is the type of i in the caller -- in other words, pointer to int.
Now let's look at another example. This time, instead of manipulating an int by reference, we're going to manipulate a pointer variable, a char *. (We're going to end up dealing with pointers to pointers.)
void g(char **sp)
{
*sp = malloc(10);
strcpy(*sp, "oranges");
}
int main(){
{
char *s = "apples";
printf("%s\n", s);
g(&s);
printf("%s\n", s);
}
Again, function g accepts an argument by reference. Again, function g is able to modify a variable in its caller. Again, the pointer type accepted by g is a pointer to the type being manipulated. Since the type being manipulated is "pointer to char", function g accepts a pointer to pointer to char, or char **.
But the code you posted is sort of a mixture of the two. Your function f accepts an int pointer, just like mine, and it tries to use that int pointer to modify an int variable in the caller. But then, in your main function, the variable you're trying to modify isn't an int, it's a pointer to int, or int *.
When you call
f(&p);
you're starting with a pointer-to-int, p, and you're taking its address with &, resulting in a pointer-to-pointer-to-int. But then you;re calling function f, which expects a pointer-to-int. That's what the compiler is trying to tell you with the messages
warning: passing arg 1 of 'f' from incompatible pointer type
note: expected 'int *' but argument is of type 'int **'

Related

How can I fix pointer problem in my C code?

#include <stdio.h>
void test(void **arg) {
int foo = 3;
**(int **)arg = foo; // I want to just fix this line!!
}
int main(void) {
int temp = 0;
printf("%d\n", temp);
test((void **)&temp);
printf("%d\n", temp);
return 0;
}
In my code, It has problem 'Segmentation fault', but I don't know how can I fix my code..
I wanna fix just **(int **)arg = foo; line.
Can Anybody Help Me?
In your code, function test(void **temp), variable temp is a pointer to a pointer, aka double pointer. That is to say, it value is an address. But when you call test from main, that value is 0, which means that address is address 0.
You can not assign a value to address 0.
It looks like you are writing to address 0.
Because:
&temp is a pointer to int.
*((int**)&temp) is an int.
**((int**)&temp) use your value from temp as address.
Your function
void test(void **arg);
expects a "pointer to pointer to void", that is the address of a location that contains another address pointing to a generic data.
When you call the function you are not passing what it expects
int temp = 0;
test((void **)&temp);
In fact &temp is an address pointing to an integer. But it expects the address of an address! So, when inside the function you deference it twice (every deferencing with the * operators means "resolving" one address) the second time you are trying to access the address 0.
In order to fix it, just pass to test a pointer to pointer:
int temp = 0;
int *tempAddr = &temp; //tempAddr points to temp
test((void **)&tempAddr); //The type of the address of tempAddr is 'int **'
You were actually asking a different thing: you explicitly asked for a fix of the **((int **) arg) = foo; line.
That's not so easy, as you are currently receiving an invalid pointer to pointer, and there's no way to make it valid just changing that line. In order to sort it out you would need to change test() interface, like shown below:
#include <stdio.h>
void test(void *arg) { // changed 'void **' to 'void *'
int foo = 3;
*(int *)arg = foo; // only one level of dereferencing
}
int main(void) {
int temp = 0;
printf("%d\n", temp);
test((void *)&temp); // cast to 'void *' instead of 'void **'
printf("%d\n", temp);
return 0;
}

warning: dereferencing ‘void *’ pointer [enabled by default] and error: void value not ignored as it ought to be help c

I'm confused about these errors. The str1 is a string that is being passed but I get the a warning at the compare and and error at the if statement
int stringcmp(void* str1, void* str2) {
int a = strlen(str1);
int b = strlen(str2);
int x;
if ( a < b ) {
x = a;
} else {
x = b;
}
int c = 0;
while ( c < x ) {
if (str1[c] < str2[c]) { //errors happen here
return 0;
}
if (str1[c] > str2[c]) {
return 1;
}
c++;
}
if ( a == x ) {
return 0;
}
return 1;
}
Your function receives void* arguments, so in the line you pointed you are dereferencing pointers to void and that is why you get the warnings. I am not sure why you are receiving the value not ignore as it ought to be because that means that you are assigning the value of a function that returns void, and that is not the case of strlen (which is the only one you are calling).
And you should also receive an error in the calls to strlen when passing to it a void* parameter.
So you have to change your function's signature to
int stringcmp(const char* str1, const char* str2);
to suppress the warnings and be able to call strlen on the strings.
Dereferencing void * makes no sense, ever. In C, void means "no type"/"nothing", if you have void *p;, what is *p supposed to be?
In C, void * is used as a generic pointer type, "pointer to anything". To use p above, you must cast it to the type of the object it is pointing at (passed in some other way, unbeknownst to the compiler). E.g.:
int i;
void *p = (void *) &i;
...
int j = *(int *)p;
You know what p points to, the compiler doesn't.
The type void * is often used to pass around opaque data, or to write generic functions (like qsort, it gets an array of unspecified elements and a function that compares them).
That said, as a (misguided) extension GCC allows pointer arithmetic on void *, so that p + 1 is like ((char *)p + 1), it points at the next char position.
Your error arises from the fact that you are attempting to use the array notation str1[c] on a void-pointer. To understand why this is wrong we need to look at what the array notation in C actually means.
Let us assume that we define char* str1. Here we have said that str1 is an address to some place in memory where there is a char.
To get the data that is stored on the address which str1 is referring to we can use *str1.
This is equivalent to saying: "Go to the address that str1 is holding and give me what is stored on that address".
When we use the array notation we can use str1[0], this will be a value fetched from a place in memory where there is an element of the same type that str1 was defined as. It is the same thing as saying *str1 (go to the address that str1 is pointing to and give me the value that is stored there).
An array is just a bunch of data stored in a sequence in memory and strings are just arrays of characters of exactly 1 byte in size stored immediately after one another.
When we say str1[1] we are telling the compiler to move by the size of the type that str1 was defined to be pointing at, in this case 1 byte(char), and then get us whatever is stored at that location. In the case of strings, this should be another char.
Now when we have defined str1 as void*, how would the compiler know how how much it should move in memory to get the next element in the array? Since void has no size it is impossible.
Hopefully you now understand what you need to change in this line to get rid of your errors
int stringcmp(void* str1, void* str2)

Passing a variable into a function and changing its global value

I am trying to pass a variable into a function and change its global value but it does not work. Here is the simplified code:
int main()
{
int *Num = malloc (sizeof (int));
ChangeValue(&Num);
printf("Number is %i\n", Num);
}
int ChangeValue(int *temp)
{
*temp = 10
}
The error message is:
expected 'int *' but argument is of type 'int **'
I tried to change the function to int ChangeValue(int **temp) but received the following error:
warning: assignment makes pointer from integer without a cast.
Any suggestions?
int *Num means Num is of type int *. Since it's already an integer pointer, there's no need to take its address again when you pass it to your function that takes an int *.
ChangeValue(Num);
OTOH, since it is a pointer you will have to dereference it to use it as an integer, like with printf.
printf("Number is %i\n", *Num);
Variable Num is a pointer to an int (int*). Function ChangeValue(int*) takes a pointer to an int (int*). However, you are passing a pointer to Num (int**) to it.
Short answer: remove & before Num in ChangeValue(&Num);
Long answer: You seem to have a problem understanding how pointers work, you might want to read more about this before going further.

Void** as parameter requires cast

I have a function in C that needs to receive a pointer to an array (with an unspecified type).
To do so, I use void**, as I would use void* to receive an array of unspecified elements.
There's a problem unfortunately: the compiler gives a warning (passing argument 1 of 'f' from incompatible pointer type). If I ignore the warning, and try to execute the program, everything works as expected.
The only way to get rid of the warning is to cast whatever I try to pass to the function to void**.
Why does C behaves like that? And is there a better way to solve the warning?
PS: I need to compile using GCC with the flags -std=gnu89 -pedantic -Wall
Example
int f(void** param){ return 1; }
int main(){
int *arr = malloc(sizeof(int) * 20);
int i;
for(i=0; i < 20; i++) arr[i] = i;
f(&arr);
}
The pointer to anything type is void*, and the compiler will not complain about conversions to that type. But void** is not a pointer to anything, it's a pointer to an array of pointers to anything, which is quite different from a pointer to an array of pointers to integers, so the compiler complains.
So, to solve the warning, yes you would need to cast explicitly.
Although void * is the "generic pointer" in C, void ** isn't a "generic pointer to pointer". Instead, it's nothing more than the "specific pointer to void *, the generic pointer".
In your case, a int ** is converted implicitly to a void **, which is not generic. Since a void ** is not guaranteed to be able to hold all pointer variables (thus incompatible to a int **), the compiler raises a warning.
Here is the warning generated by clang:
main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of
type 'void **' [-Wincompatible-pointer-types]
f(&arr);
^~~~
main.c:1:14: note: passing argument to parameter 'param' here
int f(void** param){ return 1; }
To eliminate this warning, you can have int f(void* param);, and cast param to int ** inside the function. There will be no warning because a void * can be used to store any pointer (Quoted from N1570):
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.
It seems that you want to modify the address of the data (not the value) inside the function, you can't do that directly with a void * because you can't use arithmetic with void *, but you can pass the size of the first element and a chunk of bytes (char *), suppose you want to change the address of arr to arr + 1 (the second element of the array) inside the function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f(void *ptr, size_t size)
{
// char *p = *ptr; Wrong, you can't dereference a void * without a cast
char *p = *(char **)ptr; /* pointer to address of ptr */
memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */
}
int main(void)
{
int *arr = malloc(sizeof(int) * 20);
int i;
for (i = 0; i < 20; i++) arr[i] = i;
f(&arr, sizeof arr[0]);
printf("%d\n", arr[0]);
return 0;
}
Output:
1

what this (int**)&p; mean in the statement?

This code is practice code for pointers. But I am not understanding the (int**)&p; means in this code.
void fun(void *p);
int i;
int main()
{
void *vptr;
vptr = &i;
fun(vptr);
return 0;
}
void fun(void *p)
{
int **q;
q = (int**)&p;
printf("%d\n", **q);
}
Please elaborate how it is evaluated.
It's a type cast, that interprets the value of &p, which has type void **, as instead having type int ** which is the type of the variable the value is stored in.
The cast is necessary, since void ** is not the same as void * and does not automatically convert to/from other (data) pointer types. This can be confusing.
&p being of type void**, is being casted to type of int** which is to be assigned to q.
SIDE-NOTE : "Any pointer can be assigned to a pointer to void. It can then be cast back to its original
pointer type. When this happens the value will be equal to the original pointer value."
Be careful when using pointers to void. If you cast an arbitrary
pointer to a pointer to void, there is nothing preventing you from
casting it to a different pointer type.

Resources