Global pointers cause segmentation fault? - c

When compiled by gcc and then run,
the code
int *p;
int main() {*p = 1;}
causes a segmentation fault.
Apparently, the memory location
contained in p cannot be written to.
Why????
On the other hand,
int q[];
int main() {*q = 1;}
runs just fine.
What's going on here??
Why does p contain only read-only memory?

The first example has a wild (not explicitly initialized) pointer. Since it's not an automatic variable, it is set to 0, which clearly is not memory you own. You can see this by printing it out with:
printf("%p\n", p)
As for the second, C99 ยง6.9.2 actually gives this as an example:
EXAMPLE 2 If at the end of the
translation unit containing
int i[];
the array i still has incomplete type,
the implicit initializer causes it to
have one element, which is set to zero
on program startup.
In general, objects with tentative definition (no initializer) are initialized with 0, which for an array means a 1-element array with element value 0.

*p = 1; causes Segmentation fault because it was not allocated any memory before the assignment.
*q = 1;works because the compiler (gcc 4.2.1 on Mac OS X) warns that q[] is assumed to have one element.

Your first example causes a segmentation fault because you are dereferencing NULL. You never initialize p with a value, and because it's a global it will be NULL. Thus, you dereference NULL, and boom.
I'm not sure how the second example is valid - gcc notes that it is assuming q to be a 1-element array, which is why that won't blow up.

Related

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;
}

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);

C pointer initialization differences

I am new to C and have some questions about the pointer.
Question 1 What`s differences b/w the following two? Which way is better to initialize a pointer and why?
int *p=NULL;
int *p;
#include <stdio.h>
void main()
{
char *s = "hello";
printf("%p\t%p",s);
//printf("%p\t%p",&s) it will give me unpredictable result every time
//printf("%p\t%p",(void *)&s) it will be fine
//Question3: why?
}
Question 2: I try to google what is %p doing. According to my reading, it is supposed to print the pointer. It that mean it print the address of the pointer?
Question 1, these are definitions of pointer p. One initializes the pointer to NULL, another leaves it uninitialized (if it is local variable in a function, and not global variable, global variables get initialized to 0 by default). Initializing with NULL can be good, or it can be bad, because compiler can warn you about use of uninitialized variables and help you find bugs. On the other hand compiler can't detect every possible use of uninitialized variable, so initializing to NULL is pretty much guaranteed to produce segmentation fault if used, which you can then catch and debug with a debugger very easily. Personally I'd go with always initializing when variable defined, with the correct value if possible (if initialization is too complex for single statement, add a helper function to get the value).
Question 2, %p prints the address value passed to printf. So printf("%p", pointer); gets passed value of variable pointer and it prints that, while printf("%p", &pointer); (note the extra & there) gets passed address of the variable pointer, and it prints that. Exact numeric format of %p is implementation defined, it might be printed just as a plain number.
Question 3 is about undefined behavior, because format string has more items than what you actually pass to printf. Short answer is, behavior is undefined, there is no "why". Longer answer is, run the application with machine code debugger and trace the execution in disassembly view to see what actually happens, to see why. Note that results may be different on different runs, and behavior may be different under debugger and running normally, because memory may have different byte values in different runs for various reasons.
1) The first is an initialization (to NULL in this case) the second is only a declaration of p as a pointer to int, no initial value is assigned to p in this case. You should always prefer an initialization to prevent undefined behavior.
2) You should cast to void* when using %p to print out a pointer (beware that you are using it too many times in your format specifier). The memory address to which p points is printed.
1)
int *p = NULL
defines and initializes a pointer 'p' to NULL. This is the correct way to initialize pointers in order to get "Seg Fault" if you forget to assign a valid address to this pointer later.
int *p
Only defines a pointer "p" with an unknown address. If you forget to assign a valid value to this pointer before using it, then some compilers will notify you about this mistakes while some others will not and you may access a non-valid address and get a run time error or undefined behaviour of the program.
2) "%p" is printing the address where the pointer is points. Since the pointer holds an address, then "%p" prints this address.
printf("%p\t%p",s);
So the first "%p" will print the address where the pointer "s" points which is the address which stores the string "hello". However, note that you are using twice "%p" but you providing only one pointer to print its address !!
Most compilers will not scream about this cause it is effect-less; however try to avoid it.
Answer1 :
int *p=NULL;
p is a pointer to a int variable initialized with NULL. Here NULL means pointer p is not pointing to any valid memory location.
int *p;
p is a pointer to a int variable. p in uninitialized. Reading uninitialized variables is Undefined Behavior. (one possibility if try to use is that it will throw a segmentation fault)
Answer2:
It prints content of pointer. I mean base address of string "hello"
The main difference is that in *p = NULL, NULL is a pre-defined and standard 'place' where the pointer points.
Reading from Wikipedia,
The macro NULL is defined as an implementation-defined null pointer constant,
which in C99 can be portably expressed as the integer value 0
converted implicitly or explicitly to the type void*.
This means that the 'memory cell' called p contains the MACRO value of NULL.
If you just write int *p, you are naming the memory cell with the name p but this cell is empty.

Assigning an int value to a pointer in C

According to this Berkeley course and this Stanford course, assigning an int to a pointer like so should crash my program:
#include<stdio.h>
int main() {
int *p;
*p = 5;
printf("p is %d\n", *p);
return 0;
}
Yet when I compile this on OSX 10.9.2 using GCC {Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)} I get the following output:
Chris at iMac in ~/Source
$ ./a.out
p is 5
How come? I see the reverse question has been asked (Allocating a value to a pointer in c) but this only confuses me further as my program is nearly identical to the code posted in that question.
You are not allocating int to a pointer. If p is a pointer, *p points to its value. You are assigning *p = 5; which is plain integer to integer assignment.
In this case, p is not initialized and may give rise to segmentation fault.
According to this Berkeley course and this Stanford course, allocating an int to a pointer like so should crash my program:
First off let's get your terminology correct. You are not "allocating an int to a pointer". Allocation is the creation of a storage location. An int is a value. A pointer is a value. A pointer may be dereferenced. The result of dereferencing a valid pointer is to produce a storage location. The result of dereferencing an invalid pointer is undefined, and can literally do anything. A value may be assigned to a storage location.
So you have:
int *p;
You have allocated a (short-lived) storage location called p. The value of that storage location is a pointer. Since you did not initialize it to a valid pointer, its value is either a valid pointer or an invalid pointer; which is it? That's up to your compiler to decide. It could always be invalid. It could always be valid. Or it could be left up to chance.
Then you have:
*p = 5;
You dereferenced a pointer to produce a storage location, then you stuck 5 in that storage location. If it was a valid pointer, congratulations, you stuck 5 into a valid storage location. If it was an invalid pointer then you've got undefined behaviour; again, anything could happen.
printf("p is %d\n", *p); // 5!
Apparantly you got lucky and it was a valid storage location this time.
According to this Berkeley course and this Stanford course [this] should crash my program:
Then those courses are wrong, or you are misquoting them or misunderstanding them. That program is permitted to do anything whatsoever. It is permitted to send an email inviting the president of Iran to your movie night, it is permitted to print anything whatsoever, it is permitted to crash. It is not required to do anything, because "permitted to do anything" and "required to do something" are opposites.
My answers: You're lucky!
The fact is, the value you happen to have in p is a valid memory address, that you can actually write to, this is why it works...
Try playing with optimising options (-O3) in your compiler, than you'll get different results...
Your program is not guaranteed to fail, neither is it guaranteed to succeed. You are dereferencing a pointer which could hold any address. It is undefined behaviour.
It's not that it should crash, but it is undefined behavior.
Depending on the system and the runtime circumstances, assigning to a dereferenced and uninitialized pointer can either segfault or continue running "normally," which is to say that it appears work but may have unusual side effects.

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

Resources