De-Referencing void pointer error when infact already cast - c

Situation
Consider the following source code which aims to print two a's, i.e. output should be "aa":
#include <stdio.h>
int main ()
{
char a = 'a';
void* a_pnt = &a;
void* b_pnt = (char*)a_pnt;
printf("%c", *(char*)a_pnt);
printf("%c", *b_pnt);// why is the compiler saying I am dereferencing a void pointer? It was already cast
return 0;
}
Complication
The printing of the first "a" works but the compiler is giving a compile time error on line 10 (second printing of "a") saying:
Invalid use of void expression
and a warning on the same line saying:
Dereferencing 'void *' pointer
Although b_pnt was indeed declared a void pointer, it was cast to a character pointer in its definition on line 7. My only guess as to why its complaining is something to do with the fact that I can only cast when referencing at the same time. My hunch is based off the fact that the first variable works just fine.
Solution
The solution is declare and define a character variable called 'b' and cast to character pointer upfront before printing it:
#include <stdio.h>
int main ()
{
char a = 'a';
void* a_pnt = &a;
void* b_pnt = a_pnt;
char b = *((char*)b_pnt);
printf("%c", *(char*)a_pnt);
printf("%c", b);// why is the compiler saying I am dereferencing a pointer?
return 0;
}
The question still remains: Why did the initial attempt fail?
I am deliberately starting off with void pointer to illustrate the issue. It could indeed have been avoided entirely ofcourse with the correct pointer type.

Just because you performed a cast when assigning to b_pnt doesn't mean that it's type changed. It's type is still void * and dereferencing it is an error.
You can freely assign any non-function pointer type to a void * without a warning. But the compiler doesn't keep track of what kind of pointer was stored there, so it's still a void * that needs to be casted before it can be dereferenced.

Related

why can't we use indirection operator with array name?

In the below code , why can't I dereference the array name ,since when an array is passed as an argument to a function , it becomes pointer to first element of the array , so why can't we dereference it then ?
#include <stdio.h>
int main(void) {
char s[] = "radha";
int a[2] = {0,1};
printf("%s ", *s);
printf("%d", *a);
return 0;
}
​
I am getting segmentation fault for the above code , what's the reason here , when I use a[0] ,it is internally converted as *(a+0) , so what's the issue in simply doing *a or *S ,please clarify .
printf("%s ",*s); expects second argument to be a pointer to string while you are passing char 'r' (dereferencing s gives you first array item as expected).
I have two suggestions of your,
Read the documentation.
The "%s" specifier expects a pointer of char, you are passing a char which is then considered an integer and dereference as if it were a pointer causing UNDEFINED BEHAVIOR.
If you read the documentation, and understand that char[] is converted to char * also that dereferencing a char * poitner will give you a char, then you would understand why this is wrong.
Enable compiler warnings. If you do so, then a warning telling you that you are passing the wrong type would save you a lot of time and let you learn more about how to invoke a given function.
If you ignored the warning, it's even worse. You should never ignore a warning unless you know beforehand that the compiler will complain about something. If the warning was not expected, then it's very likely an error instead.

C pointer difference Char Int [duplicate]

This question already has answers here:
warning: assignment makes integer from pointer without a cast
(5 answers)
Closed 6 years ago.
the code bellow works as it needs to work.
void TstPointer(int *Pointer)
{
*Pointer = 3;
}
int main()
{
int number = 1;
int *ptr = &number;
TstPointer(ptr);
printf("%d\n", number);
}
But when i switch types to char it doesnt work.
void TstPointer(char *Pointer)
{
*Pointer = "Hell1";
}
int main()
{
char *Hello = "Hello";
TstPointer(Hello);
printf("%s\n", Hello);
}
warning: assignment makes integer from pointer without a cast [-Wint-conversion]
*Pointer = "Hell1";
Pass the reference of Hello to your method (&Hello) as you do with int -
int *ptr = &number;
TstPointer(ptr);
While doing *Pointer = "Hell1"; your compiler warned you. You chose to ignore that which possibly invokes the undefined behavior.
In general , to copy to a pointer, use strcpy() but in that case, that will cause problem, as Pointer points to a string literal which you're not allowed to change.
You need to make sure that the memory is writable before trying to write into that memory location. Either use memory allocator function, or create an array and make the pointer point to the start of the array.
In your TstPointer method, when you do *Pointer = "Hell1";, you are generating the warning.
This is because, if Pointer is a char pointer, then *Pointer is a char variable. And you are assigning a string constant to a char variable which is wrong.
To solve this issue, I think you ought to use a double pointer in the function parameter as pass the address (of the pointer) in the main!
EDIT:
You are getting the warning because when you assign a string constant to a variable (char pointer or array, usually), that variable stores the address of the beginning of the string constant. Now, when the lvalue is not char pointer type, but is just a char variable, some implicit conversion takes place to assign (fit) the "address" into a normal char variable, which in turn gives the warning. But, we know char cannot accommodate a memory address, and thus will usually result in a segfault when printed!

Why is setting a derefernce pointer equal to a primitive illegal?

Why does setting the value of a dereferenced pointer raise a Segmentation fault 11? To make what I mean clear look a the follow code:
#include <stdio.h>
int *ptr;
*ptr = 2;
int main(){
printf("%d\n", *ptr);
return 0;
}
I thought that *ptr=2 would set the rvalue that the pointer ptr is point to to 2. Is that not the case? I apologize if for those c expert programmers, this is really easy/obvious.
Are we only allowed to set a dereferenced pointer (i.e. *ptr) to a value if that value had a memory address? i.e. like doing:
int k = 7;
int *ptr = k;
and then:
*ptr = 2;
The problem here is that ptr is not pointing to allocated space. See the following:
#include <stdio.h>
#include <stdlib.h>
int main(void){
// Create a pointer to an integer.
// This pointer will point to some random (likely unallocated) memory address.
// Trying set the value at this memory address will almost certainly cause a segfault.
int *ptr;
// Create a new integer on the heap, and assign its address to ptr.
// Don't forget to call free() on it later!
ptr = malloc(sizeof(*ptr));
// Alternatively, we could create a new integer on the stack, and have
// ptr point to this.
int value;
ptr = &value;
// Set the value of our new integer to 2.
*ptr = 2;
// Print out the value at our now properly set integer.
printf("%d\n", *ptr);
return 0;
}
It's not 'illegal', it's simply implementation defined. In fact, on some platforms (such as DOS), specific memory addresses were necessary, for example to write text to the video buffer which started at 0xB8000, or memory mapped controller I/O on the SNES.
On most current OS's, a feature called ASLR is used, for security reasons, which makes ancient modes of dedicated addresses a thing of the past, in favor of going through driver and kernel layers, which is what makes it 'illegal' for most places you would run it.
The most basic issue here is that you are not assigning ptr to a valid memory address, there are some cases where 0 is a valid memory address but usually not. Since ptr is global variable in your first case, it will be initialized to 0. remyabal asked a great follow-up question and best answer made me realize that this is a redeclaration here:
*ptr = 2;
and you are then setting ptr to have a value of 2 which is except by chance unlikely to point to a valid memory address.
If ptr was a local or automatic variable then it would be uninitialized and it's value would be indeterminate. Using a pointer with an indeterminate value is undefined behavior in both C and C++. It is in most case undefined behavior to use a NULL pointer as well although implementations are allowed to define the behavior.
On most modern system attempting to access memory your process does not own will result in a segmentation fault.
You can assign a valid memory address to ptr in a few ways, for example:
int k = 7;
int *ptr = &k;
^
note the use of of & to take the address of k or you could use malloc to allocate memory dynamically for it.
Your code is invalid, though some C compilers may permit it for compatibility with older versions of the language.
Statements, including assignment statements, are illegal (a syntax error) if they appear outside the body of a function.
You have:
int *ptr;
*ptr = 2;
at file scope. The first line is a valid declaration of an int* object called ptr, implicitly initialized to a null pointer value. The second line looks like an assignment statement, but since it's outside a function, the compiler most likely won't even try to interpret it that way. gcc treats it as a declaration. Old versions of C permitted you to omit the type name in a declaration; C99 dropped the "implicit int" rule. So gcc treats
*ptr = 2;
as equivalent to
int *ptr = 2;
and produces the following warnings:
c.c:4:1: warning: data definition has no type or storage class [enabled by default]
c.c:4:8: warning: initialization makes pointer from integer without a cast [enabled by default]
The first warning is because you omitted the int (or other type name) from the declaration. The second is because 2 is a value of type int, and you're using it to initialize an object of type int*; there is no implicit conversion from int to int* (other than the special case of a null pointer constant).
Once you get past that, you have two declarations of the same object -- but they're compatible, so that's permitted. And the pointer variable is initialized to (int*)2, which is a garbage pointer value (there's not likely to be anything useful at memory address 0x00000002).
In your main function, you do:
printf("%d\n", *ptr);
which attempts to print the value of an int object at that memory address. Since that address is not likely to be one that your program has permission to access, a segmentation fault is not a surprising result. (More generally, the behavior is undefined.)
(This is a fairly common problem in C: minor errors in a program can result in something that still compiles, but is completely different from what you intended. The way I think of it is that C's grammar is relatively"dense"; small random tweaks to a valid program often produce different but syntactically valid programs rather than creating syntax errors.)
So that's what your program actually does; I'm sure it's not what you intended it to do.
Take a deep breath and read on.
Here's something that's probably closer to what you intended:
#include <stdio.h>
int *ptr;
int main(void) {
*ptr = 2;
printf("%d\n", *ptr);
return 0;
}
Since there's now no initializer for ptr, it's implicitly initialized to a null pointer value. (And if ptr were defined inside main, its initial value would be garbage.) The assignment statement attempts to dereference that null pointer, causing a segmentation fault (again, the behavior is undefined; a segmentation fault is a likely result). Execution never reaches the printf call.
I thought that *ptr=2 would set the rvalue that the pointer ptr is point to to 2. Is that not the case?
Not quite. Pointers don't point to rvalues; an "rvalue" is merely the value of an expression. Pointers point to objects (if they point to anything). The assignment
*ptr = 2;
would assign the value 2 to the object that ptr points to -- but ptr doesn't point to an object!
Now let's see a version of your program that actually works:
#include <stdio.h>
int *ptr;
int variable;
int main(void) {
ptr = &variable;
*ptr = 2;
printf("*ptr = %d\n", *ptr);
printf("variable = %d\n", variable);
return 0;
}
Now ptr points to an object, and *ptr = 2 assigns a value to that object. The output is:
*ptr = 2
variable = 2

Dereferencing array pointer in a function

How do you deference a pointer to an array to get the value stored in it? For example:
void testFunction(int **test){
printf("%d", *test[1]);
}
int main()
{ int test[10];
test[1] = 5;
testFunction(&test);
return 0;
}
I get an error. Anyone could explain?
How do you deference a pointer to an array to get the value stored in it?
You use the * operator, as for every pointer. (Oh, and pay attention to operator precedence!)
void foo(int (*arr)[5])
{
printf("%d\n", (*arr)[0]);
}
int main()
{
int arr[5] = { 0, 1, 2, 3, 4 };
foo(&arr);
return 0;
}
Your code would have generated a diagnostic about an incompatible type being passed to the function. For example, GCC complains:
prog.c: In function 'main':
prog.c:9: warning: passing argument 1 of 'testFunction' from incompatible pointer type
You should pay attention to all diagnostics issued by your compiler, and make sure you understand them, and take the appropriate measures to address them. For this particular one, if you intend to pass in a pointer to an array, you need to write your function to accept such a thing. Then, when you dereference the pointer, you have an array. So, you access it like one.
void testFunction(int (*test)[10]){
printf("%d", (*test)[1]);
}
The [] has higher precedence that *, so the parentheses are required both for the function parameter argument, and for accessing the value in the printf(). When the pointer to int[10] is derferenced, the resulting value is the address of the first element of the array test defined in main. The [] operation then access the 2nd element of the array, and you get the value you expected.
You may be more convinced that your use of int **test is wrong for a pointer to an array if you note that the assertion below will always be true:
int test[10];
assert(&test == (void *)test);
As the compiler warning indicates, a pointer to a pointer to int is not the same as a pointer to an int[10]. The type being pointed to determines the type that results from a dereference.
So:
int test[10] = { [1] = 5 };
testFunction(&test);
This passes the address of test to testFunction. The address of a variable corresponds to its location in memory. This is not so different for an array, but the location in memory for an array variable is the address of its first element. So, the address returned by &test above is the same address returned by test alone.
This gives a disastrous consequence when you treat this pointer value as a pointer to a pointer to int in your testFunction. First, note that you ignore proper operator precedence, so the first dereference is:
test[1]
Since you declare the test parameter to be a pointer to a pointer to int, this increments the address in test by sizeof(int *) and treats the result as an int *. Then, you dereference again:
*test[1]
This now takes the value of test[1] and dereferences it again in an attempt to get an int. However, the address returned by test[1] has no relationship with the array test defined in main, and you are accessing a totally nonsensical memory location.
Even if you paid attention to the precedence with your pointer to pointer to int parameter type, a similar problem would have resulted.
(*test)[1]
Now, the pointer to int[10] is treated as a pointer to pointer to int is derferenced first. This results in the first sizeof(int **) bytes of the test array in main to be treated as a pointer to int. This is already a nonsensical value at this point, but the array dereference now increments this value by sizeof(int) bytes and dereferences that value in an attempt to obtain an int.
The other user gave an example of how it is usually done already, but if you insist on passing an int ** then because of operator precedence the syntax would be like:
void testFunction(int **test){
printf("%d", (*test)[1]);
}
int main()
{ int test[10];
test[1] = 5;
int *testptr= &test[0]; // or int *testptr= test;
testFunction(&testptr); // this passes an int **
return 0;
}
But in c the name of an array is a pointer to the array elements, so int *ptrtest and ptrtest[1] is more commonly used.

When are values implicitly converted to pointers?

I have many functions like:
void write(char* param, int len)
{
//
}
And I notice that I almost never use the & operator for arguments. When I pass an array:
char in[20];
write(in, 20);
I dont need it, but when I pass a single value:
write(5, 1);
I don't seem to need it, and when I pass a pointer:
char* in = malloc(20);
write(in, 20);
I also dont need it. So in which circumstances do I actually need to call:
write(&in, 1);
Because I'm confused :D
Are you sure about your second case? It doesn't compile for me and should be
char in = 5;
write(&in, 1);
When are values implicitly converted to pointers?
In practice, integer types may be converted to pointers implicitly by the compiler. In theory, this is illegal and compilers that accept it will usually issue a warning:
example.c:2:6: warning: incompatible integer to pointer conversion initializing
'void *' with an expression of type 'int'
In your above example:
char in = 5;
write(in, 20);
char is an integer type, so if your compiler allows it, it may be implicitly converted to a pointer type, although it is not part of the C standard and is completely compiler-specific.
Note that converting an integer type to a pointer type using a cast is allowed by the standard, although results are implementation-defined:
char in = 5;
write((char *)in, 20);
The only allowed case of implicit conversion is when integer constant 0, which denotes a null pointer:
write(0, 20); // allowed
Note that the integer constant is itself allowed, but a variable of integer type with the value 0 is not:
char in = 0;
write(in, 20); // not allowed
As for the others, when you pass a pointer, you don't need the &, obviously, because it's already a pointer. When you pass an array, it decays to a pointer so you don't need & there either. In both these cases it would be actually illegal to use it, as your function above expects a char * and be fed with a char ** and a char (*)[20] respectively.
If you copy somehow the prototype of function 'write' to the file where you call this function, as follows.
void write(char *in, int len);
void foo(int bar){
char in=5;
write(in, 1);
}
You will probably get a warning. Because in is not a pointer, though 5 can be an address.
I guess if your program is compiled and linked successfully, it will crash at run-time.
with using;
return_type function_name(prim_data_type* param...)
param is a pointer that pointing an address in the memory and *param is the value in that address.
Answer is about what you want to do with this param.
char in[20];
by saying that "in" is the first element's address. So at the function call:
write(in, 20);
you are sending the first element's address so in the function implementation, you can access the first element by *param, second element with *(param+1) or param[1] etc.
The place that you are confused is here:
char in = 5;
write(in, 1);
Because in is the address 5 (00000005), so in the implementation of the function you are accessing that place whichever value is there. You must be careful with using like this.
In the malloc operation:
char* in = malloc(20);
write(in, 20);
in is a pointer to an address (first element's address) holding up 20 elements of char can be take space. In the function you can access to all elements with param pointer(*param is the first element, *(param+7) or param[7] is the 8. element)
In the conclusion, when you want to play with an primary data typed variable (int, float, char..) in another function, you must use;
write(&in);
By doing that, in the implementation of that write function, you can access that variable, change the value by *param with no confusion.
Note:Some explanations were simplified here for better understanding. Extra warnings would be welcomed here.
Functions and arrays decay into pointers in some contexts. Functions can decay into pointers to functions, and arrays can decay into a pointer to the first element of the array. No other types behave this way.
This example:
char in = 5;
write(in, 1);
Is wrong though. You definitely need the & in that case. Are you sure it worked like that?

Resources