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

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

Related

How does the int *ptr= 5; is different than that of int *ptr= address of variable?

Though it is very basic and might seem silly, I am trying to understand what is difference between the int *ptr = 45 or 0xc8750; (some number) vs. int *ptr= &a; (address of variable).
What I already know is:
Pointers are made to store address of variables and to modify contents of pointed variables ( but I want to know how it will be achieved)
In latter case, I can assign *ptr to different address that is legal.
But, in first case it is illegal!.
Why the latter is illegal if both address/number are integers?
How differently will they be treated while storing in memory?
I have two piece of code/programs basically to highlight the same:
case-1:
#include <stdio.h>
int main()
{
int *ptr = 0xc42; // is this stored in read only memory?!! which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
return 0;
}
case-2:
int main()
{
int a=10, b=20;
int *ptr = &a; // is here get any special treatment and object will be created for *ptr!!!
*ptr = &b; //legal
printf(" *ptr = %d \n", *ptr);
*ptr = 20; //legal !!
printf(" *ptr = %d \n", *ptr);
*ptr = 50; //legal
printf(" *ptr = %d \n", *ptr);
return 0;
}
As we can see the *ptr = 20 and *ptr = 50 are legal and fine! (No segmentation faults).
Why is this assignment of int *ptr = 0xc989 or 5 different from int *ptr = &variable?.
Let's start from basics: a pointer is a variable containing the address pointing to data of a given type. If we declare
datatype* foo;
foo (that is currently not initialized) will contain the address of a variable of type datatype, and deferencing it
*foo = ...;
we are accessing that address and storing there its value.
In both cases we have * foo, but they're not the same!
In the first case the asterisk refers to datatype. The variable type is datatype *; the variable name is foo. foo contains an address.
In the second case we are dereferencing the address, in order to access it. The asterisk refers to the variable in order to perform the pointer dereferentiation.
So, when you write
int *ptr = 0xc42; // is this stored in read only memory?!!
// which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
With int *ptr = 0xc42; you are saying to the compiler that you are declaring a variable named ptr, of type int * and whose first value is 0xC42. (Note: as correctly stated by user Lundin, this assignment requires a further cast in order to be valid C).
With *ptr = 45; you are accessing the address pointed by ptr and assigning value 45. Is it legal? Well, it is if you previously assigned a valid address (and generally speaking it is if you assign to a pointer another variable's address with & operator, e.g int *ptr = &a;). But if you assign a random integer to it... it will likely lead to a segmentation fault.
Logically, if you are sure that the location, 0xc989, preserves what you need, int *ptr = 0xc989 perfectly valid (with regard to your thinking concept, as said by Roberto Caboni).
Technically, as said by Lundin, you need to cast it according to C standards.
First of all int *ptr = 0xc42; is not valid C and will not compile cleanly on a compiler configured to strict standard C. With gcc, clang and icc this means compiling with -std=c11 -pedantic-errors. For details, see "Pointer from integer/integer from pointer without a cast" issues.
int *ptr = (int*)0xc42; is valid C but fishy. To clarify, this stores an address inside the pointer variable itself, it doesn't store a value. So if you know that there is an int-sized item at memory address 0xc42, such as a memory-mapped hardware register, then you can point directly do it. But when doing so, it will only be meaningful to do that using volatile: volatile int *ptr = (volatile int*)0xc42;. Code like that mostly makes sense in embedded systems and other hardware-related programming.
As for why your second example works fine, the addresses there are assigned by the linker and not by the programmer, so they will point at valid, allocated data.

Can anyone explain to me what actually causes this Segmentation Fault and How to overcome this?

#include <stdio.h>
#define null1 ((void*)0)
#define val ((int)2)
int main() {
int *p;
p = null1;
printf("%p", &p);
//p = (int *)val;
*p = val;
//printf("\n%p", (int*)p);
return 0;
}
Output:
Segmentation fault(core dumped)
I want to assign value of macro to the Pointer.
null1 is a null pointer, its definition #define null1 ((void*)0) is one of the accepted definitions for a null pointer.
val is a macro expanding to the plain integer constant 2. Casting 2 as (int) has no effect, 2 is already an int constant value.
Storing a value to a null pointer has undefined behavior. A segmentation fault is one the possible effect of undefined behavior. A rather useful one since it allows the debugger to point to the problem immediately.
Casting any other integer value as (int *) has undefined behavior too: p = (int *)val; *p = val; is very likely to cause the same segmentation fault, but may have some other unexpected side effects, depending on the target platform specifics: if 2 happens to be the address of the self-destruct trigger port, all bets are off.
Null pointer is a special reserved value of a pointer. A pointer of any type has such a reserved value. Formally, each specific pointer type (int *, char * etc.) has its own dedicated null-pointer value. Conceptually, when a pointer has that null value it is not pointing anywhere.
Void pointer is a specific pointer type - void * - a pointer that points to some data location in storage, which doesn't have any specific type.
Here null1 refers to a void pointer whereas p is a pointer of the type integer.
Hope I was right and this is helpful to you.
Pointers directly point to memory addresses. While each program that we run is allocated a fixed memory area only (called segments). All memory address in this area is referred to using relative memory address.
But pointers have absolute memory addresses in them. Generally, the starting memory addresses are for Operating System's use. When you assign a pointer to some address outside of its segment area then it gives SIGSEGV ( Segmentation Error ).
In your case also, you are trying to assign p an address outside its segment area thus the error.
NULL pointer is an invalid pointer because it points to memory that is not valid to access so that the statment *p = val is not valid, so the Segmentation fault error appears.
To overcome this error you need to assign a valid address of a memory location to the pointer(p), such as defining a variable (var) and assign the addres to the pointer as p = &var;.
You just need to assign your pointer to your macro as code below:
#include <stdio.h>
#define val 2
int main()
{
int *p;
p = (int*)val;
printf("%p\n", &p);
printf("%d\n", p);
return 0;
}

C: Whats the difference between pointer = variable and pointer = &variable?

The textbook i'm reading explains that pointers are variables which hold the starting address of another variable, and that they are defined with a type of data to point to. Why can you assign a pointer to be the address of a variable then? or rather not be an address if omitting the "&" should it not always hold the address if that's how pointers are defined?
ptr is the actual pointer, while *ptr is whatever it is pointing at, so *ptr=&var does not really make any sense, unless it's a pointer to a pointer. It's either ptr=&var or *ptr=var
If you really want to assign a variable to a pointer, it is possible with casting. This compiles, but I cannot see any good reason to do something like this at all:
#include <stdio.h>
main()
{
int var=4;
int *ptr;
ptr = (int *)var;
printf("%d\n", *ptr);
}
The behavior is undefined. When I ran it, it segfaulted.
C was designed a long time ago, and some of the design choices were made in circumstances that are no longer current. The address of operator was needed to pass the address of an object rather than its value to a function at a time where function prototypes were optional and the ambiguity couldn't have been resolved from context. The same syntax was used for assignment, for consistency.
Note however that your proposed syntax simplification one could no longer distinguish these cases:
void *p;
void *q = &p; // make q point to the pointer p
void *q = p; // set q to the value of p
There are other potential syntax simplifications:
The . and -> operators for object and pointer dereferencing could be merged into a single operator.
The * syntax for indirect function calls: (*fun)() is reduncdant as fun() is exactly equivalent... (note that you can write (****fun)() too)

Assigning an int to a pointer, What happens?

Instead of initializing a pointer like this,
int main (){
int *ptr;
int x = 5;
ptr = &x;
}
What happens in memory when you do something like this?
int main (){
int *ptr = 100;
}
Would *ptr be looking for a random address that contains the value 100 or is it storing the value of 100 in ptr?
This is a constraint violation, the compiler should give you a diagnostic message. (If the compiler doesn't say "error" then I would recommend changing compiler flags so that it does). If the compiler generates an executable anyway, then the behaviour of that executable is undefined.
In Standard C, this code does not assign 100 to the pointer, as claimed by several other comments/answers. Integers cannot be assigned to pointers (i.e. using the assignment operator or initialization syntax with integer on the right-hand side), except the special case of constant expression zero.
To attempt to point the pointer to address 100, the code would be int *ptr = (int *)100;.
First of all, as mentioned in other answers, the code int *ptr = 100; is not even valid C. Assigning an integer to a pointer is not a valid form of simple assignment (6.5.16.1) so the code is a so-called "constraint violation", meaning it is a C standard violation.
So your first concern needs to be why your compiler does not follow the standard. If you are using gcc, please note that it is unfortunately not configured to be a conforming compiler per default, you have to tell it to become one by passing -std=c11 -pedantic-errors.
Once that is sorted, you can fix the code to become valid C by converting the integer to a pointer type, through an explicit cast. int *ptr = (int*)100;
This means nothing else but store the address 100 inside a pointer variable. No attempts have been made to access that memory location.
If you would attempt to access that memory by for example *ptr = 0; then it is your job to ensure that 100 is an aligned address for the given system. If not, you invoke undefined behavior.
And that's as far as the C language is concerned. C doesn't know or care what is stored at address 100. It is outside the scope of the language. On some systems this could be a perfectly valid address, on other systems it could be nonsense.
int *ptr = (int*)100; // valid
int *ptr = 100; // invalid as int to int * cast is not automatic
Usage of absolute address is discouraged because in a relocatable program segment, you would never know where a pointer should have as a value of some address, rather it should point to a valid address to avoid surprises.
Compiler won't give you any error. But it's a constraint violation. Pointer variables store addresses of other variables and *ptr is used to alter value stored at that address.
The long and short of it is nothing. Assigning the value 100 to the pointer value p does something; it sets the address for the pointer value to 100, just like assigning the value of the call malloc to it would; but since the value is never used, it doesn't actually do anything. We can take a look at what the value produces:
/* file test.c */
#include <stdlib.h>
#include <stdio.h>
int main() {
int *ptr = (int *) 100;
printf("%p\n", ptr);
return 0;
}
Executing this results in this output:
0x64
Pointers are, in a sense, just an integer. They (sometimes) take up about the same size of an integer (depending on the platform), and can be easily casted to and from an integer. There is even a specific (optional) type defined in C11 for an integer that is the same size as a pointer: intptr_t (see What is the use of intptr_t?).
Going back to the point, attempting to perform any dereferencing of this pointer of any kind can cause Weird Behavior(tm) - the layout of the memory is platform and implementation dependent, and so attempting to grab something at the address 100 will likely cause a Segmentation Fault (if you're lucky):
/* file test.c */
#include <stdlib.h>
#include <stdio.h>
int main() {
int *ptr = (int *) 100;
printf("%i\n", *ptr);
return 0;
}
Executing results in this output:
fish: "./test" terminated by signal SIGSEGV (Address boundary error)
So don't do it unless you know exactly what you're doing, and why you're doing it.
with:
int *ptr = 100;
you have assigned the value 100 to the pointer. Doing anything with it but printing its value will be undefined behavior:
printf ("pointer value is %p\n", (void *)ptr);

When you're dealing with C and other languages that have pointers, does initializing a pointer automatically set it to null?

Let's say you have defined a (global or local) pointer variable such as this:
void *this_is_a_pointer;
without giving it the value " = NULL; "
Would this automatically give you a NULL ptr (a pointer that points to NULL)?
* Also, what does it mean for a null pointer to point to NULL? Is that saying that it could point to literally anywhere? (basically, what really is the "address location of NULL"?)
(global or local)
This is actually what makes the difference.
In general, if you didn't initialize a variable, it's not initialized and reading from it is undefined behavior. But if the variable has static storage duration, then it's automatically initialized to zero (null for pointers).
// foo.cpp
void* this_is_null;
void whatever(void)
{
static int* and_so_is_this;
}
void not_whatever(void)
{
float* but_this_local_is_uninitialized;
}
Definitely do not count on this. Compilers in Debug mode (with the correct switch settings) will typically zero variables on the stack for you to track down bugs, but it is better to explicitly initialize all of your variables not just pointers.
EDIT: In response to your edit, the value of NULL is defined as zero. So, it would point to address 0, which in most modern operating systems would result in a segmentation fault, or memory access violation. But, on some embedded operating systems with little memory management it would let you change the contents of address 0! This one has bit me a few times ;)
C Tutorial – More on Pointers
Initialise a pointer
Before you can use a pointer in for instance a printf statement, you
have to initialize the pointer. The following example will not
initialize the pointer:
#include<stdio.h>
void main()
{
int *ptr_p;
printf("%d\n",*ptr_p);
}
Note: We used void when we declared the function main(). So no return
0; is needed. (Some compilers will give a warning when void is used on
main(). GNU compiler will give the warning: return type of ‘main’ is
not ‘int’).
In this example we print the value that ptr_p points to. However, we
did not initialize the pointer. In this case the pointer contains a
random address or 0.
The result of this program is a segmentation fault, some other
run-time error or the random address is printed. The meaning of a
segmentation fault is that you have used a pointer that points to an
invalid address.
10.4 Null Pointers
The most straightforward way to ``get'' a null pointer in your program
is by using the predefined constant NULL, which is defined for you by
several standard header files, including , , and
. To initialize a pointer to a null pointer, you might use
code like
#include
int *ip = NULL;
< and to test it for a null pointer before inspecting
the value pointed to you might use code like
if(ip != NULL)
printf("%d\n", *ip);
It is also possible to refer to the null
pointer by using a constant 0, and you will see some code that sets
null pointers by simply doing
int *ip = 0;
(In fact, NULL is a preprocessor macro which typically
has the value, or replacement text, 0.) Furthermore, since the
definition of ``true'' in C is a value that is not equal to 0, you
will see code that tests for non-null pointers with abbreviated code
like
if(ip) printf("%d\n", *ip);
This has the same meaning as our
previous example; if(ip) is equivalent to if(ip != 0) and to if(ip !=
NULL). All of these uses are legal, and although I recommend that you
use the constant NULL for clarity, you will come across the other
forms, so you should be able to recognize them.
A pointer with static storage duration will be automatically initialized to NULL. A pointer with auto duration will not be initialized, and will contain a random value that may or may not correspond to a valid memory address:
#include <stdio.h>
int *p0; // File scope, initialized to NULL
int main(void)
{
static int *p1; // Declared "static", initialized to NULL
int *p2; // Auto, not initialized
printf("p0 = %p, p1 = %p, p2 = %p\n", (void *) p0, (void *) p1, (void *) p2);
return 0;
}
There is the null pointer constant, which is 0 (the macro NULL expands to a 0-valued pointer expression). There is the null pointer value, which may or may not be 0-valued; it's the value used by the underlying system to indicate a well-defined "nowhere". When a null pointer constant appears in your code, it will be replaced with the null pointer value.
A null pointer value is guaranteed to compare unequal to any valid pointer value.

Resources