Segmentation fault: but why? - c

#include <stdio.h>
int main()
{
int* ptr;
*ptr = 5;
printf("%d", &ptr);
return 0;
}
This was asked in a coding interview, what should be the output?
I am confused between runtime error, compilation error and segmentation fault.
Anyone who can explain why will the answer be segmentation fault?

Your code invokes undefined behavior because the pointer was left uninitialized. You need to initialize the pointer first before inserting into it anything:
int *ptr = malloc(sizeof(int) * REQ_SIZE);
After this, you will no longer get a segfault. Note that you need to put a dereference operator instead of & to print the containing value of the integer pointer.
Here's a demo.

Compilation error is an error that you face while your program is being compiled by the compiler and it's due to C grammar (Maybe you wrote an incorrect instruction grammatically.)
Runtime error is an error that you face when your program is running.
Segmentation fault is an error that you face when you're trying to access to a location in the memory that you're not allowed to access to it such as a location indicated by null pointers.
Your program has undefined behavior. Because pointers store a memory address and they cannot store a value such as a number. You could allocate some memory from heap and then you can store a value in your pointer:
int *ptr = (int*) malloc (sizeof(int));
*ptr = 5;
Or you could declare a local variable and store its address in ptr:
int value = 5;
int *ptr = &value;

Just look at the definition of Pointers. Pointer is a variable whose value is the address of another variable, i.e. direct address of the memory location. Here in your case, ptr is declared as an integer pointer, which isn't pointing to any address. That's why it gives Segmentation Fault Error. Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you". Instead of this you can do 2 things :
Assign a new integer variable's address to the pointer :
int x;
int *ptr = &x;
*ptr = 5;
Initializing the pointer using the malloc() :
int *ptr = (int*)malloc(sizeof(int) * SIZE_REQUIRED);
Also note that by using the reference of ptr in the printf() prints the address of the pointer rather than the value contained by the address it is referring to. It is demonstrated here :
printf("%d", ptr); // Prints the address of the pointer variable.
printf("%d", *ptr); // Prints the value (in this case : 5) contained by the address referenced by the pointer.

Related

Is dereferencing illegal without referencing?

I tried storing a value in an uninitialized pointer using the following code but got segmentation fault (core dumped error ).
#include <stdio.h>
int main()
{ const int a=9;
int *p=&a;
scanf("%d",p+1);
printf("%d %d",*p,*(p+1));
return 0;
}
please explain why? Noob here
I tried storing a value in an uninitialized pointer
This is an initialized pointer: int *p=&a;
However, you cannot assign a const int* to an int* in C, it is invalid code and will not compile cleanly.
scanf("%d",p+1);
The code p+1 points out of bounds of the allocated variable. You tell scanf it's ok to store something at an address where no memory is allocated. This is undefined behavior and may crash.
*(p+1)
Here you de-reference the pointer, again one item out of bounds. This is not allowed - it is undefined behavior and could cause a crash.
You have problem in
scanf("%d",p+1);
you are not allowed to access the memory location as p+1, it's outside the legally accessible memory by your program, in other words, invalid memory location. Attempt to access (read/write) invalid memory location invokes undefined behaviour.

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

The following C program regarding pointers is not working

#include<stdio.h>
int main(void)
{
int *pc;
*pc=100;
printf("\n Address of Pointer : %d",pc);
printf("\n Contents of Pointer : %d",*pc);
}
When I run the code in eclipse, it is saying "Pointers.exe has stopped working". What is the error?
Assigning a value to *pc is particularly dangerous. If pc contains the valid memory address , then the assignment
*pc = 100;
will attempt to modify the data stored at that address.
If the location modified by this assignment belongs to the program, it may behave erratically; if it belongs to operating system, the program will most likely crash.
Your compiler should raise a warning that pc is uninitialized.
Change it to:
int a;
int *pc;
pc = &a;
*pc = 100;
Your pc pointer was not initialized in your program.
Moreover the way your are printing a pointer value is incorrect, use this:
printf("\n Address of Pointer : %p", (void *) pc);
You forgot to point pc to somewhere useful. When you write
int *pc;
The compiler creates a pointer for you. The pointer points somewhere in memory, and you have no way of knowing where. Chances are, it points to a bad place in memory. When you overwrite it with *pc=... you overwrite a place in memory that shouldn't be overwritten.
So you need to have pc point somewhere.
int a, *pc=&a;
will do the trick. Now the compiler prepares an int for you then and you point pc to it. That way, when you write through the pointer, nothing bad will happen - you're writing on an area of memory that you know is safe.
Another way to initialize pc is like so:
int *pc = (int*)malloc(sizeof(int)); // Allocate an integer on the heap
Now *pc=100; will also work. Just don't forget to free(pc) when you're done.
You have:
int *pc;
*pc=100;
When you define the pointer to integer pc above, this pointer is not initialized, so it points to some memory that you have not allocated and you have not the right to access.
So your executable is crashing.
Just use a valid pointer, e.g. you can allocate some heap memory using malloc(sizeof(int)) (and later release it using free()), or just use stack-based memory for local automatic variables, e.g.:
/* An integer stack-allocated variable */
int n = 64;
/* Pointer to that integer */
int * pn = &n;
/* Change its value */
*pn = 100;
Moreover, to print an address, considering using the %p specifier for printf().
e.g.:
#include <stdio.h>
int main(void)
{
int n = 64;
int *pn = &n;
printf("n (before): %d\n", n);
*pn = 100;
printf("n (after): %d\n", n);
printf("Address of n: %p", (void *)pn);
return 0;
}
Output:
n (before): 64
n (after): 100
Address of n: 003AF7CC
Pointers need to POINT! A pointer is a variable that contains the adress of another variable.
int *pc;
This pointer contains some garbage value. Who knows what was in that memory before. The adress that it's pointing to could be an adress of memory that is occupied by another program. You need to assign a valid adress to a pointer if you want to change the value in that adress.
If you want to calculate sum of all the members of an array you would have to initialize the variable sum to 0 because it could contain other values.
The same is with pointers. They have to contain a valid adress of a variable if you want to modify the value.
Your program would work if you comment line *pc = 100;. You can display the adress of an uninitialized pointer but the program will crash if you try to change the value in that adress.

pointer segmentation fault with gcc

void main()
{
int *p=20;
printf("%d\n",*p);
}
This code is compiling successfully but giving segmentation fault, I am using gcc compiler.
I think you are thinking that
int *p=20;
will stroe an integer value of 20 into pointer P,But its not the case.
you are actually initializing the poinetr value to an address 20.
and in the print statement you are dereferencing it for which you might not be authorized to do.
try the below code instead
void main()
{
int a=20
int *p=&a;
printf("%d\n",*p);
}
You defined p as a pointer to memory address 20. You are then trying to dereference that address when you use the *p syntax. Address 20 is unlikely to be in the range of memory you are allowed to access, so it will give you a segmentation fault.
char* i = "abcd"; tells the compiler to set aside space for the string in memory, and point i to that place in memory. You are still assigning the place in memory to the variable.
The *i in your printf means you want the value which is pointed to by i. In your comment, you won't actually get abcd, you will actually get a. This is because i points to the first character in the string "abcd", and that character is a.
If you want an example of how you can point to integers, take a look at this code:
#include<stdlib.h>
#include<stdio.h>
int main() {
int number = 5; //A space in memory, set to the value 5
int* pointer = &number; //A pointer to point to the space in memory
printf("%d\n", *pointer); //Using * to get the value pointed to by pointer
return 0;
}
The pointer p points to the address 20 which is likely not yours. The printf call will try to print the contents of that memory, which is not allowed.

Resources