Pointer in C/C++
Let's consider a int type variable var.
int var = 10;
So if we print var it will be like :
printf("%d",var);
Output : 10
There is a location in our system memory where every variables are stored when we declare them.
So where is the variable var ?
To print the momory address or location of a variable we have to use unary & operator
print("The memory address of a is %p: ",&a); //%p is used to print a pointer
Output :The memory address of a is : 0x7fffbabdb6f0
The memory address can be different as it takes a random memory address everytime you build your program, but looks like same(0x..........).
Let's declare a pointer :
int *pa; // or int * pa
Note : If you are pointing the pointer at a data type you have to declare it at the declaration of the pointer
Now point Pointer pa at var;
pa = &var;
Now the pointer is pointed at the var variable and it takes the location or memory address of var.
Let's print pa :
printf("%p",pa);
Output : 0x7fffbabdb6f0
Which is same as the memory address of var variable.
We can also print the value of a memory address using unary * operator.This is also called dereferencing
printf("%d",*pa);
Output : 10
Now we can say a Pointer is an object in many programming languages that stores a memory address.
Let's see what happens if we change the value of var.
var = 10001;
printf("Value of var : %d\n",var);
printf("Value of memory address %p is : %d",pa,*pa);
Output :
Value of var : 10001
Value of Memory address 0x7fffbabdb6f0 is : 10001
We can see changing the value of var changes the value of pa memory address.
What if we increase the value of the Pointer pa ? Let's see:
pa++;
printf("Pointer (pa) is pointed to %p and value becomes : %d\n", pa, *pa);
Output :
Pointer (pa) is pointed to 0x7fffbabdb6f8 and value becomes : -1161971980
Here -1161971980 is a gurbage value as nothing is initialized in memory address 0x7fffbabdb6f8
Pointer Expressions and Pointer Arithmetic:
A limited set of arithmetic operations can be performed on pointers. A pointer may be:
- incremented ( ++ )
- decremented ( -- )
- an integer may be added to a pointer ( + or += )
- an integer may be subtracted from a pointer ( – or -= )
Pointer arithmetic is meaningless unless performed on an array.
Note : Pointers contain addresses. Adding two addresses makes no sense, because there is no idea what it would point to. Subtracting two addresses lets you compute the offset between these two addresses.
Pointer in Arrays
Declare an array:
int ar[] = {1, 2, 3, 4, 5};
Declare pointer variable:
int *ptr;
Assign the address of v[0] to ptr
ptr = ar; //We can use ptr=&ar[0];(both are same)
Let's print array elements with thieir memory address :
for (int i = 0; i < 5; i++)
{
printf("Value of *ptr = %d\n", *ptr);
printf("Value of ptr = %p\n", ptr);
// Increment pointer ptr by 1
ptr++;
}
Output :
Value of *ptr = 1
Value of ptr = 0x7fffe4378a30
Value of *ptr = 2
Value of ptr = 0x7fffe4378a34
Value of *ptr = 3
Value of ptr = 0x7fffe4378a38
Value of *ptr = 4
Value of ptr = 0x7fffe4378a3c
Value of *ptr = 5
Value of ptr = 0x7fffe4378a40
We can also use :
for (int i = 0; i < 5; i++)
{
cout<<ptr[i]<<" ";
}
cout<<endl;
Output : 1 2 3 4 5
As an array name acts like a pointer constant. The value of this pointer constant is the address of the first element.
Pointer to pointer
Have you even think that if a variable has a memory address in the memory then what about the pointer we are using to point on the variable?
Yes,a pointer also has a memory address.
int sum =10;
int * psum = &a;
printf("Memory address of variable(sum) : %p\n",psum);
printf("Memory Address of pointer(psum) : %p\n",&psum);
Output :
Memory address of variable(sum) : 0x7ffc3b46638c
Memory Address of pointer(psum) : 0x7ffc3b466398
Let's declare a pointer for a int pointer :3
int **ppsum = &psum; //as ppsum is a pointer of a int type variable's pointer
print the memory address of the pointer :
printf("Memory Address of pointer(psum) : %p\n",ppsum);
Output :
Memory Address of pointer(psum) : 0x7ffc712e6780
Pointer in Structure
Structures are user defined data types.
Let' see a structure
struct Person
{ //structure
int age; //members
float salary;
};
In the Person structure there are two member int type and float type.Person is also a data type here.
So the Person data type also invoke memory and has a memory address.
struct Person p1;
printf("%p",&p1);
Output:
0x7ffebf9ffab0
Let's declare a pointer and point to the structure.
struct Person *p;
p=&p1;
printf("%p",p);
Output:
0x7ffebf9ffab0
We can also use pointer to change values:
p->age = 25; //or *(p).age = 25
p->salary = 2121324.50
Pass by Value
void passByValue(int x){
x = 20;
print("In passByValue function, x = %d\n",x);
}
int main(){
int x = 10;
passByValue(x);
print("In main Function, x = : %d\n",x);
return 0;
}
Output :
In passByValue function, x = 20
In main Function, x = : 10
In this case, x
in passByValue() function and x
in main() function are not same, just the variable names are same but they indicate two different memory locations.
Let's go deeper :3
void passByValue(int x){
cout<<"In passByValue Function : "<<endl;
x = 20;
printf("x = %d\n",x);
cout<<"Memory address of x = "<<&x<<endl;
}
int main(){
int x = 10;
passByValue(x);
cout<<"In main Function : "<<endl;
printf("x = %d\n",x);
cout<<"Memory address of x = "<<&x<<endl;
return 0;
}
Output :
In passByValue Function :
x = 20
Memory address of x = 0x7ffc6c07397c
In main Function :
x = 10
Memory address of x = 0x7ffc6c0739a0
So looking at the outputs we can find that the memory addresses are not same ! The two x
are not same.
Pass by Reference
void passByReference(int *px){
*px = 100;
printf("In passByReference() function, Memory address = %p\n",px);
}
int main(){
int x = 10;
cout<<"(Before) Value of x : "<<x<<endl;
passByReference(&x);
cout<<"(After) Value of x : "<<x<<endl;
cout<<"Memory address of x = "<<&x<<endl;
return 0;
}
Output :
(Before) Value of x : 10
Memory address = 0x7ffe2bd44670
(After) Value of x : 100
Memory address of x = 0x7ffe2bd44670
In pass by reference we are sending the memory address of x
and then in the function we are chnaging the value which is stored in the memory address.
So chaging value of memory address will also chnage the value of a
as it is stored in the memory address.
Dangling Pointers
int* getValue(){
int x;
x=2;
return &x;
}
int main(){
int *px = getValue();
print("Value in memory address(px) = %d\n",*px);
}
Output : Value in memory address(px) = 2
In this case getValue() returns the memory address where x
were stored. After returning memory address x
vanishes but the value in that address remains and after that if we take a variable like
int var3 = 120
there is a huge possibility that var3
can be stored in that memory address which can make problem for you and that is called Dangling Pointer
Dangling pointers arise during object destruction, when an object that has an incoming reference is deleted or deallocated, without modifying the value of the pointer, so that the pointer still points to the memory location of the deallocated memory.
So hare comes the term Dynamic Memory Allocation
Dynamic Memory Allocation
Sections in Memory management:
- Stack
- Heap
- BSS
- Data
- Code
C Dynamic Memory Allocation can be defined as a procedure in which the size of a data structure (like Array) is changed during the runtime.
There are 4 library functions provided by C defined under header file to facilitate dynamic memory allocation in C programming. They are:
- malloc()
- calloc()
- free()
- realloc()
C malloc() method
“malloc” or “memory allocation” method in C is used to dynamically allocate a single large block of memory with the specified size. It returns a pointer of type void which can be cast into a pointer of any form. It initializes each block with default garbage value.
Syntax:
ptr = (cast-type*) malloc(byte-size)
For Example:
int* ptr = (int*) malloc(100 * sizeof(int));
Since the size of int is 4 bytes, this statement will allocate 400 bytes of memory. And, the pointer ptr holds the address of the first byte in the allocated memory.
C free() method
“free” method in C is used to dynamically de-allocate the memory. The memory allocated using functions malloc() and calloc() is not de-allocated on their own. Hence the free() method is used, whenever the dynamic memory allocation takes place. It helps to reduce wastage of memory by freeing it.
free(ptr);
Note:When we declare a pointer it pointed to a random memory address of the memory so better practice is to set them null first
int* px = NULL;
C calloc() method
“calloc” or “contiguous allocation” method in C is used to dynamically allocate the specified number of blocks of memory of the specified type. It initializes each block with a default value ‘0’.
Syntax:
ptr = (cast-type*)calloc(n, element-size);
For Example:
ptr = (float*) calloc(25, sizeof(float));
This statement allocates contiguous space in memory for 25 elements each with the size of the float.
Note:alloc() function allocate n bytes in memory where calloc() function allocate x blocks of y bytes in memory
C realloc() method
“realloc” or “re-allocation” method in C is used to dynamically change the memory allocation of a previously allocated memory.
Syntax:
ptr = realloc(ptr, newSize);
where ptr is reallocated with new size 'newSize'.
int* p = (int*)malloc(n*sizeof(int));
p = realloc(p,n*sizeof(int));
for more Dynamic Memory Allocation and Fragmentation in C and C++
Top comments (9)
This is incorrect.
sizeof (int) is >= 1.
It is not required to be 2 or 4.
(Note that byte in C/C++ is defined to be char, and char may have more than 8 bits).
Unfortunately your understanding of what has happened here is incorrect, and the program only appears to work by accident.
C does not have a flat memory model, and you cannot derive a pointer from a pointer that does not point into or one past the end of the same array, and it is undefined behavior to dereference a pointer one past the end of array.
When you wrote pa++ you derived a pointer value from pa and assigned it back to pa, meaning that it is still indexing the same array, but is now pointing one past the end of the array.
Dereferencing pa at this point has undefined behavior.
By accident, on your implementation, this undefined behavior happened to access another variable, but that's purely accidental.
Good points, but I'd go even further.
It doesn't really index an array, it doesn't know if it points to an array and which array. It just points to a memory address and interprets what is there as an integer - without even having any notion of the array the programmer wanted to point at.
This example starts to get funnier when you declare something right after this array. While that's unspecified where the variable will be stored, you can guess for the sake of the game.
With gcc, it'll read in
d
s values and even though they are doubles, as the pointer is pointing at long values, it will interpret the doubles as longs. After all, in the memory they are just 0s and 1s... (Note that on clang, based on what I saw,d
will have a lower memory address, so the loop will not find it)I think you are inferring an incorrect model of how C works by observing how some popular implementations of C work.
Let's take a look at a freely available draft standard for C.
open-std.org/jtc1/sc22/wg14/www/do...
and
What this means is that:
What you're observing above is undefined behavior -- you may be able to get away with it with particular compilers and architectures, but it isn't how C works. :)
That's perfectly right, we are speaking about two different things. You say that getting from one array to another via pointer arithmetics is undefined behaviour. It is! In fact, that's pretty much I talked about at C++ On Sea earlier this week. Except that, I didn't speak about arrays, but STL containers and not about pointer arithmetics, but iterators.
What I tried to point at here and I see I was not clear enough, is that a pointer or an iterator doesn't know about the container it points at. It only knows the memory address and the type that it is looking for.
Let's take a practical example. We have two containers of the same type,
a
andb
and we have a pointer to eachpa
andpb
. Can you write a function taking the pointers and decide whether the pointers belong to the same array without having any more info available about the arrays?As far as I understand, this is not possible, because the pointers they don't belong to a container. And this doesn't change the fact, that it's the callers responsibility to use the pointer in a sane way not trying to depend on UB. In fact, I find it quite disturbing that the article mentions C++ whereas there is no reason in 2020 to use c-style arrays and pointer arithmetics to iterate over an array...
You cannot introspectively determine this.
Just like you cannot introspectively determine that a pointer has a well defined value, or that a pointer points at allocated memory.
It is not possible because C and C++ do not provide introspective mechanisms to determine this.
However, they do assert that you cannot legitimately derive a pointer to one array from a pointer to another array.
(And as all objects are effectively stored in arrays in C and C++, this is a universal property and applies likewise to the substructure of STL containers, and so on.)
Which means that the association exists, regardless of if it is encoded into the program in a detectable fashion or not.
Just as memory being allocated or not may not be encoded into the program in a detectable fashion.
(For example, consider a compiler which has been able to statically determine all memory allocation your program will perform and so has hard coded every allocation at compile-time.)
The fact that you can't check it doesn't mean that it isn't significant. :)
When i ran the same code in different online compilers I found the same result in case of increment of pointer.
While I usually use coliru for small sketches, if I want to try many compilers with different versions I go to wandbox.
That just means you haven't tried hard enough. :)
Tuming on asan in gcc will do the trick.
You could also try using cint, an interpreter.
Or ...
Thanks for your response and explanation.