2 Common Problems involving Pointers:
(Dereferencing) Dangling Pointers
And
Garbage Memory
Dangling Pointers
A pointer is dangling when declared & not initialized
●
●
A pointer becomes non dangling, when assigned to a
“good” memory location like local variables, global
variables, malloc-ed memory
●
A pointer can become dangling again due to mistakes in
pointer arithmetic
Mistakes in manipulation of dynamically allocated
●
memory, e.g. Linked list pointers
On deallocation of malloced memory using free()
●
etc
Dangling Pointers
Ø
Total 3 Possibilities for a pointer value
Ø
Points to memory owned by program
Local variables, Global Variables, Malloced Memory
Ø
= NULL
Ø
Dangling
Ø Some texts differentiate between ‘wild’ (uninitialized) and ‘dangling’
pointers
Ø
Dereferencing (that is * ) a dangling (or NULL) pointer is NOT to be done
Ø
Even if you find that dereferencing a dangling pointer “does not create
problem” in your code, it is still not to be done!
Ø
Result: The OS terminates the code giving
“Segmentation Fault”
int main() {
int *p, i, j, *q;// p,q are dangling
}
p i q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
}
p i q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
}
p I = 10 q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
q = &j; // q not dangling
}
p I = 10 q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
q = &j; // q not dangling
q = (int *)malloc(sizeof(int) * 4);
// q not dangling
}
p I = 10 q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
q = &j; // q not dangling
q = (int *)malloc(sizeof(int) * 4);
// q not dangling
q = q + 3; // q not dangling
}
p I = 10 q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
q = &j; // q not dangling
q = (int *)malloc(sizeof(int) * 4);
// q not dangling
q = q + 3; // q not dangling
q = q + 1; // q IS dangling now
}
p I = 10 q j
Dangling Pointers Example: 1
int main() {
int *p, i, j, *q;// p,q are dangling
p = &i; // p not dangling
i = 10; // *p = 10
q = &j; // q not dangling
q = (int *)malloc(sizeof(int) * 4);
// q not dangling
q = q + 3; // q not dangling
q = q + 1; // q IS dangling now
p = q - 6; // p IS also dangling
}
p I = 10 q j
Dangling Pointers Example: 1
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val
node a;
} next
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
}
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
a.next = (node *)malloc(sizeof(node));
Val
}
next
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
a.next = (node *)malloc(sizeof(node));
a.next->val = 50;
Val=50
}
next
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
a.next = (node *)malloc(sizeof(node));
a.next->val = 50;
Val=50
q = a.next;
} next
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
a.next = (node *)malloc(sizeof(node));
a.next->val = 50;
q = a.next;
free(a.next);
Dangling Pointers Example: 2
typedef struct node { p q
int val;
struct node *next;
}node;
int main() { a
node *p, *q; Val =20
node a;
a.val = 20; next
p = &a;
a.next = (node *)malloc(sizeof(node));
a.next->val = 50;
q = a.next;
free(a.next);
q->val = 100; // segfault
Dangling Pointers Example: 2
Remember
●
Dereferencing a dangling pointer is a cause of
segmentation fault
Dereferencing can occur using * or [ ]
●
●
Having a dangling pointer does not cause
segmentation fault
Dereferencing it causes
●
●
Having dangling pointers is not wrong, but why
have them?
Garbage ●
p was pointing to malloced memory
●
In the end p points to i
Memory ●
How to access the malloced memory now?
●
No way! It's Lost!
int *p, i; ●
It became “garbage memory”
p = malloc ●
Problems like this result in memory waste
●
Also called as Memory leak
(sizeof(int) * 4); ●
Solution
p = &i; Keep another point pointing to malloced
●
memory
i ●
p = malloc(sizeof(int) * 4);
●
q = p;
●
p = &i;
p ●
Malloced memory is available through
0 1 2 3 pointer q
Segmentation Fault
What is segmentation fault?
A program accessing an “illegal” memory location
●
Is punished by the operating system for doing so
●
The program gets “terminated” (killed)
●
●
“segmentation” comes from “memory management” concepts in
operating systems
It is ALWAYS a fault of the programmer!
●
Beware
●
●
Bad compilers may generate machine code which hide some memory
violations
●
If a programmer does illegal memory access, segmentation fault may not
occur sometimes!
–OS may “forgive” your program :-;
Some Typical Reasons for Seg-fault
Deferencing Dangling Pointers
Array Index Violation
Incorrect Function Arguments
Dangling Pointer Dereference: Some
examples int *f(int *p) {
int *p, i;
int x = *p + 2;
*p = 20;
return &x;
int *p, i;
}
p = malloc( sizeof(int)*2);
int main() {
free(p);
int i, *q;
p[2] = 20;
scanf(“%d”, &i);
int *p, i; q = f(&i);
p = &i; *q = 20;
p[1] = 20; }
Don't return address of a local variable! The variable
disappears after function call, and the returned address
is a dangling pointer.
Array Index Violation
Valid indices for an array of size n: 0 .. n-1
Accessing any index <= -1 or >= n may result in seg-fault
(it may not result in some cases, but it is STILL WRONG to do it!)
#include <stdio.h>
Try this code: int main() {
At what value int a[16], i = 0;
of i does the while(1) {
a[i] = i;
code seg-fault? printf("%d\n", a[i]);
Try 2-3 times. i++;
}
}
Reason: OS may allocate more than 16-integer size
memory for the program. So the seg fault may not occur
at index 16 or slightely higher indices also. Rule: wrong to
access index >=n
Functions: Pointer Arguments
●
Rule: When you want a function to change ACTUAL arguments
●
Function takes pointer arguments
●
Call passes address of “actual argument”
●
Example: Swap function (correct code)
void swap(int *a, int *b ) {
●
int temp;
temp = *a;
*a = * b;
*b = temp;
}
int main() {
int m = 20, n = 30;
swap(&m, &n);
}
Incorrect Pointer Aruments -
Segfault
int i;
scanf(“%d”, i);
Scanf tries to do something like
*i = value // seg fault here
Segfault occurs in scanf, although the reason is
call to scanf
●
Note that this is basically a dangling pointer
dereference which took place inside scanf()
Guidelines to avoid segfaults
Always initialize pointers to NULL
●
This will not avoid segfaults, but may lead to early detection of a problem
●
While accessing arrays, make sure that array index is valid
●
Never return address of local variable of a function
●
DO NOT IGNORE compiler's warnings
●
Compilers often warn about potential dangling references, type conversions
●
which have a potential for segfaults
Make sure that you rewrite code to remove all warnings
●
Use “-Wall” option with gcc. > cc -Wall program.c -o program
●
●
gcc -Wall enables all compiler's warning messages. This option should always
be used, in order to generate better code.