1.3 - Review Pointer
1.3 - Review Pointer
1
Data and Memory
• If you remember whenever we declare a variable, it takes an space in
memory
• You can consider a memory like many rows and each row as 8 bit
capacity
• Each row has an address
• If we execute the line: char ch = 'A'
• and the variable ch happened to be stored in memory location 1000, our
picture would look like this:
• …….
1002
1001
1000 Binary of ascii of ‘A’
……
• An integer would be stored over 4 consecutive bytes, and the address of
the variable storing the integer would be the first memory address the
variable was stored in.
2
Pointers
• During the beginning of the semester while we
learned to declare a variable, we also saw how can
we print the address of a variable. We saw it in
Lecture 2 slide number 13:
– printf("Address of basic salary is %p\n", &basic_salary);
• If you declare an integer variable by:
– int x;
– You can use x to store an integer variable
– It has one address in the memory
– If you write x = 5, then 5 is stored in that block of memory.
3
Pointers
• Now, if you want to declare a variable that can store the
address of a variable, then you need a pointer.
• So, pointer is a type of variable, that can store address of
another variable
– While declaring a pointer,
• you have to specify the type of variable (int, float, char, etc.) while declaring a
pointer as different types of variables are stored differently.
– For example, char takes 1 byte, int takes 4 bytes (but one address!)
4
Declaring a Pointer
• So, pointer can hold a memory address.
• Pointer, points to a specific data type.
• Why specific data type? Because different type takes
different size in memory.
• Example of declaring a pointer:
int *p; //You have to put * before the variable
name. Like any uninitialized variable,
here p is pointing to a garbage address as it is not
initialized yet.
- Another example bellow:
int *pointer1 = &x; // Example of both declaration and
initialization in the same line
addr of x int x;
0x2000 1
0x9060
• The above statement also can be written as two lines
• int *pointer1;
• pointer1 = &x;
5
• A pointer has to be declared just like any other variable -
remember a pointer is just a variable that stores an
address. For example,
int *p;
• Here, p is a pointer to an integer. Adding an asterisk in
front of a variable's name declares it to be a pointer to
the declared type. Notice that the asterisk applies only
to the single variable name that it is in front of, so:
int *p , q;
- declares a pointer to an int and an int variable, NOT
two pointers.
The meaning of two new operators: &
and *
• The & operator returns the address of a
variable
For example:
int *p , q;
• declares p, a pointer to int, and q an int and
• The instruction: p=&q;
stores the address of q in p
p
q
addr of q
1
0x2000
0x9060
Operator *
• When you declare a pointer, you have to put *.
However, if you use * with a pointer any time after
declaring it, it has different meaning.
• If place * in front of a pointer variable then the result is
the value stored in the variable pointed at.
• That is, p stores the address, or pointer, to another
variable and *p is the value stored in the variable that p
points at.
• The * operator is called the de-referencing operator and
it helps not to confuse it with multiplication
De-referencing Example
Consider this few lines of codes bellow, It will
print 1: p
q
0x9060
int *p , q; 0x2000
1
0x9060
p=&q;
printf(“%d”, *p); //this will print the value of q
• Why it is printing the value of q?
– Because, we are de-referencing p by writing *p
– The *p in the printf means, the variable it is pointing to. As
p is pointing to q, *p means actually q.
– Now you know the differences between *p in the first line
and *p in the third line
9
Summary of using * and &
• To declare a pointer add an * in front of its
name.
• To obtain the address of a variable use & in
front of its name.
• To obtain the value of a variable use * in
front of a pointer's name.
Example of pointer operation
Now see if you can work out what the following
means:
int *a , b , c;
b = 10;
a = &b;
c = *a;
• Firstly three variables are declared:
– a (a pointer to int),
– and b and c (both standard integers).
• The instruction is a=&b which stores the address of b
in a
• Finally c = *a stores the value in the variable pointed
to by a in c.
– As a points to b, its value i.e. 1O is stored in c
int main() output:
{ Pointer example p1 = 0x7ffce97158f8
p2 = 0x7ffce97158fc
*p1 = -42
*p2 = 163
int x, y;
---------
int *p1, *p2;
p1 = 0x7ffce97158f8 *p1 = 17
x = -42;
---------
y=163;
p1 = 0x7ffce97158fc *p1 = 163
p1 = &x;
---------
p2 = &y; ---------
printf("p1 = %p *p1 = %d \n", p1, *p1); p2 = 0x7ffce97158f8 *p2 = 17
printf("p2 = %p *p2 = %d \n", p2, *p2); p1 = 0x7ffce97158fc *p1 = 17
printf("---------\n"); ---------
p2 = &x;
printf("---------\n");
printf("p2 = %p *p2 = %d \n", p2, *p2);
*p1 = *p2;
printf("p1 = %p *p1 = %d \n", p1, *p1);
printf("---------");
return 0;
12
}
Testing pointer is pointing
something meaningful
• If a pointer is not initialized to any address, dereferencing that pointer
might result in garbage value, or can create segmentation fault/run-
time error as your code is trying to access a memory which is not
allocated to your program. In that case we can use the following
technique to prevent such potential error.
• We can assign NULL to a pointer.
• int *aPtr = NULL;
• It's important not to dereference a null pointer. Doing so will lead to a run-time
error.
• However, before dereferencing we can check it is NULL or not:
– if (aPtr) //it checks if aPtr is not NULL.
{ write statements that can use aPtr as it is safe to do so}
• The above line checks if aPtr is NULL or not.
– You could also write: if (aPtr!= NULL) //this is same as if (aPtr)
• Note that it is programmer’s responsibility to assing NULL values when necessary
13
Why to use pointer
• C programming language WANTED the programmer to
have the ability to directly manipulate memory.
x: 1 x: 2
swap
y: 2 y: 1
15
#include <stdio.h>
Here is our Solution 1
void fakeSwap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 1, y = 2;
fakeSwap(x, y);
printf(“%d %d\n”, x, y);
return 0;
}
16
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
17
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{ tmp:
int tmp; 0x2060
a:
tmp = a; 1 0x2038
a = b;
b:
b = tmp; 2 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
18
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = a; 1 0x2038
a = b;
b:
b = tmp; 2 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
19
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = a; 2 0x2038
a = b;
b:
b = tmp; 2 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
20
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = a; 2 0x2038
a = b;
b:
b = tmp; 1 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
21
#include <stdio.h>
Solution 1
void fakeSwap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
fakeSwap(x, y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
22
#include <stdio.h>
Here is our Solution 2
void trueSwap(int* a, int* b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int x = 1, y = 2;
trueSwap(&x, &y);
printf(“%d %d\n”, x, y);
return 0;
}
23
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
24
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{ tmp:
int tmp; 0x2060
a:
tmp = *a; addr of x 0x2038
*a = *b;
b:
*b = tmp; addr of y 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
25
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = *a; addr of x 0x2038
*a = *b;
b:
*b = tmp; addr of y 0x2040
}
int main()
{
int x = 1, y = 2;
x:
1 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
26
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = *a; addr of x 0x2038
*a = *b;
b:
*b = tmp; addr of y 0x2040
}
int main()
{
int x = 1, y = 2;
x:
2 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
2 0x2010
return 0;
}
27
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{ tmp:
int tmp; 1 0x2060
a:
tmp = *a; addr of x 0x2038
*a = *b;
b:
*b = tmp; addr of y 0x2040
}
int main()
{
int x = 1, y = 2;
x:
2 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
1 0x2010
return 0;
}
28
#include <stdio.h>
Solution 2
void trueSwap(int* a, int* b)
{ So, truSwap
int tmp;
managed to
swap x and y!
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int x = 1, y = 2;
x:
2 0x2000
trueSwap(&x, &y);
printf(“%d %d\n”, x, y); y:
1 0x2010
return 0;
}
29
Call by value and call by reference example conclusion
30
Pointer of Pointer
• The concept of pointers can be further
extended.
• Pointer, we know is a variable that contains
address of another variable.
• Now this variable itself might be another
pointer.
• Thus, we now have a pointer that contains
another pointer’s address.
• The following example should make this point
clear.
31
int main( )
{
int i = 3, *j, **k ;
j = &i ;
k = &j ;// K has the capability to hold address of pointer
printf ( "\nAddress of i = %u", &i ) ; //print address of i
printf ( "\nAddress of i = %u", j ) ; //print address of i
printf ( "\nAddress of i = %u", *k ) ; //print address of i
printf ( "\nAddress of j = %u", &j ) ; //print address of j
printf ( "\nAddress of j = %u", k ) ; //print address of j
printf ( "\nAddress of k = %u", &k ) ; //print address of k
printf ( "\nValue of j = %u", j ) ; //print value of j, which is address of i
printf ( "\nValue of k = %u", k ) ; //print value of k, which is address of j
printf ( "\nValue of i = %d", i ) ; //print 3
printf ( "\nValue of i = %d", * ( &i ) ) ; //print 3
printf ( "\nValue of i = %d", *j ) ; //print print 3
printf ( "\nValue of i = %d", **k ) ; //print 3. As *k = j, and *j = i, i=3
return 0;
}
//output:
Address of i = 178371580
Address of i = 178371580 i j k
Address of i = 178371580
Address of j = 178371584 178371580 178371584
Address of j = 178371584 3
Address of k = 178371592
Value of j = 178371580 178371580 178371584 178371592
Value of k = 178371584
Value of i = 3
Value of i = 3
Value of i = 3 32
Value of i = 3
Pointers and Arrays
int array[size];
int* pPtr = array + i; //let’s say i is an index of the array
34
Basic Pointer Arithmetic
0x2008 0x200C 0x2010 0x2014 0x2018
array:
0x2008
0 1 2 3 4
pPtr: qPtr:
float array[5];
float* pPtr = array;
float* qPtr = NULL;
35
0x2008 0x200C 0x2010 0x2014 0x2018
array:
0x2008
0 1 2 3 4
pPtr: qPtr:
float array[5];
float* pPtr = array;
float* qPtr = NULL;
36
0x2008 0x200C 0x2010 0x2014 0x2018
array:
0x2008
0 1 2 3 4
pPtr: qPtr:
float array[5];
float* pPtr = array;
float* qPtr = NULL;
37
0x2008 0x200C 0x2010 0x2014 0x2018
array:
0x2008
0 1 2 3 4
pPtr: qPtr:
float array[5];
float* pPtr = array;
float* qPtr = NULL;
0x2008
0 1 2 3 4
pPtr: qPtr:
float array[5];
float* pPtr = array;
float* qPtr = NULL;
printf("--------using p-------------\n");
p = data; // p is now &data[0]
for(i = 0; i<5; i++)
{
printf("address: %p, value: %d \n", p, *p);
p++;
} output:
address: 0x7ffd8ec91e10, value: 87, test: 87
address: 0x7ffd8ec91e14, value: 99, test: 88
return 0; address: 0x7ffd8ec91e18, value: 75, test: 89
} address: 0x7ffd8ec91e1c, value: 88, test: 90
The values of address: 0x7ffd8ec91e20, value: 93, test: 91
the array also --------using p-------------
address: 0x7ffd8ec91e10, value: 87 It is just adding i to
can be accessed data[0].
using: address: 0x7ffd8ec91e14, value: 99
address: 0x7ffd8ec91e18, value: 75 *data is dereferencing
data[i] data (which is &data[0])
*(i+data) address: 0x7ffd8ec91e1c, value: 88
40
i[data] address: 0x7ffd8ec91e20, value: 93
What is the difference between
pointer and array?
• While double values[10]; allocates 10
locations to store doubles, double *p; does
not.
• Instead double *p; only allocates the
memory to store a single location in memory.
• However, we CAN use a pointer to
dynamically allocate memory, that we will
learn later in the semester (if we get time).
41
Passing Entire Array to Function
main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i;
printf("Original Array: ");
for(i=0; i<6; i++)
printf("%d ", num[i]);
incBy2( num, 6 ) ;
incBy2( num, 6 ) ;
Colum 0 Column 1
Row 0 grid[0][0] grid[0][1]
Row 1 grid[1][0] grid[1][1]
Row 2 grid[2][0] grid[2][1]
Row 3 grid[3][0] grid[3][1]
44
Multidimensional Arrays with Pointers
• The declaration int grid[4][2]; can also be
interpreted as:
• This is an array of 4 elements
– Each element is an array of 2 elements
• So, it is kind of 4 one-dimensional arrays.
• Example: grid[0] is an array of 2 elements
– grid[0][0], and grid[0][1]
• The elements are laid out sequentially in
memory, just like a one-dimensional array
45
Multidimensional Arrays
Index grid[0][0] grid[0][1] grid[1][0] grid[1][1] grid[2][0] grid[2][1] grid[3][0] grid[3][1]
Value 5 6 8 23 22 9 90 4
address 1000 1004 1008 1012 1016 1020 1024 1028
46
2D Array is an array of array
main( )
{
int grid[4][2] = {
{ 5, 6 },
{ 8, 23 },
{ 22, 9 },
{ 90, 4 }
} ;
int i ;
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\nAddress of %d th 1-D array = %u", i, grid[i] ) ;
}
Output:
Address of 0 th 1-D array = 2961709872
Address of 1 th 1-D array = 2961709880
Address of 2 th 1-D array = 2961709888
Address of 3 th 1-D array = 2961709896
48
Accessing 2D array using pointer
main( )
{
int s[4][2] = {
{ 5, 6 },
{ 8, 23 },
{ 22, 9 },
{ 90, 4 }
} ;
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{
printf ( "\n" ) ;
for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( *( s + i ) + j ) ) ;
}
}
Output:
5 6
8 23
22 9
90 4
49
2D array as parameter
• Only first subscript may be left unspecified
• void f1(int grid[][10]) // valid
• void f3(int grid[][]); //invalid
• Generally, array sizes are also passed to functions while
dealing with 1D or multi dimensional array
• void print( int a[ ][4], int row, int col )
• The sizes allow to iterate properly and access the elements
within the ranges.
50
main( )
Accessing 2D array using pointer
{ print ( int q[ ][4], int row, int col )
int a[3][4] = { {
1, 2, 3, 4, int i, j ;
5, 6, 7, 8, for ( i = 0 ; i < row ; i++ )
9, 0, 1, 6 {
} ; for ( j = 0 ; j < col ; j++ )
printf ( "%d ", q[i][j] ) ;
display ( a, 3, 4 ) ; printf ( "\n" ) ;
print ( a, 3, 4 ) ; }
} printf ( "\n" ) ;
}
display ( int *q, int row, int col )
{
int i, j ;
for ( i = 0 ; i < row ; i++ )
{
for ( j = 0 ; j < col ; j++ )
printf("%d ",*(q+i*col+j));
printf ( "\n" ) ;
}
printf ("\n" ) ;
}
51
52