SlideShare a Scribd company logo
Multilevel Pointers
Advanced C
Pointers – Multilevel
●
A pointer, pointing to another pointer which can be pointing to
others pointers and so on is know as multilevel pointers.
●
We can have any level of pointers.
●
As the depth of the level increase we have to bit careful while
dealing with it.
Advanced C
Pointers – Multilevel
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
101000
num
001_example.c
Advanced C
Pointers – Multilevel
101000
num
10002000
ptr1
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
20003000
ptr2
10002000
ptr1
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
30004000
ptr3
20003000
ptr2
10002000
ptr1
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
30004000
ptr3
20003000
ptr2
10002000
ptr1
Output 3000→
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
30004000
ptr3
20003000
ptr2
10002000
ptr1
Output 2000→
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
30004000
ptr3
20003000
ptr2
10002000
ptr1
Output 1000→
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Pointers – Multilevel
101000
num
30004000
ptr3
20003000
ptr2
10002000
ptr1
Output 10→
#include <stdio.h>
int main()
{
int num = 10;
int *ptr1 = &num;
int **ptr2 = &ptr1;
int ***ptr3 = &ptr2;
printf(“%d”, ptr3);
printf(“%d”, *ptr3);
printf(“%d”, **ptr3);
printf(“%d”, ***ptr3);
return 0;
}
001_example.c
Advanced C
Arrays – Interpretations
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
return 0;
}
1
2
3
4
5
a
One big
variable
Pointer to
the first
small variable
While
assigning to
pointer
While
passing to
functions
While
using with
sizeof()
While
pointer
arithmetic
on &array
Example
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a);
printf(“%pn”, &a[0]);
printf(“%pn”, &a);
return 0;
}
002_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a);
printf(“%pn”, &a[0]);
printf(“%pn”, &a);
return 0;
}
002_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a);
printf(“%pn”, &a[0]);
printf(“%pn”, &a);
return 0;
}
002_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a + 1);
printf(“%pn”, &a[0] + 1);
printf(“%pn”, &a + 1);
return 0;
}
003_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a + 1);
printf(“%pn”, &a[0] + 1);
printf(“%pn”, &a + 1);
return 0;
}
003_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a + 1);
printf(“%pn”, &a[0] + 1);
printf(“%pn”, &a + 1);
return 0;
}
003_example.c
Advanced C
Arrays – Interpretations
1
2
3
4
5
a
1000
1004
1008
1012
1016
?
1020
⋮
1036
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf(“%pn”, a + 1);
printf(“%pn”, &a[0] + 1);
printf(“%pn”, &a + 1);
return 0;
}
003_example.c
Advanced C
Arrays – Interpretations
●
So in summary, if we try to print the address of a[]
– a – prints the value of the constant pointer
– &a[0] – prints the address of the first element pointed
by a
– &a – prints the address of the whole array which
pointed by a
●
Hence all the lines will print 1000 as output
●
These concepts plays a very important role in multi
dimension arrays
Advanced C
Arrays
Advanced C
Arrays – 2D
●
Find the broken eggs!
●
Hmm, how should I
proceed with count??
Advanced C
Arrays – 2D
●
Now is it better to tell
which one broken??
C1 C2 C3 C4 C5
R1
R2
R3
R4
R5
R6
Advanced C
Arrays – 2D
●
So in matrix method it
becomes bit easy to locate
items
●
In other terms we can
reference the location with
easy indexing
●
In this case we can say the
broken eggs are at
R2-C4 and R4-C3
or
C4-R2 and C3-R4
C1 C2 C3 C4 C5
R1
R2
R3
R4
R5
R6
●
The matrix in computer memory is a bit tricky!!
●
Why?. Since its a sequence of memory
●
So pragmatically, it is a concept of dimensions is
generally referred
●
The next slide illustrates the expectation and the
reality of the memory layout of the data in a system
Advanced C
Arrays – 2D
Advanced C
Arrays – 2D
R1
R2
R3
R0
C1 C2 C3C0
201 101 187 22
123 9 234 39
23 155 33 2
100 88 8 111
1231001
91002
2341003
391004
231005
1551006
331007
21008
1001009
881010
81011
1111012
2011013
1011014
1871015
221016
Concept Illustration System Memory
Advanced C
Arrays - 2D
Syntax
data_type name[ROW][COL];
Where ROW * COL represents number of elements
Memory occupied by array = (number of elements * size of an element)
= (ROW * COL * <size of data_type>)
Example
int a[2][3] = {{10, 20, 30}, {40, 50, 60}};
10 20 30 40 50
R0 - C0
R0 - C1
R0 - C2
R1 - C0
R1 - C1
baseaddr
baseaddr+4
baseaddr+8
baseaddr+12
baseaddr+16
60
R1 - C2
baseaddr+20
Advanced C
Arrays – 2D - Referencing
2 * 1D array linearly
placed in memory
[0]
[2]
[1]
[0]
[1]
[2]
Index to access the
1D array
[1]
[0]
[0]
[0]
[1]
[1]
2nd
1D Array with base address 1012
a[1] = &a[1][0] = a + 1 1012→
1st
1D Array with base address 1000
a[0] = &a[0][0] = a + 0 1000→
401012
301008
201004
101000
501016
601020
a
1DArray1DArray
Core Principle
●
Dereferencing nth - dimensional array will return (n - 1)th
-dimensional array
– Example : dereferencing 2D array will return 1D array
●
Dereferencing 1D array will return 'data element'
– Example : Dereferencing 1D integer array will return
integer
Advanced C
Arrays – 2D - Dereferencing
Array Dimension
&a n + 1
a n
*a n - 1
Advanced C
Arrays – 2D - Dereferencing
2 * 1D array linearly
placed in memory
[0]
[2]
[1]
[0]
[1]
[2]
Index to access the
1D array
[1]
[0]
[0]
[0]
[1]
[1]
401012
301008
201004
101000
501016
601020
a
1DArray1DArray
Example 1: Say a[0][1] is to be accessed, then
decomposition happens like,
a[0][1] =
= *(a[0] + (1 * sizeof(type)))
= *(*(a + (0 * sizeof(1D array))) + (1 * sizeof(type)))
= *(*(a + (0 * 12)) + (1 * 4))
= *(*(a + 0) + 4)
= *(*a + 0 + 4)
= *(*a + 4)
= *(1000 + 4)
= *(1004))
a[0][1] =
= *(a[0] + (1 * sizeof(type)))
= 20
Advanced C
Arrays – 2D - Dereferencing
2 * 1D array linearly
placed in memory
[0]
[2]
[1]
[0]
[1]
[2]
Index to access the
1D array
[1]
[0]
[0]
[0]
[1]
[1]
401012
301008
201004
101000
501016
601020
a
1DArray1DArray
Example 1: Say a[1][1] is to be accessed, then
decomposition happens like,
a[1][1] =
= *(a[1] + (1 * sizeof(type)))
= *(*(a + (1 * sizeof(1D array))) + (1 * sizeof(type)))
= *(*(a + (1 * 12)) + (1 * 4))
= *(*(a + 12) + 4)
= *(*a + 12 + 4)
= *(*a + 16)
= *(1000 + 16)
= *(1016)
a[1][1] =
= *(a[1] + (1 * sizeof(type)))
= 50
Address of a[r][c] = value(a) + r * sizeof(1D array) + c * sizeof(type)
Advanced C
Arrays – 2D - DIY
●
WAP to find the MIN and MAX of a 2D array
Advanced C
Pointers – Array of pointers
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3];
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
return 0;
}
Synatx
004_example.c
101000
a
201004
b
301008
c
Advanced C
Pointers – Array of pointers
?
?
?
4000
4004
4008
ptr
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3];
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
return 0;
}
Synatx
004_example.c
101000
a
201004
b
301008
c
Advanced C
Pointers – Array of pointers
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3];
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
return 0;
}
Synatx
004_example.c
101000
a
201004
b
301008
c
1000
1004
1008
4000
4004
4008
ptr
Advanced C
Pointers – Array of pointers
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a[2] = {10, 20};
int b[2] = {30, 40};
int c[2] = {50, 60};
int *ptr[3];
ptr[0] = a;
ptr[1] = b;
ptr[2] = c;
return 0;
}
Synatx
005_example.c
10
1000
a
30
1008
b
50
1016
c
20
1004
40
1012
60
1020
Advanced C
Pointers – Array of pointers
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a[2] = {10, 20};
int b[2] = {30, 40};
int c[2] = {50, 60};
int *ptr[3];
ptr[0] = a;
ptr[1] = b;
ptr[2] = c;
return 0;
}
Synatx
005_example.c
10
1000
a
30
1008
b
50
1016
c
20
1004
40
1012
60
1020
?
?
?
4000
4004
4008
ptr
Advanced C
Pointers – Array of pointers
datatype *ptr_name[SIZE]
#include <stdio.h>
int main()
{
int a[2] = {10, 20};
int b[2] = {30, 40};
int c[2] = {50, 60};
int *ptr[3];
ptr[0] = a;
ptr[1] = b;
ptr[2] = c;
return 0;
}
Synatx
005_example.c
10
1000
a
30
1008
b
50
1016
c
20
1004
40
1012
60
1020
1000
1008
1016
4000
4004
4008
ptr
Advanced C
Pointers – Array of pointers
#include <stdio.h>
void print_array(int **p)
{
int i;
for (i = 0; i < 3; i++)
{
printf(“%d ”, *p[i]);
printf(“at %pn”, p[i]);
}
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3] = {&a, &b, &c};
print_array(ptr);
return 0;
}
006_example.c
101000
a
201004
b
301008
c
Advanced C
Pointers – Array of pointers
#include <stdio.h>
void print_array(int **p)
{
int i;
for (i = 0; i < 3; i++)
{
printf(“%d ”, *p[i]);
printf(“at %pn”, p[i]);
}
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3] = {&a, &b, &c};
print_array(ptr);
return 0;
}
006_example.c
101000
a
201004
b
301008
c
1000
1004
1008
4000
4004
4008
ptr
Advanced C
Pointers – Array of pointers
#include <stdio.h>
void print_array(int **p)
{
int i;
for (i = 0; i < 3; i++)
{
printf(“%d ”, *p[i]);
printf(“at %pn”, p[i]);
}
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3] = {&a, &b, &c};
print_array(ptr);
return 0;
}
006_example.c
101000
a
201004
b
301008
c
1000
1004
1008
4000
4004
4008
ptr
#include <stdio.h>
void print_array(int **p)
{
int i;
for (i = 0; i < 3; i++)
{
printf(“%d ”, *p[i]);
printf(“at %pn”, p[i]);
}
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
int *ptr[3] = {&a, &b, &c};
print_array(ptr);
return 0;
}
Advanced C
Pointers – Array of pointers
006_example.c
101000
a
201004
b
301008
c
1000
1004
1008
4000
4004
4008
ptr
4000
p
5000
Advanced C
Pointers – Array of strings
#include <stdio.h>
int main()
{
char s[3][8] = {
“Array”,
“of”,
“Strings”
};
printf(“%s %s %sn”, s[0], s[1], s[2]);
return 0;
}
s
'A'
'r'
'r'
'a'
'y'
'0'
'o'
'f'
'0'
'S'
't'
'r'
'i'
'n'
'g'
's'
'0'
?
?
?
?
?
?
?
1000
1001
1002
1003
1004
1005
1011
1012
1021
1022
1023
1006
1007
1008
1009
1013
1014
1015
1016
1017
1018
1019
1010
1020
s
0x41
0x72
0x72
0x61
0x79
0x00
0x6F
0x66
0x00
0x53
0x74
0x72
0x69
0x6E
0x67
0x73
0x00
?
?
?
?
?
?
?
1000
1001
1002
1003
1004
1005
1011
1012
1021
1022
1023
1006
1007
1008
1009
1013
1014
1015
1016
1017
1018
1019
1010
1020
007_example.c
Advanced C
Pointers – Array of strings
#include <stdio.h>
int main()
{
char *s[3];
s[0] = “Array”;
s[1] = “of”;
s[2] = “Strings”;
printf(“%s %s %sn”, s[0], s[1], s[2]);
return 0;
}
? ? ?
4000 4004 4008
s
008_example.c
Advanced C
Pointers – Array of strings
1000 ? ?
4000 4004 4008
s
'A'
'r'
'r'
'a'
'y'
'0'
1000
1001
1002
1003
1004
1005
#include <stdio.h>
int main()
{
char *s[3];
s[0] = “Array”;
s[1] = “of”;
s[2] = “Strings”;
printf(“%s %s %sn”, s[0], s[1], s[2]);
return 0;
}
008_example.c
Advanced C
Pointers – Array of strings
1000 1010 ?
4000 4004 4008
s
'A'
'r'
'r'
'a'
'y'
'0'
'o'
'f'
'0'
1000
1001
1002
1003
1004
1005
1010
1011
1012
#include <stdio.h>
int main()
{
char *s[3];
s[0] = “Array”;
s[1] = “of”;
s[2] = “Strings”;
printf(“%s %s %sn”, s[0], s[1], s[2]);
return 0;
}
008_example.c
Advanced C
Pointers – Array of strings
1000 1010 1020
4000 4004 4008
s
'A'
'r'
'r'
'a'
'y'
'0'
'o'
'f'
'0'
'S'
't'
'r'
'i'
'n'
'g'
's'
'0'
1000
1001
1002
1003
1004
1005
1010
1011
1012
1020
1021
1022
1023
1024
1025
1026
1027
#include <stdio.h>
int main()
{
char *s[3];
s[0] = “Array”;
s[1] = “of”;
s[2] = “Strings”;
printf(“%s %s %sn”, s[0], s[1], s[2]);
return 0;
}
008_example.c
Advanced C
Pointers – Array of strings
●
W.A.P to print menu and select an option
– Menu options { File, Edit, View, Insert, Help }
●
The prototype of print_menu function
– void print_menu (char **menu);
user@user:~]
user@user:~]./a.out
1. File
2. Edit
3. View
4. Insert
5. Help
Select your option: 2
You have selected Edit Menu
user@user:~]
Screen Shot
Advanced C
Pointers – Array of strings
●
Command line arguments
– Refer to PPT “11_functions_part2”
Advanced C
Pointers – Pointer to an Array
●
Pointer to an array!!, why is
the syntax so weird??
●
Isn't the code shown left is an
example for pointer to an
array?
●
Should the code print as 1 in
output?
●
Yes, everything is fine here
except the dimension of the
array.
●
This is perfect code for 1D
array
datatype (*ptr_name)[SIZE];
int main()
{
int array[3] = {1, 2, 3};
int *ptr;
ptr = array;
printf(“%dn”, *ptr);
return 0;
}
Syntax
009_example.c
Advanced C
Pointers – Pointer to an Array
●
So in order to point to 2D
array we would prefer the
given syntax
●
Ookay, Isn't a 2D array
linearly arranged in the
memory?
So can I write the code as
shown?
●
Hmm!, Yes but the compiler
would warn you on the
assignment statement
●
Then how should I write?
datatype (*ptr_name)[SIZE];
int main()
{
int array[3] = {1, 2, 3};
int (*ptr)[3];
ptr = array;
printf(“%dn”, **ptr);
return 0;
}
Syntax
010_example.c
Advanced C
Pointers – Pointer to an Array
●
Hhoho, isn't array is equal to
&array?? what is the
difference?
●
Well the difference lies in the
compiler interpretation while
pointer arithmetic and hence
●
Please see the difference in
the next slides
datatype (*ptr_name)[SIZE];
int main()
{
int array[3] = {1, 2, 3};
int (*ptr)[3];
ptr = &array;
printf(“%dn”, **ptr);
return 0;
}
Syntax
011_example.c
Advanced C
Pointers – Pointer to an Array
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
?
p1
2000
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
?
p1
2000
?
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
1000
p1
2000
?
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
1000
p1
2000
1000
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
1000
p1
2000
1000
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
1000
p1
2000
1000
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
?
?
?
?
?
?
?1036
array
1000
p1
2000
1000
2004
p2
int main()
{
int array[3] = {1, 2, 3};
int *p1;
int (*p2)[3];
p1 = array;
p2 = &array;
printf(“%p %pn”, p1 + 0, p2 + 0);
printf(“%p %pn”, p1 + 1, p2 + 1);
printf(“%p %pn”, p1 + 2, p2 + 2);
return 0;
}
012_example.c
Advanced C
Pointers – Pointer to an Array
●
So as a conclution we can say the
●
Pointer arithmetic on 1D array is based on the size of
datatype
●
Pointer arithmetic on 2D array is based on the size of
datatype and size of 1D array
●
Still one question remains is what is real use of this
syntax if can do p[i][j]?
●
In case of dynamic memory allocation as shown in next
slide
Advanced C
Pointers – Pointer to an Array
?
p
2000
int main()
{
int (*p)[3];
p = malloc(sizeof(*p) * 3);
(*(p + 0))[0] = 1;
(*(p + 1))[1] = 2;
(*(p + 2))[2] = 3;
printf(“%dn”, p[0][0]);
printf(“%dn”, p[1][1]);
printf(“%dn”, p[2][2]);
return 0;
}
013_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
?
?
?
?
?
?
?
?
?
?1036
1000
p
2000
int main()
{
int (*p)[3];
p = malloc(sizeof(*p) * 3);
(*(p + 0))[0] = 1;
(*(p + 1))[1] = 2;
(*(p + 2))[2] = 3;
printf(“%dn”, p[0][0]);
printf(“%dn”, p[1][1]);
printf(“%dn”, p[2][2]);
return 0;
}
013_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
?
?
?
?
?
?
?
?
?1036
1000
p
2000
int main()
{
int (*p)[3];
p = malloc(sizeof(*p) * 3);
(*(p + 0))[0] = 1;
(*(p + 1))[1] = 2;
(*(p + 2))[2] = 3;
printf(“%dn”, p[0][0]);
printf(“%dn”, p[1][1]);
printf(“%dn”, p[2][2]);
return 0;
}
013_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
?
?
?
2
?
?
?
?
?1036
1000
p
2000
int main()
{
int (*p)[3];
p = malloc(sizeof(*p) * 3);
(*(p + 0))[0] = 1;
(*(p + 1))[1] = 2;
(*(p + 2))[2] = 3;
printf(“%dn”, p[0][0]);
printf(“%dn”, p[1][1]);
printf(“%dn”, p[2][2]);
return 0;
}
013_example.c
Advanced C
Pointers – Pointer to an Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
?
?
?
2
?
?
?
3
?1036
1000
p
2000
int main()
{
int (*p)[3];
p = malloc(sizeof(*p) * 3);
(*(p + 0))[0] = 1;
(*(p + 1))[1] = 2;
(*(p + 2))[2] = 3;
printf(“%dn”, p[0][0]);
printf(“%dn”, p[1][1]);
printf(“%dn”, p[2][2]);
return 0;
}
013_example.c
int main()
{
int (*p)[3];
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
p = a;
return 0;
}
Advanced C
Pointers – Pointer to an 2D Array
1000
p
2000
014_example.c
Advanced C
Pointers – Pointer to an 2D Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
1000
p
2000
a
int main()
{
int (*p)[3];
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
p = a;
return 0;
}
014_example.c
Advanced C
Pointers – Pointer to an 2D Array
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
1000
p
2000
a
int main()
{
int (*p)[3];
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
p = a;
return 0;
}
014_example.c
#include <stdio.h>
void print_array(int p[2][3])
{
int i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
printf(“%dn”, p[i][j]);
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(a);
return 0;
}
Advanced C
Pointers – Passing 2D array to function
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
a
015_example.c
Advanced C
Pointers – Passing 2D array to function
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
a
1000
p
2000
#include <stdio.h>
void print_array(int p[2][3])
{
int i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
printf(“%dn”, p[i][j]);
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(a);
return 0;
}
015_example.c
#include <stdio.h>
void print_array(int (*p)[3])
{
int i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
printf(“%dn”, p[i][j]);
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(a);
return 0;
}
Advanced C
Pointers – Passing 2D array to function
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
a
016_example.c
Advanced C
Pointers – Passing 2D array to function
1000
1004
1008
1012
1016
1020
1024
1028
1032
1
2
3
4
5
6
?
?
?
?1036
a
1000
p
2000
#include <stdio.h>
void print_array(int (*p)[3])
{
int i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
printf(“%dn”, p[i][j]);
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(a);
return 0;
}
016_example.c
Advanced C
Pointers – Passing 2D array to function
#include <stdio.h>
void print_array(int row, int col, int (*p)[col])
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(“%dn”, p[i][j]);
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(2, 3, a);
return 0;
}
017_example.c
Advanced C
Pointers – Passing 2D array to function
#include <stdio.h>
void print_array(int row, int col, int *p)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(“%dn”, *((p + i * col) + j));
}
}
}
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_array(2, 3, (int *) a);
return 0;
}
018_example.c
Advanced C
Pointers – 2D Array Creations
●
Each Dimension could be Static or Dynamic
●
Possible combination of creation could be
– BS: Both Static (Rectangular)
– FSSD: First Static, Second Dynamic
– FDSS: First Dynamic, Second Static
– BD: Both Dynamic
Advanced C
Pointers – 2D Array Creations - BS
#include <stdio.h>
int main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
return 0;
}
●
Both Static (BS)
●
Called as an rectangular
array
●
Total size is
2 * 3 * sizeof(datatype)
2 * 3 * 4 = 24 Bytes
●
The memory
representation can be as
shown in next slide
018_example.c
Advanced C
Pointers – 2D Array Creations - BS
1000
1004
1008
1012
1016
1020
1
2
3
4
5
6
a
0 0 0 1
Static
3 Columns
On Stack
Static
2 Rows
On Stack
0 0 0 2 0 0 0 3
0 0 0 4 0 0 0 5 0 0 0 6
Advanced C
Pointers – 2D Array Creations - FSSD
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a[2];
for ( i = 0; i < 2; i++)
{
a[i] = malloc(3 * sizeof(int));
}
return 0;
}
●
First Static and Second
Dynamic (FSSD)
●
Mix of Rectangular &
Ragged
●
Total size is
2 * sizeof(datatype *) +
2 * 3 * sizeof(datatype)
2 * 4 + 2 * 3 * 4 = 32 Bytes
●
The memory
representation can be as
shown in next slide
019_example.c
Advanced C
Pointers – 2D Array Creations - FSSD
1004
1000
524
512
a
0 0 0 1
Dynamic
3 Columns
On Heap
Static
2 Rows
On Heap
0 0 0 2 0 0 0 3
0 0 0 4 0 0 0 5 0 0 0 6
532
528
524
520
516
512
6
5
4
3
2
1
0 0 A 0
0 0 A C
Pointers to
2 Rows
On Stack
Advanced C
Pointers – 2D Array Creations - FDSS
#include <stdio.h>
#include <stdlib.h>
int main()
{
int (*a)[3];
a = malloc(2 * sizeof(int [3]));
return 0;
}
●
First Dynamic and
Second Static (FDSS)
●
Total size is
sizeof(datatype *) +
2 * 3 * sizeof(datatype)
4 + 2 * 3 * 4 = 28 Bytes
●
The memory
representation can be as
shown in next slide
020_example.c
Advanced C
Pointers – 2D Array Creations - FDSS
1000 512
a
0 0 0 1
Static
3 Columns
On Heap
Dynamic
2 Rows
On Heap
0 0 0 2 0 0 0 3
0 0 0 4 0 0 0 5 0 0 0 4
532
528
524
520
516
512
6
5
4
3
2
1
0 0 A 0
Pointer to
1 Row
On Stack
Advanced C
Pointers – 2D Array Creations - BD
#include <stdio.h>
#include <stdlib.h>
int main()
{
int **a;
int i;
a = malloc(2 * sizeof(int *));
for (i = 0; i < 2; i++)
{
a[i] = malloc(3 * sizeof(int));
}
return 0;
}
●
Both Dynamic (BD)
●
Total size is
sizeof(datatype **) +
2 * sizeof(datatype *) +
2 * 3 * sizeof(datatype)
4 + 2 * 4 + 2 * 3 * 4 = 36
Bytes
●
The memory
representation can be as
shown in next slide
021_example.c
Advanced C
Pointers – 2D Array Creations - BD
0 0 0 1
Dynamic
3 Columns
On Heap
Dynamic
2 Rows
On Heap
0 0 0 2 0 0 0 3
0 0 0 4 0 0 0 5 0 0 0 6
788
784
780
776
772
768
6
5
4
3
2
1
0 0 3 0
0 0 3 C
Pointers to
2 Rows
On Heap
516
512
780
768
1004 512
a
0 0 A 0
Pointer to
1 Row
On Stack
Advanced Functions
Command Line Arguments
Advanced C
Functions – Command Line Arguments
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
return 0;
}
Example
Passed Arguments on CL
Arguments Count
Environmental Variables
user@user:~] ./a.out 5 + 3
Usage
4th
argument
3rd
argument
2nd
argument
1st
argument
All stored in argv
Total counts of the args stored
in argc
Advanced C
Functions – Command Line Arguments
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
printf(“No of argument(s): %dn”, argc);
printf(“List of argument(s):n”);
for (i = 0; i < argc; i++)
{
printf(“t%d - ”%s”n”, i + 1, argv[i]);
}
return 0;
}
001_example.c
Advanced C
Functions – Command Line Arguments
Stack
Text Segment
Initialized
Heap
.BSS
(Uninitialized
)
Command Line
Arguments
Hole
Data
Segment
Memory Segments
1000
1004
1008
4000
4100
4200
argv
4300 1012
NULL 1016
‘.’ ‘/’ ‘a’ ‘.’ ‘o’ ‘u’ ‘t’ ‘0’
4000
‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘’0’
4100
‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘’0’
4200
‘W’ ‘e’ ‘l’ ‘c’ ‘o’ ‘m’ ‘e’ ‘0’
4300
user@user:~] ./a.out Hello World Welcome
Example
[0]
[1]
[2]
[3]
[4]
[0][0]
[1][0]
[2][0]
[3][0]
Advanced C
Functions – Command Line Arguments - DIY
●
Print all the Environmental Variables
●
WAP to calculate average of numbers passed via
command line
Function Pointer
Advanced C
Functions – Function Pointers
●
A variable that stores the address of a function.
Therefore, points to the function.
Syntax
return_datatype (*foo)(list of argument(s) datatype);
Advanced C
Functions – Function Pointers
#include <stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int main()
{
printf(“%pn”, add);
printf(“%pn”, &add);
return 0;
}
●
Every function code
would be stored in the
text segment with an
address associated with
it
●
This example would print
the address of the add
function
002_example.c
Advanced C
Functions – Function Pointers
●
Hold on!!. Can't I store
the address on the
normal pointer??
●
Well, Yes you can! But
how would you expect
the compiler to interpret
this?
●
The compiler interprets
this as a pointer to
normal variable and not
the code
●
Then how to do it?
#include <stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int main()
{
int *fptr;
fptr = add;
printf(“%pn”, add);
printf(“%pn”, fptr);
printf(“%pn”, &fptr);
return 0;
}
003_example.c
Advanced C
Functions – Function Pointers
●
The address of the
function should be stored
in a function pointer
●
Not to forget that the
function pointer is a
variable and would have
address for itself
#include <stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int main()
{
int (*fptr)(int, int);
fptr = add;
printf(“%pn”, add);
printf(“%pn”, fptr);
printf(“%pn”, &fptr);
return 0;
}
004_example.c
Advanced C
Functions – Function Pointers
●
The function pointer
could be invoked as
shown in the example
#include <stdio.h>
int add(int num1, int num2)
{
return num1 + num2;
}
int main()
{
int (*fptr)(int, int);
fptr = add;
printf(“%dn”, fptr(2, 4));
printf(“%dn”, (*fptr)(2, 4));
return 0;
}
005_example.c
Advanced C
Functions – Func Ptr – Passing to functions
int add(int num1, int num2)
{
return num1 + num2;
}
int sub(int num1, int num2)
{
return num1 - num2;
}
int oper(int (*f)(int, int), int a, int b)
{
return f(a, b);
}
006_example.c
Advanced C
Functions – Array of Function Pointers
007_example.c
Advanced C
Functions – Array of Function Pointers
008_example.c
int add(int num1, int num2)
{
return num1 + num2;
}
int sub(int num1, int num2)
{
return num1 - num2;
}
int oper(int (*f)(int, int), int a, int b)
{
return f(a, b);
}
Advanced C
Functions – Func Ptr – Std Functions - atexit()
009_example.c
void my_exit(void)
{
printf(“Exiting programn”);
if (ptr)
{
/* Deallocation in my_exit */
free(ptr);
}
}
void test(void)
{
puts(“In test”);
exit(0);
}
Advanced C
Functions – Func Ptr – Std Functions - qsort()
010_example.c
int sa(const void *a, const void *b)
{
return *(int *) a > *(int *) b;
}
int sd(const void *a, const void *b)
{
return *(int *) a < *(int *) b;
}
void print(int *a, unsigned int size)
{
int i = 0;
for (i = 0; i < size; i++)
{
printf(“%d ”, a[i]);
}
printf(“n”);
}
Variadic Functions
Advanced C
Functions – Variadic
●
Variadic functions can be called with any number of
trailing arguments
●
For example,
printf(), scanf() are common variadic functions
●
Variadic functions can be called in the usual way with
individual arguments
Syntax
return_data_type function_name(parameter list, ...);
Advanced C
Functions – Variadic – Definition & Usage
●
Defining and using a variadic function involves three steps:
Step 1: Variadic functions are defined using an ellipsis (‘…’) in
the argument list, and using special macros to access the
variable arguments.
Step 2: Declare the function as variadic, using a prototype
with an ellipsis (‘…’), in all the files which call it.
Step 3: Call the function by writing the fixed arguments
followed by the additional variable arguments.
int foo(int a, ...)
{
/* Function Body */
}
Example
Advanced C
Functions – Variadic – Argument access macros
●
Descriptions of the macros used to retrieve variable
arguments
●
These macros are defined in the header file stdarg.h
Type/Macros Description
va_list The type va_list is used for argument pointer variables
va_start This macro initializes the argument pointer variable ap to point to
the first of the optional arguments of the current function; last-
required must be the last required argument to the function
va_arg The va_arg macro returns the value of the next optional argument,
and modifies the value of ap to point to the subsequent argument.
Thus, successive uses of va_arg return successive optional
arguments
va_end This ends the use of ap
Advanced C
Functions – Variadic – Example
011_example.c
int add(int count, ...)
{
va_list ap;
int iter, sum;
/* Initilize the arg list */
va_start(ap, count);
sum = 0;
for (iter = 0; iter < count; iter++)
{
/* Extract args */
sum += va_arg(ap, int);
}
/* Cleanup */
va_end(ap);
return sum;
}
Preprocessing
Advanced C
Preprocessor
●
One of the step performed before compilation
●
Is a text substitution tool and it instructs the compiler to
do required pre-processing before the actual compilation
●
Instructions given to preprocessor are called
preprocessor directives and they begin with “#” symbol
●
Few advantages of using preprocessor directives would
be,
– Easy Development
– Readability
– Portability
Advanced C
Preprocessor – Compilation Stages
●
Before we proceed with preprocessor directive let's try to
understand the stages involved in compilation
●
Some major steps involved in compilation are
– Preprocessing (Textual replacement)
– Compilation (Syntax and Semantic rules checking)
– Assembly (Generate object file(s))
– Linking (Resolve linkages)
●
The next slide provide the flow of these stages
Advanced C
Preprocessor – Compilation Stages
Source Code
Expanded Source
Code
Assembly Source
Code
Object Code
Executable
.cPreprocessor
Compiler
Assembler
Linker
Loader
.i
.s
.o
.out
user@user:~] gcc -E file.c
user@user:~] gcc -S file.c
user@user:~] gcc -c file.c
user@user:~] gcc file.c -o file.out
user@user:~]gcc -save-temps file.c #would generate all intermediate files
Advanced C
Preprocessor – Compilation Steps
.c
.i
.s
user@user:~] cpp file.c -o file.i
user@user:~] cc -S file.i -o file.s
user@user:~] as file.s -o file.o
user@user:~] ld file.o -o file.out <LIBRARY PATH>
user@user:~]./file.out
Bit complex step
.o
.out
Advanced C
Preprocessor – Compilation Steps
.c
.i
.s
user@user:~] gcc -E file.c -o file.i
user@user:~] gcc -S file.i -o file.s
user@user:~] gcc -c file.s -o file.o
.o
.out
user@user:~] gcc file.o -o file.out
user@user:~]./file.out
Advanced C
Preprocessor – Directives
#include
#define
#undef
#ifdef
#ifndef
#if
#elif
#else
#endif
#error
#warning
#line
#pragma
#
##
Advanced C
Preprocessor – Header Files
●
A header file is a file containing C declarations and macro
definitions to be shared between several source files.
●
Has to be included using C preprocessing directive
‘#include'
●
Header files serve two purposes.
– Declare the interfaces to parts of the operating system by
supplying the definitions and declarations you need to
invoke system calls and libraries.
– Your own header files contain declarations for interfaces
between the source files of your program.
Advanced C
Preprocessor – Header Files vs Source Files
.h .cVS
●
Declarations
●
Sharable/reusable
●
#defines
●
Datatypes
●
Used by more than 1
file
●
Function and variable
definitions
●
Non sharable/reusable
●
#defines
●
Datatypes
Advanced C
Preprocessor – Header Files - Syntax
Syntax
#include <file.h> ●
System header files
●
It searches for a file named file
in a standard list of system
directories
Syntax
#include “file.h” ●
Local (your) header files
●
It searches for a file named file
first in the directory containing the
current file, then in the quote
directories and then the same
directories used for <file>
Advanced C
Preprocessor – Header Files - Operation
int num;
#include “003_file2.h”
int main()
{
puts(test());
return 0;
}
char *test(void);
002_file2.c
char *test(void)
{
static char *str = “Hello”;
return str;
}
int num;
char *test(void);
int main()
{
puts(test());
return 0;
}
user@user:~] gcc -E 001_file1.c 002_file2.c # You may add -P option too!!
Compile as
001_file1.c
003_file2.h
Advanced C
Preprocessor – Header Files – Search Path
int num;
#include “003_file2.h”
int main()
{
puts(test());
return 0;
}
char *test(void);char *test(void)
{
static char *str = “Hello”;
return str;
}
user@user:~] gcc -E 001_file1.c 002_file2.c
Compile as
002_file2.c
001_file1.c
003_file2.h
Advanced C
Preprocessor – Header Files – Search Path
int num;
#include <file2.h>
int main()
{
puts(test());
return 0;
}
char *test(void);char *test(void)
{
static char *str = “Hello”;
return str;
}
user@user:~] gcc -E 001_file1.c 002_file2.c -I .
Compile as
002_file2.c
001_file1.c
003_file2.h
Advanced C
Preprocessor – Header Files – Search Path
●
On a normal Unix system GCC by default will look for
headers requested with #include <file> in:
– /usr/local/include
– libdir/gcc/target/version/include
– /usr/target/include
– /usr/include
●
You can add to this list with the -I <dir> command-line option
user@user:~] cpp -v /dev/null -o /dev/null #would show search the path info
Get it as
Advanced C
Preprocessor – Macro – Object-Like
●
An object-like macro is a simple identifier which will be
replaced by a code fragment
●
It is called object-like because it looks like a data object
in code that uses it.
●
They are most commonly used to give symbolic names to
numeric constants
#define SYMBOLIC_NAME CONSTANTS
Syntax
#define BUFFER_SIZE 1024
Example
Advanced C
Preprocessor – Macro – Object-Like
#define SIZE 1024
#define MSG “Enter a string”
int main()
{
char array[SIZE];
printf(“%sn”, MSG);
fgets(array, SIZE, stdin);
printf(“%sn”, array);
return 0;
}
# 1 "main.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.c"
int main()
{
char array[1024];
printf("%sn", “Enter a string”);
fgets(array, 1024, stdin);
printf("%sn", array);
return 0;
}
user@user:~] gcc -E 004_example.c -o 004_example.i
Compile as
004_example.c 004_example.i
Advanced C
Preprocessor – Macro – Standard Predefined
●
Several object-like macros are predefined; you use them
without supplying their definitions.
●
Standard are specified by the relevant language
standards, so they are available with all compilers that
implement those standards
#include <stdio.h>
int main()
{
printf(“Program: “%s” ”, __FILE__);
printf(“was compiled on %s at %s. ”, __DATE__, __TIME__);
printf(“This print is from Function: ”%s””, __func__);
printf(“at line %dn”, __LINE__);
return 0;
}
005_example.c
Advanced C
Preprocessor – Macro – Arguments
●
Function-like macros can take arguments, just like true
functions
●
To define a macro that uses arguments, you insert
parameters between the pair of parentheses in the macro
definition that make the macro function-like
Syntax
#define MACRO(ARGUMENT(S)) (EXPRESSION WITH ARGUMENT(S))
Advanced C
Preprocessor – Macro – Arguments
#include <stdio.h>
#define SET_BIT(num, pos) num | (1 << pos)
int main()
{
printf(“%dn”, 2 * SET_BIT(0, 2));
return 0;
}
int main()
{
printf(“%dn”, 2 * 0 | (1 << 2));
return 0;
}
006_example.c
006_example.i
Advanced C
Preprocessor – Macro – Arguments
#include <stdio.h>
#define SET_BIT(num, pos) (num | (1 << pos))
int main()
{
printf(“%dn”, 2 * SET_BIT(0, 2));
return 0;
}
int main()
{
printf(“%dn”, 2 * (0 | (1 << 2)));
return 0;
}
007_example.c
007_example.i
Advanced C
Preprocessor – Macro – Arguments - DIY
●
WAM to find the sum of two nos
●
Write macros to get, set and clear Nth bit in an integer
●
WAM to swap a nibble in a byte
Advanced C
Preprocessor – Macro – Multiple Lines
●
You may continue the definition onto multiple lines, if
necessary, using backslash-newline.
●
This could be done to achieve readability
●
When the macro is expanded, however, it will all come
out on one line
Advanced C
Preprocessor – Macro – Multiple Lines
#include <stdio.h>
#define SWAP(a, b) 
int temp = a; 
a = b; 
b = temp; 
int main()
{
int n1 = 10, n2= 20;
SWAP(n1, n2);
printf(“%d %dn”, n1, n2);
SWAP(n1, n2);
printf(“%d %dn”, n1, n2);
return 0;
}
int main()
{
int n1 = 10, n2= 20;
int temp = n1;n1 = n2;n2 = temp;
printf(“%d %dn”, n1, n2);
int temp = n1;n1 = n2;n2 = temp;
printf(“%d %dn”, n1, n2);
return 0;
}
008_example.c
008_example.i
Advanced C
Preprocessor – Macro – Multiple Lines
#include <stdio.h>
#define SWAP(a, b) 
{ 
int temp = a; 
a = b; 
b = temp; 
}
int main()
{
int n1 = 10, n2= 20;
SWAP(n1, n2);
printf(“%d %dn”, n1, n2);
SWAP(n1, n2);
printf(“%d %dn”, n1, n2);
return 0;
}
int main()
{
int n1 = 10, n2= 20;
{int temp = n1;n1 = n2;n2 = temp;}
printf(“%d %dn”, n1, n2);
{int temp = n1;n1 = n2;n2 = temp;}
printf(“%d %dn”, n1, n2);
return 0;
}
009_example.c
009_example.i
Advanced C
Preprocessor – Macro – Multiple Lines - DIY
●
WAM to swap any two numbers of basic type using
temporary variable
Advanced C
Preprocessor – Macro vs Function
Function
#include <stdio.h>
int set_bt(int n, int p)
{
return (n | (1 << p));
}
int main()
{
printf(“%dn”, 2 * set_bt(0, 2));
printf(“%dn”, 4 * set_bt(0, 2));
return 0;
}
Macro
#include <stdio.h>
#define set_bt(n, p) (n | (1 << p))
int main()
{
printf(“%dn”, 2 * set_bt(0, 2));
printf(“%dn”, 4 * set_bt(0, 2));
return 0;
}
●
Context switching overhead
●
Stack frame creation overhead
●
Space optimized on repeated call
●
Compiled at compile stage,
invoked at run time
●
Type sensitive
●
Recommended for larger operation
●
No context switching overhead
●
No stack frame creation overhead
●
Time optimized on repeated call
●
Preprocessed and expanded at
preprocessing stage
●
Type insensitive
●
Recommended for smaller operation
Advanced C
Preprocessor – Macro – Stringification
#include <stdio.h>
#define WARN_IF(EXP) 
do 
{ 
x--; 
if (EXP) 
{ 
fprintf(stderr, "Warning: " #EXP "n"); 
} 
} while (x);
int main()
{
int x = 5;
WARN_IF(x == 0);
return 0;
}
●
You can convert a macro
argument into a string
constant by adding #
010_example.c
Advanced C
Preprocessor – Conditional Compilation
●
A conditional is a directive that instructs the preprocessor
to select whether or not to include a chunk of code in the
final token stream passed to the compiler
●
Preprocessor conditionals can test arithmetic expressions,
or whether a name is defined as a macro, or both
simultaneously using the special defined operator
●
A conditional in the C preprocessor resembles in some
ways an if statement in C with the only difference being it
happens in compile time
●
Its purpose is to allow different code to be included in the
program depending on the situation at the time of
compilation.
Advanced C
Preprocessor – Conditional Compilation
●
There are three general reasons to use a conditional.
– Portability: A program may need to use different code
depending on the machine or operating system it is to
run on
– Testing: You may want to be able to compile the same
source file into two different programs, like one for
debug (Test) and other as final (Production)
– Reference Code: A conditional whose condition is
always false is one way to exclude code from the
program but keep it as a sort of comment for future
reference
Advanced C
Preprocessor – Header Files – Once-Only
●
If a header file happens to be included twice, the compiler
will process its contents twice causing an error
●
E.g. when the compiler sees the same structure definition
twice
●
This can be avoided like
#ifndef NAME
#define NAME
/* The entire file is protected */
#endif
Syntax
Advanced C
Preprocessor – Header Files – Once-Only
#include “012_example.h”
#include “012_example.h”
int main()
{
struct UserInfo p = {420, “Tingu”};
return 0;
}
struct UserInfo
{
int id;
char name[30];
};
●
Note that, 012_exampe.h is
included 2 times which
would lead to redefinition of
the structure UserInfo
011_example.c
012_example.h
Advanced C
Preprocessor – Header Files – Once-Only
#include “014_example.h”
#include “014_example.h”
int main()
{
struct UserInfo p = {420, “Tingu”};
return 0;
}
#ifndef EXAMPLE_014_H
#define EXAMPLE_014_H
struct UserInfo
{
int id;
char name[30];
};
#endif
●
The multiple inclusion is
protected by the #ifndef
preprocessor directive
013_example.c
014_example.h
Advanced C
Preprocessor – Header Files – Once-Only
#include “016_example.h”
#include “016_example.h”
int main()
{
struct UserInfo p = {420, “Tingu”};
return 0;
}
#pragma once
struct UserInfo
{
int id;
char name[30];
};
●
The other way to do this
would be #pragma once
directive
●
This is not portable
015_example.c
016_example.h
Advanced C
Preprocessor – Conditional Compilation - ifdef
#ifdef MACRO
/* Controlled Text */
#endif
#include <stdio.h>
#define METHOD1
int main()
{
#ifdef METHOD1
puts(“Hello World”);
#else
printf(“Hello World”);
#endif
return 0;
}
#ifdef MACRO
/* Controlled Text */
#endif
017_example.cSyntax
Advanced C
Preprocessor – Conditional Compilation - ifndef
#include <stdio.h>
#undef METHOD1
int main()
{
#ifndef METHOD1
puts(“Hello World”);
#else
printf(“Hello World”);
#endif
return 0;
}
#ifndef MACRO
/* Controlled Text */
#endif
018_example.cSyntax
Advanced C
Preprocessor – Conditional Compilation - defined
#if defined condition
/* Controlled Text */
#endif
#include <stdio.h>
#define METHOD1
int main()
{
#if defined (METHOD1)
puts(“Hello World”);
#endif
#if defined (METHOD2)
printf(“Hello World”);
#endif
#if defined (METHOD1) && defined (METHOD2)
puts(“Hello World”);
printf(“Hello World”);
#endif
return 0;
}
019_example.cSyntax
Advanced C
Preprocessor – Conditional Compilation - if
#if expression
/* Controlled Text */
#endif
#include <stdio.h>
#define METHOD 1
int main()
{
#if METHOD == 1
puts(“Hello World”);
#endif
#if METHOD == 2
printf(“Hello World”);
#endif
return 0;
}
020_example.cSyntax
Advanced C
Preprocessor – Conditional Compilation - else
#if expression
/* Controlled Text if true */
#else
/* Controlled Text if false */
#endif
#include <stdio.h>
#define METHOD 0
int main()
{
#if METHOD == 1
puts(“Hello World”);
#else
printf(“Hello World”);
#endif
return 0;
}
021_example.cSyntax
Advanced C
Preprocessor – Conditional Compilation - elif
#if expression1
/* Controlled Text*/
#elif expression2
/* Controlled Text */
#else
/* Controlled Text */
#endif
#include <stdio.h>
#define METHOD 1
int main()
{
char msg[] = “Hello World”;
#if METHOD == 1
puts(msg);
#elif METHOD == 2
printf(“%sn”, msg);
#else
int i;
for (i = 0; i < 12; i++)
{
putchar(msg[i]);
}
#endif
return 0;
}
022_example.cSyntax
Advanced C
Preprocessor – Cond... Com... – CL Option
#include <stdio.h>
int main()
{
int x = 10, y = 20;
#ifdef SPACE_OPTIMIZED
x = x ^ y;
y = x ^ y;
x = x ^ y;
printf(“Selected Space Optimizationn”);
#else
int temp;
temp = x;
x = y;
y = temp;
printf(“Selected Time Optimizationn”);
#endif
return 0;
}
user@user:~] gcc main.c -D SPACE_OPTIMIZED
Compile as
023_example.c
Advanced C
Preprocessor – Cond... Com... – Deleted Code
#if 0
/* Deleted code while compiling */
/* Can be used for nested code comments */
/* Avoid for general comments */
/* Don't write lines like these!! with '
#endif
024_example.c
Advanced C
Preprocessor – Diagnostic
●
The directive #error causes the preprocessor to report a
fatal error. The tokens forming the rest of the line
following #error are used as the error message
●
The directive #warning is like #error, but causes the
preprocessor to issue a warning and continue
preprocessing. The tokens following #warning are used as
the warning message
Advanced C
Preprocessor – Diagnostic - #warning
#include <stdio.h>
#if defined DEBUG_PRINT
#warning “Debug print enabled”
#endif
int main()
{
int sum, num1, num2;
printf(“Enter 2 numbers: ”);
scanf(“%d %d”, &num1, &num2);
#ifdef DEBUG_PRINT
printf(“The entered values are %d %dn”, num1, num2);
#endif
sum = num1 + num2;
printf(“The sum is %dn”, sum);
return 0;
}
025_example.c
Advanced C
Preprocessor – Diagnostic - #error
#include <stdio.h>
#if defined (STATIC) || defined (DYNAMIC)
#define SIZE 100
#else
#error “Memory not allocated!! Use -D STATIC or DYNAMIC while compiling”
#endif
int main()
{
#if defined STATIC
char buffer[SIZE];
#elif defined DYNAMIC
char *buffer = malloc(SIZE * sizeof(char));
#endif
#if defined (STATIC) || defined (DYNAMIC)
fgets(buffer, SIZE, stdin);
printf(“%sn”, buffer);
#endif
return 0;
}
026_example.c
Advanced C
Preprocessor – Diagnostic - #line
●
Also known as preprocessor line control directive
●
#line directive can be used to alter the line number and
filename
●
The line number will start from the set value, from the
#line is encountered with the provided name
#include <stdio.h>
int main()
{
#line 100 “project tuntun”
printf(“This is from file %s at line %d n”, __FILE__, __LINE__);
return 0;
}
027_example.c
User Defined Datatypes
Advanced C
User Defined Datatypes (Composite Data Types)
●
Sometimes it becomes tough to build a whole software that
works only with integers, floating values, and characters.
●
In circumstances such as these, you can create your own data
types which are based on the standard ones
●
There are some mechanisms for doing this in C:
– Structure (derived)
– Unions (derived)
– Typedef (storage class)
– Enum (user defined)
●
Hoo!!, let's not forget our old friend _r_a_ which is a user
defined data type too!!.
Advanced C
User Defined Datatypes (Composite Data Types)
: Composite (or Compound) Data Type :
●
Any data type which can be constructed from primitive
data types and other composite types
●
It is sometimes called a structure or aggregate data type
●
Primitives types – int, char, float, double
Advanced C
UDTs
Advanced C
UDTs - Structures
struct StructureName
{
/* Group of data types */
};
Syntax
●
So if we create a structure of the above requirement, it
would look like,
struct Student
{
int id;
char name[20];
char address[60];
};
Example
●
If we consider the Student as
an example, The admin
should have at least some
important data like name, ID
and address.
Advanced C
UDTs – Structures – Declaration and definition
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1;
return 0;
}
●
Name of the datatype. Note it's
struct Student and not Student
●
Are called as fields or members of
of the structure
●
Declaration ends here
●
The memory is not yet allocated!!
●
s1 is a variable of type
struct Student
●
The memory is allocated now
001_example.c
Advanced C
UDTs – Structures – Memory Layout
●
What does s1 contain?
●
How can we draw it's memory
layout?
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1;
return 0;
}
001_example.c
?
?
?
id
name
address
s1
Advanced C
UDTs – Structures – Memory Layout
Structure size depends in the member arrangment!!. Will discuss that shortly
4 Bytes
20 Bytes
60 Bytes
id
name
address
s1
002_example.c
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1;
s1.id = 10;
return 0;
}
●
How to write into id now?
●
It's by using “.” (Dot) operator (member access operator)
●
Now please assign the name member of s1
10
?
?
id
name
address
s1
003_example.c
Advanced C
UDTs – Structures – Access
Advanced C
UDTs – Structures - Initialization
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1 = {10, “Tingu”, “Bangalore”};
return 0;
}
10
"Tingu"
Bangalore
id
name
address
s1
004_example.c
Advanced C
UDTs – Structures - Copy
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1 = {10, “Tingu”, “Bangalore”};
struct Student s2;
s2 = s1;
return 0;
}
Structure name does not represent its address. (No correlation with arrays)
10
"Tingu"
Bangalore
id
name
address
s2
005_example.c
Advanced C
UDTs – Structures - Address
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s1 = {10, “Tingu”, “Bangalore”};
printf(“Struture starts at %pn”, &s1);
printf(“Member id is at %pn”, &s1.id);
printf(“Member name is at %pn”, s1.name);
printf(“Member address is at %pn”, s1.address);
return 0;
}
10
"Tingu"
Bangalore
id
name
address
s1
1000
006_example.c
Advanced C
UDTs – Structures - Pointers
●
Pointers!!!. Not again ;). Fine don't worry, not a big deal
●
But do you any idea how to create it?
●
Will it be different from defining them like in other data
types?
Advanced C
UDTs – Structures - Pointer
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
static struct Student s1;
int main()
{
struct Student *sptr = &s1;
return 0;
}
1000
sptr
1000
2000
id
name
address
s1
?
?
?
007_example.c
Advanced C
UDTs – Structures – Pointer - Access
1000
sptr
1000
2000
id
name
address
s1
10
?
?
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
static struct Student s1;
int main()
{
struct Student *sptr = &s1;
(*sptr).id = 10;
return 0;
}
008_example.c
Advanced C
UDTs – Structures – Pointer – Access – Arrow
Note: we can access the structure pointer as seen
in the previous slide. The Arrow operator is just
convenience and frequently used
1000
sptr
1000
2000
id
name
address
s1
10
?
?
Note: we can access the structure pointer as seen
in the previous slide. The Arrow operator is just
convenience and frequently used
#include <stdio.h>
struct Student
{
int id;
char name[20];
char address[60];
};
static struct Student s1;
int main()
{
struct Student *sptr = &s1;
sptr->id = 10;
return 0;
}
009_example.c
Advanced C
UDTs – Structures - Functions
●
The structures can be passed as parameter and can be
returned from a function
●
This happens just like normal datatypes.
●
The parameter passing can have two methods again as
normal
– Pass by value
– Pass by reference
Advanced C
UDTs – Structures – Functions – Pass by Value
#include <stdio.h>
struct Student
{
int id;
char name[30];
char address[150];
};
void data(struct Student s)
{
s.id = 10;
}
int main()
{
struct Student s1;
data(s1);
return 0;
}
Not recommended on
larger structures
010_example.c
Advanced C
UDTs – Structures – Functions – Pass by Reference
Recommended on
larger structures
#include <stdio.h>
struct Student
{
int id;
char name[30];
char address[150];
};
void data(struct Student *s)
{
s->id = 10;
}
int main()
{
struct Student s1;
data(&s1);
return 0;
}
011_example.c
Advanced C
UDTs – Structures – Functions – Return
struct Student
{
int id;
char *name;
char *address;
};
struct Student data(void)
{
struct Student s;
s.name = (char *) malloc(30 * sizeof(char));
s.address = (char *) malloc(150 * sizeof(char));
return s;
}
int main()
{
struct Student s1;
s1 = data();
return 0;
}
012_example.c
Advanced C
UDTs – Structures – Array
struct Student
{
int id;
char name[20];
char address[60];
};
int main()
{
struct Student s[5];
int i;
for (i = 0; i < 5; i++)
{
scanf(“%d”, &s[i].id);
}
for (i = 0; i < 5; i++)
{
printf(“s[%d].id is %dn”, i, s[i].id);
}
return 0;
}
013_example.c
Advanced C
UDTs – Structures – Nesting
struct College
{
struct Student
{
int id;
char name[20];
char address[60];
} student;
struct
{
int id;
char name[20];
char address[60];
} faculty;
};
int main()
{
struct College member;
member.student.id = 10;
member.faculty.id = 20;
return 0;
}
014_example.c
Advanced C
UDTs – Structures – Padding
●
Adding of few extra useless bytes (in fact skip address) in
between the address of the members are called
structure padding.
●
What!!?, wasting extra bytes!!, Why?
●
This is done for Data Alignment.
●
Now!, what is data alignment and why did this issue
suddenly arise?
●
No its is not sudden, it is something the compiler would
be doing internally while allocating memory.
●
So let's understand data alignment in next few slides
Advanced C
Data Alignment
●
A way the data is arranged and accessed in computer
memory.
●
When a modern computer reads from or writes to a
memory address, it will do this in word sized chunks (4
bytes in 32 bit system) or larger.
●
The main idea is to increase the efficiency of the CPU,
while handling the data, by arranging at a memory
address equal to some multiple of the word size
●
So, Data alignment is an important issue for all
programmers who directly use memory.
Advanced C
Data Alignment
●
If you don't understand data and its address alignment
issues in your software, the following scenarios, in
increasing order of severity, are all possible:
– Your software will run slower.
– Your application will lock up.
– Your operating system will crash.
– Your software will silently fail, yielding incorrect results.
Advanced C
Data Alignment
int main()
{
char ch = 'A';
int num = 0x12345678;
}
Example ●
Lets consider the code as
given
●
The memory allocation we
expect would be like shown
in figure
●
So lets see how the CPU tries
to access these data in next
slides
ch
78
56
34
12
?
?
?
0
1
2
3
4
5
6
7
Advanced C
Data Alignment
●
Fetching a character by
the CPU will be like shown
below
41
78
56
34
12
?
?
?
0
1
2
3
4
5
6
7
0 4 Bytes
41
78
56
34
41
0
0
0
Example
int main()
{
char ch = 'A';
int num = 0x12345678;
}
Advanced C
Data Alignment
●
Fetching integer by the
CPU will be like shown
below
41
78
56
34
12
?
?
?
0
1
2
3
4
5
6
7
0 4 Bytes
41
78
56
34
Example
int main()
{
char ch = 'A';
int num = 0x12345678;
}
Advanced C
Data Alignment
●
Fetching the integer by
the CPU will be like shown
below
41
78
56
34
12
?
?
?
0
1
2
3
4
5
6
7
4 4 Bytes
41
78
56
34
12
?
?
?
Example
int main()
{
char ch = 'A';
int num = 0x12345678;
}
Advanced C
Data Alignment
●
Fetching the integer by
the CPU will be like shown
below
41
78
56
34
12
?
?
?
0
1
2
3
4
5
6
7
41
78
56
34
12
?
?
?
78
56
34
0
Shift 1 Byte Up
0
0
0
12
78
56
34
12
Shift 3 Byte Down
Combine
Example
int main()
{
char ch = 'A';
int num = 0x12345678;
}
Advanced C
UDTs – Structures – Data Alignment - Padding
●
Because of the data alignment issue, structures uses padding
between its members if they don't fall under even address.
●
So if we consider the following structure the memory
allocation will be like shown in below figure
struct Test
{
char ch1;
int num;
char ch2;
}
ch1
pad
pad
pad
num
num
num
num
0
1
2
3
4
5
6
7
ch2
pad
pad
pad
8
9
A
B
Example
Advanced C
UDTs – Structures – Data Alignment - Padding
●
You can instruct the compiler to modify the default padding
behavior using #pragma pack directive
#pragma pack(1)
struct Test
{
char ch1;
int num;
char ch2;
};
ch1
num
num
num
num
ch2
0
1
2
3
4
5
Example
Advanced C
UDTs – Structures – Padding
#include <stdio.h>
struct Student
{
char ch1;
int num;
char ch2;
};
int main()
{
struct Student s1;
printf(“%zun”, sizeof(struct Student));
return 0;
}
015_example.c
Advanced C
UDTs – Structures – Padding
#include <stdio.h>
#pragma pack(1)
struct Student
{
char ch1;
int num;
char ch2;
};
int main()
{
struct Student s1;
printf(“%zun”, sizeof(struct Student));
return 0;
}
016_example.c
Advanced C
UDTs – Structures – Bit Fields
●
The compiler generally gives the memory allocation in
multiples of bytes, like 1, 2, 4 etc.,
●
What if we want to have freedom of having getting
allocations in bits?!.
●
This can be achieved with bit fields.
●
But note that
– The minimum memory allocation for a bit field member
would be a byte that can be broken in max of 8 bits
– The maximum number of bits assigned to a member would
depend on the length modifier
– The default size is equal to word size
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
unsigned char lower : 4;
unsigned char upper : 4;
};
●
The above structure divides a char into two nibbles
●
We can access these nibbles independently
Example
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
unsigned char lower : 4;
unsigned char upper : 4;
};
int main()
{
struct Nibble nibble;
nibble.upper = 0x0A;
nibble.lower = 0x02;
return 0;
}
?1000
nibble
? ? ? ? ? ? ? ?
017_example.c
Advanced C
UDTs – Structures – Bit Fields
0xA?1000
nibble
1 0 1 0 ? ? ? ?
struct Nibble
{
unsigned char lower : 4;
unsigned char upper : 4;
};
int main()
{
struct Nibble nibble;
nibble.upper = 0x0A;
nibble.lower = 0x02;
return 0;
}
017_example.c
Advanced C
UDTs – Structures – Bit Fields
0xA21000
nibble
1 0 1 0 0 0 1 0
struct Nibble
{
unsigned char lower : 4;
unsigned char upper : 4;
};
int main()
{
struct Nibble nibble;
nibble.upper = 0x0A;
nibble.lower = 0x02;
return 0;
}
017_example.c
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
unsigned char lower : 4;
unsigned char upper : 4;
};
int main()
{
struct Nibble nibble;
printf(“%zun”, sizeof(nibble));
return 0;
}
018_example.c
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
unsigned lower : 4;
unsigned upper : 4;
};
int main()
{
struct Nibble nibble;
printf(“%zun”, sizeof(nibble));
return 0;
}
019_example.c
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
char lower : 4;
char upper : 4;
};
int main()
{
struct Nibble nibble;
nibble.upper = 0x0A;
nibble.lower = 0x02;
printf(“%dn”, nibble.upper);
printf(“%dn”, nibble.lower);
return 0;
}
019_example.c
Advanced C
UDTs – Structures – Bit Fields
struct Nibble
{
char lower : 4;
char upper : 4;
};
int main()
{
struct Nibble nibble = {0x02, 0x0A};
printf(“%#on”, nibble.upper);
printf(“%#xn”, nibble.lower);
return 0;
}
020_example.c
Advanced C
UDTs – Unions
Advanced C
UDTs – Unions
●
Like structures, unions may have different members with
different data types.
●
The major difference is, the structure members get
different memory allocation, and in case of unions there
will be single memory allocation for the biggest data type
Advanced C
UDTs – Unions
union Test
{
char option;
int id;
double height;
};
●
The above union will get the size allocated for the type
double
●
The size of the union will be 8 bytes.
●
All members will be using the same space when accessed
●
The value the union contain would be the latest update
●
So as summary a single variable can store different type of
data as required
Example
Advanced C
UDTs – Unions
union Test
{
char option;
int id;
double height;
};
int main()
{
union Test temp_var;
temp_var.height = 7.2;
temp_var.id = 0x1234;
temp_var.option = '1';
return 0;
}
?
?
?
?
1000 ?
?
?
?
1007
Total 8 Bytes
allocated
since longest
member is
double
temp_var
021_example.c
Advanced C
UDTs – Unions
0xCC
0xCC
0X1C
0X40
1000 0xCD
0xCC
0xCC
0xCC
1007
double uses
its memory
temp_var
union Test
{
char option;
int id;
double height;
};
int main()
{
union Test temp_var;
temp_var.height = 7.2;
temp_var.id = 0x1234;
temp_var.option = '1';
return 0;
}
021_example.c
Advanced C
UDTs – Unions
0xCC
0xCC
0X1C
0X40
1000 0x34
0x12
0x00
0x00
1007
int shares
double's
memory
temp_var
union Test
{
char option;
int id;
double height;
};
int main()
{
union Test temp_var;
temp_var.height = 7.2;
temp_var.id = 0x1234;
temp_var.option = '1';
return 0;
}
021_example.c
Advanced C
UDTs – Unions
0xCC
0xCC
0X1C
0X40
1000 0x31
0x12
0x00
0x00
1007
char shares
double's
memory
temp_var
union Test
{
char option;
int id;
double height;
};
int main()
{
union Test temp_var;
temp_var.height = 7.2;
temp_var.id = 0x1234;
temp_var.option = '1';
return 0;
}
021_example.c
Advanced C
UDTs – Unions
union FloatBits
{
float degree;
struct
{
unsigned m : 23;
unsigned e : 8;
unsigned s : 1;
} elements;
};
int main()
{
union FloatBits fb = {3.2};
printf(“Sign: %Xn”, fb.elements.s);
printf(“Exponent: %Xn”, fb.elements.e);
printf(“Mantissa: %Xn”, fb.elements.m);
return 0;
}
1000 0xCD
0xCC
0x4C
0x401004
fb
022_example.c
Advanced C
UDTs – Unions
union Endian
{
unsigned int value;
unsigned char byte[4];
};
int main()
{
union Endian e = {0x12345678};
e.byte[0] == 0x78 ? printf(“Littlen”) : printf(“Bign”);
return 0;
}
023_example.c
Advanced C
UDTs - Typedefs
●
Typedef is used to create a new name to the existing
types.
●
K&R states that there are two reasons for using a
typedef.
– First, it provides a means to make a program more
portable. Instead of having to change a type everywhere it
appears throughout the program's source files, only a single
typedef statement needs to be changed.
– Second, a typedef can make a complex definition or
declaration easier to understand.
Advanced C
UDTs - Typedefs
typedef unsigned int uint;
int main()
{
uint number;
return 0;
}
typedef int * int_ptr;
typedef float * float_ptr;
int main()
{
int_ptr ptr1, ptr2, ptr3;
float_ptr fptr;
return 0;
}
typedef int array_of_100[100];
int main()
{
array_of_100 array;
printf(“%zun”, sizeof(array));
return 0;
}
025_example.c
026_example.c
027_example.c
Advanced C
UDTs - Typedefs
typedef struct _Student
{
int id;
char name[30];
char address[150]
} Student;
void data(Student s)
{
s.id = 10;
}
int main()
{
Student s1;
data(s1);
return 0;
}
#include <stdio.h>
typedef int (*fptr)(int, int);
int add(int num1, int num2)
{
return num1 + num2;
}
int main()
{
fptr function;
function = add;
printf(“%dn”, function(2, 4));
return 0;
}
028_example.c 029_example.c
Advanced C
UDTs - Typedefs
#include <stdio.h>
typedef signed int sint, si;
typedef unsigned int uint, ui;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main()
{
u8 count = 200;
s16 axis = -70;
printf(“%un”, count);
printf(“%dn”, axis);
return 0;
}
030_example.c
Advanced C
UDTs – Typedefs - Standard
size_t – stdio.h
ssize_t – stdio.h
va_list – stdarg.h
Example
Advanced C
UDTs – Typedefs - Usage
typedef struct Sensor {
int id;
char name[12];
int version;
/*
* The members of an anonymous union
* are considered to be members of the
* containing structure.
*/
union { // Anonymous union
float temperature;
float humidity;
char motion[4];
};
} Sensor;
031_example.c
Advanced C
UDTs – Enums
●
Set of named integral values
●
Generally referred as named integral constants
enum name
{
/* Members separated with , */
};
Syntax
Advanced C
UDTs – Enums
enum bool
{
e_false,
e_true
};
int main()
{
printf(“%dn”, e_false);
printf(“%dn”, e_true);
return 0;
}
●
The above example has two
members with its values
starting from 0.
i.e, e_false = 0 and e_true = 1.
032_example.c
Advanced C
UDTs – Enums
●
The member values can be
explicitly initialized
●
There is no constraint in
values, it can be in any order
and same values can be
repeated
●
The derived data type can be
used to define new members
which will be uninitialized
typedef enum
{
e_red = 1,
e_blue = 4,
e_green
} Color;
int main()
{
Color e_white = 0, e_black;
printf(“%dn”, e_white);
printf(“%dn”, e_black);
printf(“%dn”, e_green);
return 0;
}
033_example.c
Advanced C
UDTs – Enums
●
Enums does not have name
space of its own, so we cannot
have same name used again in
the same scope.
int main()
{
typedef enum
{
red,
blue
} Color;
int blue;
printf(“%dn”, blue);
printf(“%dn”, blue);
return 0;
}
034_example.c
Advanced C
UDTs – Enums
●
Size of Enum does not depend
on number of members
typedef enum
{
red,
blue,
green
} Color;
int main()
{
Color c;
printf(“%zun”, sizeof(Color));
printf(“%zun”, sizeof(c));
return 0;
}
035_example.c
Advanced C
UDTs - DIY
●
WAP to accept students record. Expect the below output
user@user:~]./students_record.out
Enter the number of students : 2
Enter name of the student : Tingu
Enter P, C and M marks : 23 22 12  
Enter name of the student : Pingu
Enter P, C and M marks : 98 87 87
--------------------------------------------------------------
Name Maths Physics Chemistry       
--------------------------------------------------------------
Tingu 12 23 22         
Pingu 87 98 87         
--------------------------------------------------------------
Average          49.50            60.50            54.50      
--------------------------------------------------------------
user@user:~]
Screen Shot
Advanced C
UDTs - DIY
●
WAP to program to swap a nibble using bit fields
File I/O
Advanced C
File Input / Output
●
Sequence of bytes
●
Could be regular or binary file
●
Why?
– Persistent storage
– Theoretically unlimited size
– Flexibility of storing any type data
Advanced C
File Input / Output
^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^F^@^
@^@^P^@^@^@RåtdÔ<91>^Z^
@^@^Pw·^X^Aù¿^@^@^@^@Øþø
¿0Éu·^@^@^@^@^@^@^@^@^@
^@^@^@^C^@^@^@^@^@^@^
@ðÈu·H^Aù¿&ìu·^X^Aù ¿^@^
@^@^@^D^@^@^@x^Xw·^@^@^
@^@^T^Aù¿^P^Aù¿Í<8d>u·ýßX·^L^
Fu·^P^Aù¿^O^Aù¿^@ÿø¿
A regular file looks normal as it
appears here.
regular files are generally group
of ASCII characters hence the
Sometimes called as text files
which is human readable.
The binary file typically contains
the raw data. The contents of a
Binary file is not human readable
Regular File Binary File
Advanced C
File Input / Output – Via Redirection
●
General way for feeding and getting the output is using
standard input (keyboard) and output (screen)
●
By using redirection we can achieve it with files i.e
./a.out < input_file > output_file
●
The above line feed the input from input_file and output
to output_file
●
The above might look useful, but its the part of the OS
and the C doesn't work this way
●
C has a general mechanism for reading and writing files,
which is more flexible than redirection
Advanced C
File Input / Output
●
C abstracts all file operations into operations on streams
of bytes, which may be "input streams" or "output
streams"
●
No direct support for random-access data files
●
To read from a record in the middle of a file, the
programmer must create a stream, seek to the middle of
the file, and then read bytes in sequence from the
stream
●
Let's discuss some commonly used file I/O functions
Advanced C
File IO – File Pointer
●
stdio.h is used for file I/O library functions
●
The data type for file operation generally is
●
FILE pointer, which will let the program keep track of the
file being accessed
●
Operations on the files can be
– Open
– File operations
– Close
Type
FILE *fp;
Advanced C
File IO – Functions – fopen() & fclose()
Prototype
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *stream);
Where mode are:
r - open for reading
w - open for writing (file need not exist)
a - open for appending (file need not exist)
r+ - open for reading and writing, start at beginning
w+ - open for reading and writing (overwrite file)
a+ - open for reading and writing (append if file exists)
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen(“test.txt”, “r”);
fclose(fp);
return 0;
}
001_example.c
Advanced C
File IO – Functions – fopen() & fclose()
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *input_fp;
input_fp = fopen(“text.txt”, “r”);
if (input_fp == NULL)
{
return 1;
}
fclose(input_fp);
return 0;
}
002_example.c
Advanced C
File IO – DIY
●
Create a file named text.txt and add some content to
it.
– WAP to print its contents on standard output
– WAP to copy its contents in text_copy.txt
Advanced C
File IO – Functions – feof()
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fptr;
char ch;
fptr = fopen(“/etc/shells”, “r”);
/* Need to do error checking on fopen() */
while (ch = fgetc(fptr))
{
if (feof(fptr))
break;
fputc(ch, stdout);
}
fclose(fptr);
return 0;
}
003_example.c
Advanced C
File IO – Functions – ferror() and clearerr()
#include <stdio.h>
int main()
{
FILE *fptr;
char ch;
fptr = fopen(“file.txt”, “w”);
ch = fgetc(fptr);/* This should fail since reading a file in write mode*/
if (ferror(fptr))
fprintf(stderr, “Error in reading from file : file.txtn”);
clearerr(fptr);
/* This loop should be false since we cleared the error indicator */
if (ferror(fptr))
fprintf(stderr, “Error in reading from file : file.txtn”);
fclose(fptr);
return 0;
}
004_example.c
Advanced C
File IO – Functions – ftell()
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fptr;
char ch;
fptr = fopen(“/etc/shells”, “r”);
/* Need to do error checking on fopen() */
printf(“File offset is at -> %ldnn”, ftell(fptr));
printf(“--> The content of file is <--n”);
while ((ch = fgetc(fptr)) != EOF)
fputc(ch, stdout);
printf(“nFile offset is at -> %ldn”, ftell(fptr));
fclose(fptr);
return 0;
}
005_example.c
Advanced C
File IO – DIY
●
Create a file named text.txt and add
“abcdabcbcdaabc”.
– WAP program to find the occurrences of character 'c'
using ftell()
Advanced C
File IO – Functions – fprintf(), fscanf() & rewind()
#include <stdio.h>
int main()
{
int num1, num2;
float num3;
char str[10], oper, ch;
FILE *fptr;
if ((fptr = fopen(“text.txt”, “w+”)) == NULL)
{
fprintf(stderr, “Can't open input file text.txt!n”);
return 1;
}
fprintf(fptr, “%d %c %d %s %fn”, 2, '+', 1, “is”, 1.1);
rewind(fptr);
fscanf(fptr, “%d %c %d %s %f”, &num1, &oper, &num2, str, &num3);
printf(“%d %c %d %s %fn”, num1, oper, num2, str, num3);
fclose(fptr);
return 0;
}
006_example.c
Advanced C
File IO – Functions – fseek()
#include <stdio.h>
int main()
{
int num1, num2;
float num3;
char str[10], oper, ch;
FILE *fptr;
if ((fptr = fopen(“text.txt”, “w+”)) == NULL)
{
fprintf(stderr, “Can't open input file text.txt!n”);
return 1;
}
fprintf(fptr, “%d %c %d %s %fn”, 2, '+', 1, “is”, 1.1);
fseek(fptr, 0L, SEEK_SET);
fscanf(fptr, “%d %c %d %s %f”, &num1, &oper, &num2, str, &num3);
printf(“%d %c %d %s %fn”, num1, oper, num2, str, num3);
fclose(fptr);
return 0;
}
007_example.c
Advanced C
File IO – Functions – fwrite() & fread()
#include <stdio.h>
int main()
{
int num1, num2, num3, num4;
FILE *fptr;
if ((fptr = fopen(“text.txt”, “w+”)) == NULL)
{
fprintf(stderr, “Can't open input file text.txt!n”); return 1;
}
scanf(“%d%d”, &num1, &num2);
fwrite(&num1, sizeof(num1), 1, fptr);
fwrite(&num2, sizeof(num2), 1, fptr);
rewind(fptr);
fread(&num3, sizeof(num3), 1, fptr);
fread(&num4, sizeof(num4), 1, fptr);
printf(“%d %dn”, num3, num4);
fclose(fptr);
return 0;
}
008_example.c
#include <stdio.h>
int main()
{
struct Data d1 = {2, '+', 1, “is”, 1.1};
struct Data d2;
FILE *fptr;
if ((fptr = fopen(“text.txt”, “w+”)) == NULL)
{
fprintf(stderr, “Can't open input file text.txt!n”);
return 1;
}
fwrite(&d1, sizeof(d1), 1, fptr);
rewind(fptr);
fread(&d2, sizeof(d2), 1, fptr);
printf(“%d %c %d %s %fn”, d2.num1, d2.oper, d2.num2, d2.str, d2.num3);
fclose(fptr);
return 0;
}
Advanced C
File IO – Functions – fwrite() & fread()
struct Data
{
int num1;
char oper;
int num2;
char str[10];
float num3;
};
009_example.c
Advanced C
File IO – DIY
●
WAP to accept students record from user. Store all the data in as a binary
file
●
WAP to read out entries by the previous program
user@user:~]./students_record_enrty.out
Enter the number of students : 2
Enter name of the student : Tingu
Enter P, C and M marks : 23 22 12  
Enter name of the student : Pingu
Enter P, C and M marks : 98 87 87
user@user:~]./read_students_record.out
--------------------------------------------------------------
Name Maths Physics Chemistry       
--------------------------------------------------------------
Tingu 12 23 22         
Pingu 87 98 87         
--------------------------------------------------------------
Average          49.50            60.50            54.50      
--------------------------------------------------------------
user@user:~]
Screen Shot
Miscellaneous
Advanced C
Miscellaneous - Volatile
●
A datatype qualifier
●
Most commonly used Embedded Applications
●
A keyword instructing the compiler not apply any
optimizations on objects qualified with it!
●
Why??
– You know! the compiler sometimes act extra smart on
the objects not qualified with volatile
– Takes implicit assumption the the objects
Advanced C
Miscellaneous - Volatile
#include <stdio.h>
int main()
{
long int wait;
unsigned char bit = 0;
while (1)
{
bit = !bit;
printf(“The bit is now: %dr”, bit);
fflush(stdout);
for (wait = 0xFFFFFFF; wait--; );
}
return 0;
}
user@user:~] gcc 001_example.c
Compile like
●
Typical embedded bit toggle
code
●
The output would toggle
between 0 and 1 (Depends
on the system
configuration, tune the
delay as required)
●
Note the toggle frequency
and
user@user:~] gcc -O3 001_example.c
Compile like
●
Now try the same code
001_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 001_example.c
Compile like
user@user:~] gcc -O3 001_example.c
Compile like
●
Should solve the issue!
●
or
●
What happens in the previous code is that the compiler see the for loop as
an unnecessary code just delaying the system operation
●
Hence it removes that statement in the final output
●
Adding volatile to the wait restricts the compiler from optimizing the code
#include <stdio.h>
int main()
{
volatile long int wait;
unsigned char bit = 0;
while (1)
{
bit = !bit;
printf(“The bit is now: %dr”, bit);
fflush(stdout);
for (wait = 0xFFFFFFF; wait--; );
}
return 0;
}
001_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 002_example.c
Compile like
user@user:~] gcc -O3 002_example.c
Compile like
●
Might take some time to see
the output on screen!!
●
Immediate output!!
●
Compiler sees the same
assignment operation is
unnecessarily happening in
the loop
●
Optimizes the loop, by
removing the for loop
#include <stdio.h>
int main()
{
unsigned int i;
int num;
for (i = 0; i < 0xFFFFFFFF; i++)
{
num = 5;
}
printf(“%dn”, num);
return 0;
}
002_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 002_example.c
Compile like
user@user:~] gcc -O3 002_example.c
Compile like
●
Should solve the issue!
●
Both should behave the
same way!
●
or
#include <stdio.h>
int main()
{
volatile unsigned int i;
int num;
for (i = 0; i < 0xFFFFFFFF; i++)
{
num = 5;
}
printf(“%dn”, num);
return 0;
}
002_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 003_example.c
Compile like
user@user:~] gcc -O3 003_example.c
Compile like
●
Enter 1 and should not
come out of the loop
●
Terminate and run again
with input 0, you should not
enter the loop
●
Enter 1 and should not
enter the loop!! which
shouldn't be the case
#include <stdio.h>
int main()
{
int get_out;
int num = 0;
scanf(“%d”, &get_out);
while (get_out)
{
num++;
}
return 0;
}
003_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 003_example.c
Compile like
user@user:~] gcc -O3 003_example.c
Compile like
●
Should solve the issue!
●
Both should behave the
same way!
●
or
#include <stdio.h>
int main()
{
int get_out;
volatile int num = 0;
scanf(“%d”, &get_out);
while (get_out)
{
num++;
}
return 0;
}
003_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 004_example.c
Compile like
#include <stdio.h>
int main()
{
int num1;
int num2 = 1;
num1 = ++num2 + num2++ + num2++ + num2++;
printf(“%dn”, num1);
return 0;
}
●
Use the precedence table to
obtain the result and verify
with output
user@user:~] ./a.out
Run
004_example.c
Advanced C
Miscellaneous - Volatile
user@user:~] gcc 004_example.c
Compile like
●
and
#include <stdio.h>
int main()
{
int num1;
volatile int num2 = 1;
num1 = ++num2 + num2++ + num2++ + num2++;
printf(“%dn”, num1);
return 0;
}
004_example.c
user@user:~] ./a.out
Run
●
Hmmmh, is it ok now!!

More Related Content

PDF
PDF
C Programming - Refresher - Part II
PDF
Linux Systems: Getting started with setting up an Embedded platform
PDF
C Programming - Refresher - Part I
PDF
Linux-Internals-and-Networking
PPT
Linux command ppt
PDF
Fun with Network Interfaces
C Programming - Refresher - Part II
Linux Systems: Getting started with setting up an Embedded platform
C Programming - Refresher - Part I
Linux-Internals-and-Networking
Linux command ppt
Fun with Network Interfaces

What's hot (20)

PDF
C Programming - Refresher - Part III
PDF
Meet cute-between-ebpf-and-tracing
PDF
Introduction to Embedded System
PDF
Let's trace Linux Lernel with KGDB @ COSCUP 2021
PPTX
Introduction to Embedded Linux
PDF
Linux Internals - Part II
PDF
File System Hierarchy
PDF
BPF Internals (eBPF)
PDF
Embedded Linux Kernel - Build your custom kernel
PDF
Linux Internals - Part III
PPTX
Understanding eBPF in a Hurry!
PDF
Making Linux do Hard Real-time
PDF
Linux systems - Linux Commands and Shell Scripting
PDF
ODP
eBPF maps 101
PDF
Architecture Overview: Kubernetes with Red Hat Enterprise Linux 7.1
PDF
The linux networking architecture
PDF
Linux Internals - Interview essentials 4.0
C Programming - Refresher - Part III
Meet cute-between-ebpf-and-tracing
Introduction to Embedded System
Let's trace Linux Lernel with KGDB @ COSCUP 2021
Introduction to Embedded Linux
Linux Internals - Part II
File System Hierarchy
BPF Internals (eBPF)
Embedded Linux Kernel - Build your custom kernel
Linux Internals - Part III
Understanding eBPF in a Hurry!
Making Linux do Hard Real-time
Linux systems - Linux Commands and Shell Scripting
eBPF maps 101
Architecture Overview: Kubernetes with Red Hat Enterprise Linux 7.1
The linux networking architecture
Linux Internals - Interview essentials 4.0
Ad

Similar to Advanced C - Part 3 (20)

PPTX
C (PPS)Programming for problem solving.pptx
PPTX
Array,MULTI ARRAY, IN C
PDF
11 1. multi-dimensional array eng
PPTX
PPTX
Array
PPT
array2d.ppt
PPTX
Address, Pointers, Arrays, and Structures.pptx
PDF
Programming Fundamentals Arrays and Strings
PPTX
Unit 3
PPTX
Chapter 13.pptx
PPSX
Pointers
PPTX
Unit 3
PDF
02 arrays
DOCX
Array
PPTX
Arrays.pptx
PPTX
Arrays & Strings
PDF
Multi dimensional array
PPTX
unit-2-dsa.pptx
PPT
Pointers and arrays
PPTX
Co&amp;al lecture-08
C (PPS)Programming for problem solving.pptx
Array,MULTI ARRAY, IN C
11 1. multi-dimensional array eng
Array
array2d.ppt
Address, Pointers, Arrays, and Structures.pptx
Programming Fundamentals Arrays and Strings
Unit 3
Chapter 13.pptx
Pointers
Unit 3
02 arrays
Array
Arrays.pptx
Arrays & Strings
Multi dimensional array
unit-2-dsa.pptx
Pointers and arrays
Co&amp;al lecture-08
Ad

More from Emertxe Information Technologies Pvt Ltd (20)

Recently uploaded (20)

PDF
cuic standard and advanced reporting.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Encapsulation theory and applications.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Electronic commerce courselecture one. Pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
cuic standard and advanced reporting.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Diabetes mellitus diagnosis method based random forest with bat algorithm
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Encapsulation theory and applications.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Review of recent advances in non-invasive hemoglobin estimation
Spectral efficient network and resource selection model in 5G networks
Building Integrated photovoltaic BIPV_UPV.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Advanced methodologies resolving dimensionality complications for autism neur...
Electronic commerce courselecture one. Pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
MIND Revenue Release Quarter 2 2025 Press Release
Dropbox Q2 2025 Financial Results & Investor Presentation
Empathic Computing: Creating Shared Understanding
Digital-Transformation-Roadmap-for-Companies.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”

Advanced C - Part 3

  • 2. Advanced C Pointers – Multilevel ● A pointer, pointing to another pointer which can be pointing to others pointers and so on is know as multilevel pointers. ● We can have any level of pointers. ● As the depth of the level increase we have to bit careful while dealing with it.
  • 3. Advanced C Pointers – Multilevel #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 101000 num 001_example.c
  • 4. Advanced C Pointers – Multilevel 101000 num 10002000 ptr1 #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 5. Advanced C Pointers – Multilevel 101000 num 20003000 ptr2 10002000 ptr1 #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 6. Advanced C Pointers – Multilevel 101000 num 30004000 ptr3 20003000 ptr2 10002000 ptr1 #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 7. Advanced C Pointers – Multilevel 101000 num 30004000 ptr3 20003000 ptr2 10002000 ptr1 Output 3000→ #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 8. Advanced C Pointers – Multilevel 101000 num 30004000 ptr3 20003000 ptr2 10002000 ptr1 Output 2000→ #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 9. Advanced C Pointers – Multilevel 101000 num 30004000 ptr3 20003000 ptr2 10002000 ptr1 Output 1000→ #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 10. Advanced C Pointers – Multilevel 101000 num 30004000 ptr3 20003000 ptr2 10002000 ptr1 Output 10→ #include <stdio.h> int main() { int num = 10; int *ptr1 = &num; int **ptr2 = &ptr1; int ***ptr3 = &ptr2; printf(“%d”, ptr3); printf(“%d”, *ptr3); printf(“%d”, **ptr3); printf(“%d”, ***ptr3); return 0; } 001_example.c
  • 11. Advanced C Arrays – Interpretations #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; return 0; } 1 2 3 4 5 a One big variable Pointer to the first small variable While assigning to pointer While passing to functions While using with sizeof() While pointer arithmetic on &array Example
  • 12. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a); printf(“%pn”, &a[0]); printf(“%pn”, &a); return 0; } 002_example.c
  • 13. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a); printf(“%pn”, &a[0]); printf(“%pn”, &a); return 0; } 002_example.c
  • 14. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a); printf(“%pn”, &a[0]); printf(“%pn”, &a); return 0; } 002_example.c
  • 15. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a + 1); printf(“%pn”, &a[0] + 1); printf(“%pn”, &a + 1); return 0; } 003_example.c
  • 16. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a + 1); printf(“%pn”, &a[0] + 1); printf(“%pn”, &a + 1); return 0; } 003_example.c
  • 17. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a + 1); printf(“%pn”, &a[0] + 1); printf(“%pn”, &a + 1); return 0; } 003_example.c
  • 18. Advanced C Arrays – Interpretations 1 2 3 4 5 a 1000 1004 1008 1012 1016 ? 1020 ⋮ 1036 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; printf(“%pn”, a + 1); printf(“%pn”, &a[0] + 1); printf(“%pn”, &a + 1); return 0; } 003_example.c
  • 19. Advanced C Arrays – Interpretations ● So in summary, if we try to print the address of a[] – a – prints the value of the constant pointer – &a[0] – prints the address of the first element pointed by a – &a – prints the address of the whole array which pointed by a ● Hence all the lines will print 1000 as output ● These concepts plays a very important role in multi dimension arrays
  • 21. Advanced C Arrays – 2D ● Find the broken eggs! ● Hmm, how should I proceed with count??
  • 22. Advanced C Arrays – 2D ● Now is it better to tell which one broken?? C1 C2 C3 C4 C5 R1 R2 R3 R4 R5 R6
  • 23. Advanced C Arrays – 2D ● So in matrix method it becomes bit easy to locate items ● In other terms we can reference the location with easy indexing ● In this case we can say the broken eggs are at R2-C4 and R4-C3 or C4-R2 and C3-R4 C1 C2 C3 C4 C5 R1 R2 R3 R4 R5 R6
  • 24. ● The matrix in computer memory is a bit tricky!! ● Why?. Since its a sequence of memory ● So pragmatically, it is a concept of dimensions is generally referred ● The next slide illustrates the expectation and the reality of the memory layout of the data in a system Advanced C Arrays – 2D
  • 25. Advanced C Arrays – 2D R1 R2 R3 R0 C1 C2 C3C0 201 101 187 22 123 9 234 39 23 155 33 2 100 88 8 111 1231001 91002 2341003 391004 231005 1551006 331007 21008 1001009 881010 81011 1111012 2011013 1011014 1871015 221016 Concept Illustration System Memory
  • 26. Advanced C Arrays - 2D Syntax data_type name[ROW][COL]; Where ROW * COL represents number of elements Memory occupied by array = (number of elements * size of an element) = (ROW * COL * <size of data_type>) Example int a[2][3] = {{10, 20, 30}, {40, 50, 60}}; 10 20 30 40 50 R0 - C0 R0 - C1 R0 - C2 R1 - C0 R1 - C1 baseaddr baseaddr+4 baseaddr+8 baseaddr+12 baseaddr+16 60 R1 - C2 baseaddr+20
  • 27. Advanced C Arrays – 2D - Referencing 2 * 1D array linearly placed in memory [0] [2] [1] [0] [1] [2] Index to access the 1D array [1] [0] [0] [0] [1] [1] 2nd 1D Array with base address 1012 a[1] = &a[1][0] = a + 1 1012→ 1st 1D Array with base address 1000 a[0] = &a[0][0] = a + 0 1000→ 401012 301008 201004 101000 501016 601020 a 1DArray1DArray
  • 28. Core Principle ● Dereferencing nth - dimensional array will return (n - 1)th -dimensional array – Example : dereferencing 2D array will return 1D array ● Dereferencing 1D array will return 'data element' – Example : Dereferencing 1D integer array will return integer Advanced C Arrays – 2D - Dereferencing Array Dimension &a n + 1 a n *a n - 1
  • 29. Advanced C Arrays – 2D - Dereferencing 2 * 1D array linearly placed in memory [0] [2] [1] [0] [1] [2] Index to access the 1D array [1] [0] [0] [0] [1] [1] 401012 301008 201004 101000 501016 601020 a 1DArray1DArray Example 1: Say a[0][1] is to be accessed, then decomposition happens like, a[0][1] = = *(a[0] + (1 * sizeof(type))) = *(*(a + (0 * sizeof(1D array))) + (1 * sizeof(type))) = *(*(a + (0 * 12)) + (1 * 4)) = *(*(a + 0) + 4) = *(*a + 0 + 4) = *(*a + 4) = *(1000 + 4) = *(1004)) a[0][1] = = *(a[0] + (1 * sizeof(type))) = 20
  • 30. Advanced C Arrays – 2D - Dereferencing 2 * 1D array linearly placed in memory [0] [2] [1] [0] [1] [2] Index to access the 1D array [1] [0] [0] [0] [1] [1] 401012 301008 201004 101000 501016 601020 a 1DArray1DArray Example 1: Say a[1][1] is to be accessed, then decomposition happens like, a[1][1] = = *(a[1] + (1 * sizeof(type))) = *(*(a + (1 * sizeof(1D array))) + (1 * sizeof(type))) = *(*(a + (1 * 12)) + (1 * 4)) = *(*(a + 12) + 4) = *(*a + 12 + 4) = *(*a + 16) = *(1000 + 16) = *(1016) a[1][1] = = *(a[1] + (1 * sizeof(type))) = 50 Address of a[r][c] = value(a) + r * sizeof(1D array) + c * sizeof(type)
  • 31. Advanced C Arrays – 2D - DIY ● WAP to find the MIN and MAX of a 2D array
  • 32. Advanced C Pointers – Array of pointers datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a = 10; int b = 20; int c = 30; int *ptr[3]; ptr[0] = &a; ptr[1] = &b; ptr[2] = &c; return 0; } Synatx 004_example.c 101000 a 201004 b 301008 c
  • 33. Advanced C Pointers – Array of pointers ? ? ? 4000 4004 4008 ptr datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a = 10; int b = 20; int c = 30; int *ptr[3]; ptr[0] = &a; ptr[1] = &b; ptr[2] = &c; return 0; } Synatx 004_example.c 101000 a 201004 b 301008 c
  • 34. Advanced C Pointers – Array of pointers datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a = 10; int b = 20; int c = 30; int *ptr[3]; ptr[0] = &a; ptr[1] = &b; ptr[2] = &c; return 0; } Synatx 004_example.c 101000 a 201004 b 301008 c 1000 1004 1008 4000 4004 4008 ptr
  • 35. Advanced C Pointers – Array of pointers datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a[2] = {10, 20}; int b[2] = {30, 40}; int c[2] = {50, 60}; int *ptr[3]; ptr[0] = a; ptr[1] = b; ptr[2] = c; return 0; } Synatx 005_example.c 10 1000 a 30 1008 b 50 1016 c 20 1004 40 1012 60 1020
  • 36. Advanced C Pointers – Array of pointers datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a[2] = {10, 20}; int b[2] = {30, 40}; int c[2] = {50, 60}; int *ptr[3]; ptr[0] = a; ptr[1] = b; ptr[2] = c; return 0; } Synatx 005_example.c 10 1000 a 30 1008 b 50 1016 c 20 1004 40 1012 60 1020 ? ? ? 4000 4004 4008 ptr
  • 37. Advanced C Pointers – Array of pointers datatype *ptr_name[SIZE] #include <stdio.h> int main() { int a[2] = {10, 20}; int b[2] = {30, 40}; int c[2] = {50, 60}; int *ptr[3]; ptr[0] = a; ptr[1] = b; ptr[2] = c; return 0; } Synatx 005_example.c 10 1000 a 30 1008 b 50 1016 c 20 1004 40 1012 60 1020 1000 1008 1016 4000 4004 4008 ptr
  • 38. Advanced C Pointers – Array of pointers #include <stdio.h> void print_array(int **p) { int i; for (i = 0; i < 3; i++) { printf(“%d ”, *p[i]); printf(“at %pn”, p[i]); } } int main() { int a = 10; int b = 20; int c = 30; int *ptr[3] = {&a, &b, &c}; print_array(ptr); return 0; } 006_example.c 101000 a 201004 b 301008 c
  • 39. Advanced C Pointers – Array of pointers #include <stdio.h> void print_array(int **p) { int i; for (i = 0; i < 3; i++) { printf(“%d ”, *p[i]); printf(“at %pn”, p[i]); } } int main() { int a = 10; int b = 20; int c = 30; int *ptr[3] = {&a, &b, &c}; print_array(ptr); return 0; } 006_example.c 101000 a 201004 b 301008 c 1000 1004 1008 4000 4004 4008 ptr
  • 40. Advanced C Pointers – Array of pointers #include <stdio.h> void print_array(int **p) { int i; for (i = 0; i < 3; i++) { printf(“%d ”, *p[i]); printf(“at %pn”, p[i]); } } int main() { int a = 10; int b = 20; int c = 30; int *ptr[3] = {&a, &b, &c}; print_array(ptr); return 0; } 006_example.c 101000 a 201004 b 301008 c 1000 1004 1008 4000 4004 4008 ptr
  • 41. #include <stdio.h> void print_array(int **p) { int i; for (i = 0; i < 3; i++) { printf(“%d ”, *p[i]); printf(“at %pn”, p[i]); } } int main() { int a = 10; int b = 20; int c = 30; int *ptr[3] = {&a, &b, &c}; print_array(ptr); return 0; } Advanced C Pointers – Array of pointers 006_example.c 101000 a 201004 b 301008 c 1000 1004 1008 4000 4004 4008 ptr 4000 p 5000
  • 42. Advanced C Pointers – Array of strings #include <stdio.h> int main() { char s[3][8] = { “Array”, “of”, “Strings” }; printf(“%s %s %sn”, s[0], s[1], s[2]); return 0; } s 'A' 'r' 'r' 'a' 'y' '0' 'o' 'f' '0' 'S' 't' 'r' 'i' 'n' 'g' 's' '0' ? ? ? ? ? ? ? 1000 1001 1002 1003 1004 1005 1011 1012 1021 1022 1023 1006 1007 1008 1009 1013 1014 1015 1016 1017 1018 1019 1010 1020 s 0x41 0x72 0x72 0x61 0x79 0x00 0x6F 0x66 0x00 0x53 0x74 0x72 0x69 0x6E 0x67 0x73 0x00 ? ? ? ? ? ? ? 1000 1001 1002 1003 1004 1005 1011 1012 1021 1022 1023 1006 1007 1008 1009 1013 1014 1015 1016 1017 1018 1019 1010 1020 007_example.c
  • 43. Advanced C Pointers – Array of strings #include <stdio.h> int main() { char *s[3]; s[0] = “Array”; s[1] = “of”; s[2] = “Strings”; printf(“%s %s %sn”, s[0], s[1], s[2]); return 0; } ? ? ? 4000 4004 4008 s 008_example.c
  • 44. Advanced C Pointers – Array of strings 1000 ? ? 4000 4004 4008 s 'A' 'r' 'r' 'a' 'y' '0' 1000 1001 1002 1003 1004 1005 #include <stdio.h> int main() { char *s[3]; s[0] = “Array”; s[1] = “of”; s[2] = “Strings”; printf(“%s %s %sn”, s[0], s[1], s[2]); return 0; } 008_example.c
  • 45. Advanced C Pointers – Array of strings 1000 1010 ? 4000 4004 4008 s 'A' 'r' 'r' 'a' 'y' '0' 'o' 'f' '0' 1000 1001 1002 1003 1004 1005 1010 1011 1012 #include <stdio.h> int main() { char *s[3]; s[0] = “Array”; s[1] = “of”; s[2] = “Strings”; printf(“%s %s %sn”, s[0], s[1], s[2]); return 0; } 008_example.c
  • 46. Advanced C Pointers – Array of strings 1000 1010 1020 4000 4004 4008 s 'A' 'r' 'r' 'a' 'y' '0' 'o' 'f' '0' 'S' 't' 'r' 'i' 'n' 'g' 's' '0' 1000 1001 1002 1003 1004 1005 1010 1011 1012 1020 1021 1022 1023 1024 1025 1026 1027 #include <stdio.h> int main() { char *s[3]; s[0] = “Array”; s[1] = “of”; s[2] = “Strings”; printf(“%s %s %sn”, s[0], s[1], s[2]); return 0; } 008_example.c
  • 47. Advanced C Pointers – Array of strings ● W.A.P to print menu and select an option – Menu options { File, Edit, View, Insert, Help } ● The prototype of print_menu function – void print_menu (char **menu); user@user:~] user@user:~]./a.out 1. File 2. Edit 3. View 4. Insert 5. Help Select your option: 2 You have selected Edit Menu user@user:~] Screen Shot
  • 48. Advanced C Pointers – Array of strings ● Command line arguments – Refer to PPT “11_functions_part2”
  • 49. Advanced C Pointers – Pointer to an Array ● Pointer to an array!!, why is the syntax so weird?? ● Isn't the code shown left is an example for pointer to an array? ● Should the code print as 1 in output? ● Yes, everything is fine here except the dimension of the array. ● This is perfect code for 1D array datatype (*ptr_name)[SIZE]; int main() { int array[3] = {1, 2, 3}; int *ptr; ptr = array; printf(“%dn”, *ptr); return 0; } Syntax 009_example.c
  • 50. Advanced C Pointers – Pointer to an Array ● So in order to point to 2D array we would prefer the given syntax ● Ookay, Isn't a 2D array linearly arranged in the memory? So can I write the code as shown? ● Hmm!, Yes but the compiler would warn you on the assignment statement ● Then how should I write? datatype (*ptr_name)[SIZE]; int main() { int array[3] = {1, 2, 3}; int (*ptr)[3]; ptr = array; printf(“%dn”, **ptr); return 0; } Syntax 010_example.c
  • 51. Advanced C Pointers – Pointer to an Array ● Hhoho, isn't array is equal to &array?? what is the difference? ● Well the difference lies in the compiler interpretation while pointer arithmetic and hence ● Please see the difference in the next slides datatype (*ptr_name)[SIZE]; int main() { int array[3] = {1, 2, 3}; int (*ptr)[3]; ptr = &array; printf(“%dn”, **ptr); return 0; } Syntax 011_example.c
  • 52. Advanced C Pointers – Pointer to an Array int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 53. int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 012_example.c
  • 54. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array ? p1 2000 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 55. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array ? p1 2000 ? 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 56. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 1000 p1 2000 ? 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 57. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 1000 p1 2000 1000 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 58. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 1000 p1 2000 1000 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 59. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 1000 p1 2000 1000 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 60. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 ? ? ? ? ? ? ?1036 array 1000 p1 2000 1000 2004 p2 int main() { int array[3] = {1, 2, 3}; int *p1; int (*p2)[3]; p1 = array; p2 = &array; printf(“%p %pn”, p1 + 0, p2 + 0); printf(“%p %pn”, p1 + 1, p2 + 1); printf(“%p %pn”, p1 + 2, p2 + 2); return 0; } 012_example.c
  • 61. Advanced C Pointers – Pointer to an Array ● So as a conclution we can say the ● Pointer arithmetic on 1D array is based on the size of datatype ● Pointer arithmetic on 2D array is based on the size of datatype and size of 1D array ● Still one question remains is what is real use of this syntax if can do p[i][j]? ● In case of dynamic memory allocation as shown in next slide
  • 62. Advanced C Pointers – Pointer to an Array ? p 2000 int main() { int (*p)[3]; p = malloc(sizeof(*p) * 3); (*(p + 0))[0] = 1; (*(p + 1))[1] = 2; (*(p + 2))[2] = 3; printf(“%dn”, p[0][0]); printf(“%dn”, p[1][1]); printf(“%dn”, p[2][2]); return 0; } 013_example.c
  • 63. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 ? ? ? ? ? ? ? ? ? ?1036 1000 p 2000 int main() { int (*p)[3]; p = malloc(sizeof(*p) * 3); (*(p + 0))[0] = 1; (*(p + 1))[1] = 2; (*(p + 2))[2] = 3; printf(“%dn”, p[0][0]); printf(“%dn”, p[1][1]); printf(“%dn”, p[2][2]); return 0; } 013_example.c
  • 64. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 ? ? ? ? ? ? ? ? ?1036 1000 p 2000 int main() { int (*p)[3]; p = malloc(sizeof(*p) * 3); (*(p + 0))[0] = 1; (*(p + 1))[1] = 2; (*(p + 2))[2] = 3; printf(“%dn”, p[0][0]); printf(“%dn”, p[1][1]); printf(“%dn”, p[2][2]); return 0; } 013_example.c
  • 65. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 ? ? ? 2 ? ? ? ? ?1036 1000 p 2000 int main() { int (*p)[3]; p = malloc(sizeof(*p) * 3); (*(p + 0))[0] = 1; (*(p + 1))[1] = 2; (*(p + 2))[2] = 3; printf(“%dn”, p[0][0]); printf(“%dn”, p[1][1]); printf(“%dn”, p[2][2]); return 0; } 013_example.c
  • 66. Advanced C Pointers – Pointer to an Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 ? ? ? 2 ? ? ? 3 ?1036 1000 p 2000 int main() { int (*p)[3]; p = malloc(sizeof(*p) * 3); (*(p + 0))[0] = 1; (*(p + 1))[1] = 2; (*(p + 2))[2] = 3; printf(“%dn”, p[0][0]); printf(“%dn”, p[1][1]); printf(“%dn”, p[2][2]); return 0; } 013_example.c
  • 67. int main() { int (*p)[3]; int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; p = a; return 0; } Advanced C Pointers – Pointer to an 2D Array 1000 p 2000 014_example.c
  • 68. Advanced C Pointers – Pointer to an 2D Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 1000 p 2000 a int main() { int (*p)[3]; int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; p = a; return 0; } 014_example.c
  • 69. Advanced C Pointers – Pointer to an 2D Array 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 1000 p 2000 a int main() { int (*p)[3]; int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; p = a; return 0; } 014_example.c
  • 70. #include <stdio.h> void print_array(int p[2][3]) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf(“%dn”, p[i][j]); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(a); return 0; } Advanced C Pointers – Passing 2D array to function 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 a 015_example.c
  • 71. Advanced C Pointers – Passing 2D array to function 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 a 1000 p 2000 #include <stdio.h> void print_array(int p[2][3]) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf(“%dn”, p[i][j]); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(a); return 0; } 015_example.c
  • 72. #include <stdio.h> void print_array(int (*p)[3]) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf(“%dn”, p[i][j]); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(a); return 0; } Advanced C Pointers – Passing 2D array to function 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 a 016_example.c
  • 73. Advanced C Pointers – Passing 2D array to function 1000 1004 1008 1012 1016 1020 1024 1028 1032 1 2 3 4 5 6 ? ? ? ?1036 a 1000 p 2000 #include <stdio.h> void print_array(int (*p)[3]) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf(“%dn”, p[i][j]); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(a); return 0; } 016_example.c
  • 74. Advanced C Pointers – Passing 2D array to function #include <stdio.h> void print_array(int row, int col, int (*p)[col]) { int i, j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { printf(“%dn”, p[i][j]); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(2, 3, a); return 0; } 017_example.c
  • 75. Advanced C Pointers – Passing 2D array to function #include <stdio.h> void print_array(int row, int col, int *p) { int i, j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { printf(“%dn”, *((p + i * col) + j)); } } } int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; print_array(2, 3, (int *) a); return 0; } 018_example.c
  • 76. Advanced C Pointers – 2D Array Creations ● Each Dimension could be Static or Dynamic ● Possible combination of creation could be – BS: Both Static (Rectangular) – FSSD: First Static, Second Dynamic – FDSS: First Dynamic, Second Static – BD: Both Dynamic
  • 77. Advanced C Pointers – 2D Array Creations - BS #include <stdio.h> int main() { int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; return 0; } ● Both Static (BS) ● Called as an rectangular array ● Total size is 2 * 3 * sizeof(datatype) 2 * 3 * 4 = 24 Bytes ● The memory representation can be as shown in next slide 018_example.c
  • 78. Advanced C Pointers – 2D Array Creations - BS 1000 1004 1008 1012 1016 1020 1 2 3 4 5 6 a 0 0 0 1 Static 3 Columns On Stack Static 2 Rows On Stack 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 6
  • 79. Advanced C Pointers – 2D Array Creations - FSSD #include <stdio.h> #include <stdlib.h> int main() { int *a[2]; for ( i = 0; i < 2; i++) { a[i] = malloc(3 * sizeof(int)); } return 0; } ● First Static and Second Dynamic (FSSD) ● Mix of Rectangular & Ragged ● Total size is 2 * sizeof(datatype *) + 2 * 3 * sizeof(datatype) 2 * 4 + 2 * 3 * 4 = 32 Bytes ● The memory representation can be as shown in next slide 019_example.c
  • 80. Advanced C Pointers – 2D Array Creations - FSSD 1004 1000 524 512 a 0 0 0 1 Dynamic 3 Columns On Heap Static 2 Rows On Heap 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 6 532 528 524 520 516 512 6 5 4 3 2 1 0 0 A 0 0 0 A C Pointers to 2 Rows On Stack
  • 81. Advanced C Pointers – 2D Array Creations - FDSS #include <stdio.h> #include <stdlib.h> int main() { int (*a)[3]; a = malloc(2 * sizeof(int [3])); return 0; } ● First Dynamic and Second Static (FDSS) ● Total size is sizeof(datatype *) + 2 * 3 * sizeof(datatype) 4 + 2 * 3 * 4 = 28 Bytes ● The memory representation can be as shown in next slide 020_example.c
  • 82. Advanced C Pointers – 2D Array Creations - FDSS 1000 512 a 0 0 0 1 Static 3 Columns On Heap Dynamic 2 Rows On Heap 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 4 532 528 524 520 516 512 6 5 4 3 2 1 0 0 A 0 Pointer to 1 Row On Stack
  • 83. Advanced C Pointers – 2D Array Creations - BD #include <stdio.h> #include <stdlib.h> int main() { int **a; int i; a = malloc(2 * sizeof(int *)); for (i = 0; i < 2; i++) { a[i] = malloc(3 * sizeof(int)); } return 0; } ● Both Dynamic (BD) ● Total size is sizeof(datatype **) + 2 * sizeof(datatype *) + 2 * 3 * sizeof(datatype) 4 + 2 * 4 + 2 * 3 * 4 = 36 Bytes ● The memory representation can be as shown in next slide 021_example.c
  • 84. Advanced C Pointers – 2D Array Creations - BD 0 0 0 1 Dynamic 3 Columns On Heap Dynamic 2 Rows On Heap 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 6 788 784 780 776 772 768 6 5 4 3 2 1 0 0 3 0 0 0 3 C Pointers to 2 Rows On Heap 516 512 780 768 1004 512 a 0 0 A 0 Pointer to 1 Row On Stack
  • 87. Advanced C Functions – Command Line Arguments #include <stdio.h> int main(int argc, char *argv[], char *envp[]) { return 0; } Example Passed Arguments on CL Arguments Count Environmental Variables user@user:~] ./a.out 5 + 3 Usage 4th argument 3rd argument 2nd argument 1st argument All stored in argv Total counts of the args stored in argc
  • 88. Advanced C Functions – Command Line Arguments #include <stdio.h> int main(int argc, char **argv) { int i; printf(“No of argument(s): %dn”, argc); printf(“List of argument(s):n”); for (i = 0; i < argc; i++) { printf(“t%d - ”%s”n”, i + 1, argv[i]); } return 0; } 001_example.c
  • 89. Advanced C Functions – Command Line Arguments Stack Text Segment Initialized Heap .BSS (Uninitialized ) Command Line Arguments Hole Data Segment Memory Segments 1000 1004 1008 4000 4100 4200 argv 4300 1012 NULL 1016 ‘.’ ‘/’ ‘a’ ‘.’ ‘o’ ‘u’ ‘t’ ‘0’ 4000 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘’0’ 4100 ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘’0’ 4200 ‘W’ ‘e’ ‘l’ ‘c’ ‘o’ ‘m’ ‘e’ ‘0’ 4300 user@user:~] ./a.out Hello World Welcome Example [0] [1] [2] [3] [4] [0][0] [1][0] [2][0] [3][0]
  • 90. Advanced C Functions – Command Line Arguments - DIY ● Print all the Environmental Variables ● WAP to calculate average of numbers passed via command line
  • 92. Advanced C Functions – Function Pointers ● A variable that stores the address of a function. Therefore, points to the function. Syntax return_datatype (*foo)(list of argument(s) datatype);
  • 93. Advanced C Functions – Function Pointers #include <stdio.h> int add(int num1, int num2) { return num1 + num2; } int main() { printf(“%pn”, add); printf(“%pn”, &add); return 0; } ● Every function code would be stored in the text segment with an address associated with it ● This example would print the address of the add function 002_example.c
  • 94. Advanced C Functions – Function Pointers ● Hold on!!. Can't I store the address on the normal pointer?? ● Well, Yes you can! But how would you expect the compiler to interpret this? ● The compiler interprets this as a pointer to normal variable and not the code ● Then how to do it? #include <stdio.h> int add(int num1, int num2) { return num1 + num2; } int main() { int *fptr; fptr = add; printf(“%pn”, add); printf(“%pn”, fptr); printf(“%pn”, &fptr); return 0; } 003_example.c
  • 95. Advanced C Functions – Function Pointers ● The address of the function should be stored in a function pointer ● Not to forget that the function pointer is a variable and would have address for itself #include <stdio.h> int add(int num1, int num2) { return num1 + num2; } int main() { int (*fptr)(int, int); fptr = add; printf(“%pn”, add); printf(“%pn”, fptr); printf(“%pn”, &fptr); return 0; } 004_example.c
  • 96. Advanced C Functions – Function Pointers ● The function pointer could be invoked as shown in the example #include <stdio.h> int add(int num1, int num2) { return num1 + num2; } int main() { int (*fptr)(int, int); fptr = add; printf(“%dn”, fptr(2, 4)); printf(“%dn”, (*fptr)(2, 4)); return 0; } 005_example.c
  • 97. Advanced C Functions – Func Ptr – Passing to functions int add(int num1, int num2) { return num1 + num2; } int sub(int num1, int num2) { return num1 - num2; } int oper(int (*f)(int, int), int a, int b) { return f(a, b); } 006_example.c
  • 98. Advanced C Functions – Array of Function Pointers 007_example.c
  • 99. Advanced C Functions – Array of Function Pointers 008_example.c int add(int num1, int num2) { return num1 + num2; } int sub(int num1, int num2) { return num1 - num2; } int oper(int (*f)(int, int), int a, int b) { return f(a, b); }
  • 100. Advanced C Functions – Func Ptr – Std Functions - atexit() 009_example.c void my_exit(void) { printf(“Exiting programn”); if (ptr) { /* Deallocation in my_exit */ free(ptr); } } void test(void) { puts(“In test”); exit(0); }
  • 101. Advanced C Functions – Func Ptr – Std Functions - qsort() 010_example.c int sa(const void *a, const void *b) { return *(int *) a > *(int *) b; } int sd(const void *a, const void *b) { return *(int *) a < *(int *) b; } void print(int *a, unsigned int size) { int i = 0; for (i = 0; i < size; i++) { printf(“%d ”, a[i]); } printf(“n”); }
  • 103. Advanced C Functions – Variadic ● Variadic functions can be called with any number of trailing arguments ● For example, printf(), scanf() are common variadic functions ● Variadic functions can be called in the usual way with individual arguments Syntax return_data_type function_name(parameter list, ...);
  • 104. Advanced C Functions – Variadic – Definition & Usage ● Defining and using a variadic function involves three steps: Step 1: Variadic functions are defined using an ellipsis (‘…’) in the argument list, and using special macros to access the variable arguments. Step 2: Declare the function as variadic, using a prototype with an ellipsis (‘…’), in all the files which call it. Step 3: Call the function by writing the fixed arguments followed by the additional variable arguments. int foo(int a, ...) { /* Function Body */ } Example
  • 105. Advanced C Functions – Variadic – Argument access macros ● Descriptions of the macros used to retrieve variable arguments ● These macros are defined in the header file stdarg.h Type/Macros Description va_list The type va_list is used for argument pointer variables va_start This macro initializes the argument pointer variable ap to point to the first of the optional arguments of the current function; last- required must be the last required argument to the function va_arg The va_arg macro returns the value of the next optional argument, and modifies the value of ap to point to the subsequent argument. Thus, successive uses of va_arg return successive optional arguments va_end This ends the use of ap
  • 106. Advanced C Functions – Variadic – Example 011_example.c int add(int count, ...) { va_list ap; int iter, sum; /* Initilize the arg list */ va_start(ap, count); sum = 0; for (iter = 0; iter < count; iter++) { /* Extract args */ sum += va_arg(ap, int); } /* Cleanup */ va_end(ap); return sum; }
  • 108. Advanced C Preprocessor ● One of the step performed before compilation ● Is a text substitution tool and it instructs the compiler to do required pre-processing before the actual compilation ● Instructions given to preprocessor are called preprocessor directives and they begin with “#” symbol ● Few advantages of using preprocessor directives would be, – Easy Development – Readability – Portability
  • 109. Advanced C Preprocessor – Compilation Stages ● Before we proceed with preprocessor directive let's try to understand the stages involved in compilation ● Some major steps involved in compilation are – Preprocessing (Textual replacement) – Compilation (Syntax and Semantic rules checking) – Assembly (Generate object file(s)) – Linking (Resolve linkages) ● The next slide provide the flow of these stages
  • 110. Advanced C Preprocessor – Compilation Stages Source Code Expanded Source Code Assembly Source Code Object Code Executable .cPreprocessor Compiler Assembler Linker Loader .i .s .o .out user@user:~] gcc -E file.c user@user:~] gcc -S file.c user@user:~] gcc -c file.c user@user:~] gcc file.c -o file.out user@user:~]gcc -save-temps file.c #would generate all intermediate files
  • 111. Advanced C Preprocessor – Compilation Steps .c .i .s user@user:~] cpp file.c -o file.i user@user:~] cc -S file.i -o file.s user@user:~] as file.s -o file.o user@user:~] ld file.o -o file.out <LIBRARY PATH> user@user:~]./file.out Bit complex step .o .out
  • 112. Advanced C Preprocessor – Compilation Steps .c .i .s user@user:~] gcc -E file.c -o file.i user@user:~] gcc -S file.i -o file.s user@user:~] gcc -c file.s -o file.o .o .out user@user:~] gcc file.o -o file.out user@user:~]./file.out
  • 113. Advanced C Preprocessor – Directives #include #define #undef #ifdef #ifndef #if #elif #else #endif #error #warning #line #pragma # ##
  • 114. Advanced C Preprocessor – Header Files ● A header file is a file containing C declarations and macro definitions to be shared between several source files. ● Has to be included using C preprocessing directive ‘#include' ● Header files serve two purposes. – Declare the interfaces to parts of the operating system by supplying the definitions and declarations you need to invoke system calls and libraries. – Your own header files contain declarations for interfaces between the source files of your program.
  • 115. Advanced C Preprocessor – Header Files vs Source Files .h .cVS ● Declarations ● Sharable/reusable ● #defines ● Datatypes ● Used by more than 1 file ● Function and variable definitions ● Non sharable/reusable ● #defines ● Datatypes
  • 116. Advanced C Preprocessor – Header Files - Syntax Syntax #include <file.h> ● System header files ● It searches for a file named file in a standard list of system directories Syntax #include “file.h” ● Local (your) header files ● It searches for a file named file first in the directory containing the current file, then in the quote directories and then the same directories used for <file>
  • 117. Advanced C Preprocessor – Header Files - Operation int num; #include “003_file2.h” int main() { puts(test()); return 0; } char *test(void); 002_file2.c char *test(void) { static char *str = “Hello”; return str; } int num; char *test(void); int main() { puts(test()); return 0; } user@user:~] gcc -E 001_file1.c 002_file2.c # You may add -P option too!! Compile as 001_file1.c 003_file2.h
  • 118. Advanced C Preprocessor – Header Files – Search Path int num; #include “003_file2.h” int main() { puts(test()); return 0; } char *test(void);char *test(void) { static char *str = “Hello”; return str; } user@user:~] gcc -E 001_file1.c 002_file2.c Compile as 002_file2.c 001_file1.c 003_file2.h
  • 119. Advanced C Preprocessor – Header Files – Search Path int num; #include <file2.h> int main() { puts(test()); return 0; } char *test(void);char *test(void) { static char *str = “Hello”; return str; } user@user:~] gcc -E 001_file1.c 002_file2.c -I . Compile as 002_file2.c 001_file1.c 003_file2.h
  • 120. Advanced C Preprocessor – Header Files – Search Path ● On a normal Unix system GCC by default will look for headers requested with #include <file> in: – /usr/local/include – libdir/gcc/target/version/include – /usr/target/include – /usr/include ● You can add to this list with the -I <dir> command-line option user@user:~] cpp -v /dev/null -o /dev/null #would show search the path info Get it as
  • 121. Advanced C Preprocessor – Macro – Object-Like ● An object-like macro is a simple identifier which will be replaced by a code fragment ● It is called object-like because it looks like a data object in code that uses it. ● They are most commonly used to give symbolic names to numeric constants #define SYMBOLIC_NAME CONSTANTS Syntax #define BUFFER_SIZE 1024 Example
  • 122. Advanced C Preprocessor – Macro – Object-Like #define SIZE 1024 #define MSG “Enter a string” int main() { char array[SIZE]; printf(“%sn”, MSG); fgets(array, SIZE, stdin); printf(“%sn”, array); return 0; } # 1 "main.c" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "main.c" int main() { char array[1024]; printf("%sn", “Enter a string”); fgets(array, 1024, stdin); printf("%sn", array); return 0; } user@user:~] gcc -E 004_example.c -o 004_example.i Compile as 004_example.c 004_example.i
  • 123. Advanced C Preprocessor – Macro – Standard Predefined ● Several object-like macros are predefined; you use them without supplying their definitions. ● Standard are specified by the relevant language standards, so they are available with all compilers that implement those standards #include <stdio.h> int main() { printf(“Program: “%s” ”, __FILE__); printf(“was compiled on %s at %s. ”, __DATE__, __TIME__); printf(“This print is from Function: ”%s””, __func__); printf(“at line %dn”, __LINE__); return 0; } 005_example.c
  • 124. Advanced C Preprocessor – Macro – Arguments ● Function-like macros can take arguments, just like true functions ● To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like Syntax #define MACRO(ARGUMENT(S)) (EXPRESSION WITH ARGUMENT(S))
  • 125. Advanced C Preprocessor – Macro – Arguments #include <stdio.h> #define SET_BIT(num, pos) num | (1 << pos) int main() { printf(“%dn”, 2 * SET_BIT(0, 2)); return 0; } int main() { printf(“%dn”, 2 * 0 | (1 << 2)); return 0; } 006_example.c 006_example.i
  • 126. Advanced C Preprocessor – Macro – Arguments #include <stdio.h> #define SET_BIT(num, pos) (num | (1 << pos)) int main() { printf(“%dn”, 2 * SET_BIT(0, 2)); return 0; } int main() { printf(“%dn”, 2 * (0 | (1 << 2))); return 0; } 007_example.c 007_example.i
  • 127. Advanced C Preprocessor – Macro – Arguments - DIY ● WAM to find the sum of two nos ● Write macros to get, set and clear Nth bit in an integer ● WAM to swap a nibble in a byte
  • 128. Advanced C Preprocessor – Macro – Multiple Lines ● You may continue the definition onto multiple lines, if necessary, using backslash-newline. ● This could be done to achieve readability ● When the macro is expanded, however, it will all come out on one line
  • 129. Advanced C Preprocessor – Macro – Multiple Lines #include <stdio.h> #define SWAP(a, b) int temp = a; a = b; b = temp; int main() { int n1 = 10, n2= 20; SWAP(n1, n2); printf(“%d %dn”, n1, n2); SWAP(n1, n2); printf(“%d %dn”, n1, n2); return 0; } int main() { int n1 = 10, n2= 20; int temp = n1;n1 = n2;n2 = temp; printf(“%d %dn”, n1, n2); int temp = n1;n1 = n2;n2 = temp; printf(“%d %dn”, n1, n2); return 0; } 008_example.c 008_example.i
  • 130. Advanced C Preprocessor – Macro – Multiple Lines #include <stdio.h> #define SWAP(a, b) { int temp = a; a = b; b = temp; } int main() { int n1 = 10, n2= 20; SWAP(n1, n2); printf(“%d %dn”, n1, n2); SWAP(n1, n2); printf(“%d %dn”, n1, n2); return 0; } int main() { int n1 = 10, n2= 20; {int temp = n1;n1 = n2;n2 = temp;} printf(“%d %dn”, n1, n2); {int temp = n1;n1 = n2;n2 = temp;} printf(“%d %dn”, n1, n2); return 0; } 009_example.c 009_example.i
  • 131. Advanced C Preprocessor – Macro – Multiple Lines - DIY ● WAM to swap any two numbers of basic type using temporary variable
  • 132. Advanced C Preprocessor – Macro vs Function Function #include <stdio.h> int set_bt(int n, int p) { return (n | (1 << p)); } int main() { printf(“%dn”, 2 * set_bt(0, 2)); printf(“%dn”, 4 * set_bt(0, 2)); return 0; } Macro #include <stdio.h> #define set_bt(n, p) (n | (1 << p)) int main() { printf(“%dn”, 2 * set_bt(0, 2)); printf(“%dn”, 4 * set_bt(0, 2)); return 0; } ● Context switching overhead ● Stack frame creation overhead ● Space optimized on repeated call ● Compiled at compile stage, invoked at run time ● Type sensitive ● Recommended for larger operation ● No context switching overhead ● No stack frame creation overhead ● Time optimized on repeated call ● Preprocessed and expanded at preprocessing stage ● Type insensitive ● Recommended for smaller operation
  • 133. Advanced C Preprocessor – Macro – Stringification #include <stdio.h> #define WARN_IF(EXP) do { x--; if (EXP) { fprintf(stderr, "Warning: " #EXP "n"); } } while (x); int main() { int x = 5; WARN_IF(x == 0); return 0; } ● You can convert a macro argument into a string constant by adding # 010_example.c
  • 134. Advanced C Preprocessor – Conditional Compilation ● A conditional is a directive that instructs the preprocessor to select whether or not to include a chunk of code in the final token stream passed to the compiler ● Preprocessor conditionals can test arithmetic expressions, or whether a name is defined as a macro, or both simultaneously using the special defined operator ● A conditional in the C preprocessor resembles in some ways an if statement in C with the only difference being it happens in compile time ● Its purpose is to allow different code to be included in the program depending on the situation at the time of compilation.
  • 135. Advanced C Preprocessor – Conditional Compilation ● There are three general reasons to use a conditional. – Portability: A program may need to use different code depending on the machine or operating system it is to run on – Testing: You may want to be able to compile the same source file into two different programs, like one for debug (Test) and other as final (Production) – Reference Code: A conditional whose condition is always false is one way to exclude code from the program but keep it as a sort of comment for future reference
  • 136. Advanced C Preprocessor – Header Files – Once-Only ● If a header file happens to be included twice, the compiler will process its contents twice causing an error ● E.g. when the compiler sees the same structure definition twice ● This can be avoided like #ifndef NAME #define NAME /* The entire file is protected */ #endif Syntax
  • 137. Advanced C Preprocessor – Header Files – Once-Only #include “012_example.h” #include “012_example.h” int main() { struct UserInfo p = {420, “Tingu”}; return 0; } struct UserInfo { int id; char name[30]; }; ● Note that, 012_exampe.h is included 2 times which would lead to redefinition of the structure UserInfo 011_example.c 012_example.h
  • 138. Advanced C Preprocessor – Header Files – Once-Only #include “014_example.h” #include “014_example.h” int main() { struct UserInfo p = {420, “Tingu”}; return 0; } #ifndef EXAMPLE_014_H #define EXAMPLE_014_H struct UserInfo { int id; char name[30]; }; #endif ● The multiple inclusion is protected by the #ifndef preprocessor directive 013_example.c 014_example.h
  • 139. Advanced C Preprocessor – Header Files – Once-Only #include “016_example.h” #include “016_example.h” int main() { struct UserInfo p = {420, “Tingu”}; return 0; } #pragma once struct UserInfo { int id; char name[30]; }; ● The other way to do this would be #pragma once directive ● This is not portable 015_example.c 016_example.h
  • 140. Advanced C Preprocessor – Conditional Compilation - ifdef #ifdef MACRO /* Controlled Text */ #endif #include <stdio.h> #define METHOD1 int main() { #ifdef METHOD1 puts(“Hello World”); #else printf(“Hello World”); #endif return 0; } #ifdef MACRO /* Controlled Text */ #endif 017_example.cSyntax
  • 141. Advanced C Preprocessor – Conditional Compilation - ifndef #include <stdio.h> #undef METHOD1 int main() { #ifndef METHOD1 puts(“Hello World”); #else printf(“Hello World”); #endif return 0; } #ifndef MACRO /* Controlled Text */ #endif 018_example.cSyntax
  • 142. Advanced C Preprocessor – Conditional Compilation - defined #if defined condition /* Controlled Text */ #endif #include <stdio.h> #define METHOD1 int main() { #if defined (METHOD1) puts(“Hello World”); #endif #if defined (METHOD2) printf(“Hello World”); #endif #if defined (METHOD1) && defined (METHOD2) puts(“Hello World”); printf(“Hello World”); #endif return 0; } 019_example.cSyntax
  • 143. Advanced C Preprocessor – Conditional Compilation - if #if expression /* Controlled Text */ #endif #include <stdio.h> #define METHOD 1 int main() { #if METHOD == 1 puts(“Hello World”); #endif #if METHOD == 2 printf(“Hello World”); #endif return 0; } 020_example.cSyntax
  • 144. Advanced C Preprocessor – Conditional Compilation - else #if expression /* Controlled Text if true */ #else /* Controlled Text if false */ #endif #include <stdio.h> #define METHOD 0 int main() { #if METHOD == 1 puts(“Hello World”); #else printf(“Hello World”); #endif return 0; } 021_example.cSyntax
  • 145. Advanced C Preprocessor – Conditional Compilation - elif #if expression1 /* Controlled Text*/ #elif expression2 /* Controlled Text */ #else /* Controlled Text */ #endif #include <stdio.h> #define METHOD 1 int main() { char msg[] = “Hello World”; #if METHOD == 1 puts(msg); #elif METHOD == 2 printf(“%sn”, msg); #else int i; for (i = 0; i < 12; i++) { putchar(msg[i]); } #endif return 0; } 022_example.cSyntax
  • 146. Advanced C Preprocessor – Cond... Com... – CL Option #include <stdio.h> int main() { int x = 10, y = 20; #ifdef SPACE_OPTIMIZED x = x ^ y; y = x ^ y; x = x ^ y; printf(“Selected Space Optimizationn”); #else int temp; temp = x; x = y; y = temp; printf(“Selected Time Optimizationn”); #endif return 0; } user@user:~] gcc main.c -D SPACE_OPTIMIZED Compile as 023_example.c
  • 147. Advanced C Preprocessor – Cond... Com... – Deleted Code #if 0 /* Deleted code while compiling */ /* Can be used for nested code comments */ /* Avoid for general comments */ /* Don't write lines like these!! with ' #endif 024_example.c
  • 148. Advanced C Preprocessor – Diagnostic ● The directive #error causes the preprocessor to report a fatal error. The tokens forming the rest of the line following #error are used as the error message ● The directive #warning is like #error, but causes the preprocessor to issue a warning and continue preprocessing. The tokens following #warning are used as the warning message
  • 149. Advanced C Preprocessor – Diagnostic - #warning #include <stdio.h> #if defined DEBUG_PRINT #warning “Debug print enabled” #endif int main() { int sum, num1, num2; printf(“Enter 2 numbers: ”); scanf(“%d %d”, &num1, &num2); #ifdef DEBUG_PRINT printf(“The entered values are %d %dn”, num1, num2); #endif sum = num1 + num2; printf(“The sum is %dn”, sum); return 0; } 025_example.c
  • 150. Advanced C Preprocessor – Diagnostic - #error #include <stdio.h> #if defined (STATIC) || defined (DYNAMIC) #define SIZE 100 #else #error “Memory not allocated!! Use -D STATIC or DYNAMIC while compiling” #endif int main() { #if defined STATIC char buffer[SIZE]; #elif defined DYNAMIC char *buffer = malloc(SIZE * sizeof(char)); #endif #if defined (STATIC) || defined (DYNAMIC) fgets(buffer, SIZE, stdin); printf(“%sn”, buffer); #endif return 0; } 026_example.c
  • 151. Advanced C Preprocessor – Diagnostic - #line ● Also known as preprocessor line control directive ● #line directive can be used to alter the line number and filename ● The line number will start from the set value, from the #line is encountered with the provided name #include <stdio.h> int main() { #line 100 “project tuntun” printf(“This is from file %s at line %d n”, __FILE__, __LINE__); return 0; } 027_example.c
  • 153. Advanced C User Defined Datatypes (Composite Data Types) ● Sometimes it becomes tough to build a whole software that works only with integers, floating values, and characters. ● In circumstances such as these, you can create your own data types which are based on the standard ones ● There are some mechanisms for doing this in C: – Structure (derived) – Unions (derived) – Typedef (storage class) – Enum (user defined) ● Hoo!!, let's not forget our old friend _r_a_ which is a user defined data type too!!.
  • 154. Advanced C User Defined Datatypes (Composite Data Types) : Composite (or Compound) Data Type : ● Any data type which can be constructed from primitive data types and other composite types ● It is sometimes called a structure or aggregate data type ● Primitives types – int, char, float, double
  • 156. Advanced C UDTs - Structures struct StructureName { /* Group of data types */ }; Syntax ● So if we create a structure of the above requirement, it would look like, struct Student { int id; char name[20]; char address[60]; }; Example ● If we consider the Student as an example, The admin should have at least some important data like name, ID and address.
  • 157. Advanced C UDTs – Structures – Declaration and definition struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1; return 0; } ● Name of the datatype. Note it's struct Student and not Student ● Are called as fields or members of of the structure ● Declaration ends here ● The memory is not yet allocated!! ● s1 is a variable of type struct Student ● The memory is allocated now 001_example.c
  • 158. Advanced C UDTs – Structures – Memory Layout ● What does s1 contain? ● How can we draw it's memory layout? #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1; return 0; } 001_example.c ? ? ? id name address s1
  • 159. Advanced C UDTs – Structures – Memory Layout Structure size depends in the member arrangment!!. Will discuss that shortly 4 Bytes 20 Bytes 60 Bytes id name address s1 002_example.c
  • 160. #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1; s1.id = 10; return 0; } ● How to write into id now? ● It's by using “.” (Dot) operator (member access operator) ● Now please assign the name member of s1 10 ? ? id name address s1 003_example.c Advanced C UDTs – Structures – Access
  • 161. Advanced C UDTs – Structures - Initialization #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1 = {10, “Tingu”, “Bangalore”}; return 0; } 10 "Tingu" Bangalore id name address s1 004_example.c
  • 162. Advanced C UDTs – Structures - Copy #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1 = {10, “Tingu”, “Bangalore”}; struct Student s2; s2 = s1; return 0; } Structure name does not represent its address. (No correlation with arrays) 10 "Tingu" Bangalore id name address s2 005_example.c
  • 163. Advanced C UDTs – Structures - Address #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s1 = {10, “Tingu”, “Bangalore”}; printf(“Struture starts at %pn”, &s1); printf(“Member id is at %pn”, &s1.id); printf(“Member name is at %pn”, s1.name); printf(“Member address is at %pn”, s1.address); return 0; } 10 "Tingu" Bangalore id name address s1 1000 006_example.c
  • 164. Advanced C UDTs – Structures - Pointers ● Pointers!!!. Not again ;). Fine don't worry, not a big deal ● But do you any idea how to create it? ● Will it be different from defining them like in other data types?
  • 165. Advanced C UDTs – Structures - Pointer #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; static struct Student s1; int main() { struct Student *sptr = &s1; return 0; } 1000 sptr 1000 2000 id name address s1 ? ? ? 007_example.c
  • 166. Advanced C UDTs – Structures – Pointer - Access 1000 sptr 1000 2000 id name address s1 10 ? ? #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; static struct Student s1; int main() { struct Student *sptr = &s1; (*sptr).id = 10; return 0; } 008_example.c
  • 167. Advanced C UDTs – Structures – Pointer – Access – Arrow Note: we can access the structure pointer as seen in the previous slide. The Arrow operator is just convenience and frequently used 1000 sptr 1000 2000 id name address s1 10 ? ? Note: we can access the structure pointer as seen in the previous slide. The Arrow operator is just convenience and frequently used #include <stdio.h> struct Student { int id; char name[20]; char address[60]; }; static struct Student s1; int main() { struct Student *sptr = &s1; sptr->id = 10; return 0; } 009_example.c
  • 168. Advanced C UDTs – Structures - Functions ● The structures can be passed as parameter and can be returned from a function ● This happens just like normal datatypes. ● The parameter passing can have two methods again as normal – Pass by value – Pass by reference
  • 169. Advanced C UDTs – Structures – Functions – Pass by Value #include <stdio.h> struct Student { int id; char name[30]; char address[150]; }; void data(struct Student s) { s.id = 10; } int main() { struct Student s1; data(s1); return 0; } Not recommended on larger structures 010_example.c
  • 170. Advanced C UDTs – Structures – Functions – Pass by Reference Recommended on larger structures #include <stdio.h> struct Student { int id; char name[30]; char address[150]; }; void data(struct Student *s) { s->id = 10; } int main() { struct Student s1; data(&s1); return 0; } 011_example.c
  • 171. Advanced C UDTs – Structures – Functions – Return struct Student { int id; char *name; char *address; }; struct Student data(void) { struct Student s; s.name = (char *) malloc(30 * sizeof(char)); s.address = (char *) malloc(150 * sizeof(char)); return s; } int main() { struct Student s1; s1 = data(); return 0; } 012_example.c
  • 172. Advanced C UDTs – Structures – Array struct Student { int id; char name[20]; char address[60]; }; int main() { struct Student s[5]; int i; for (i = 0; i < 5; i++) { scanf(“%d”, &s[i].id); } for (i = 0; i < 5; i++) { printf(“s[%d].id is %dn”, i, s[i].id); } return 0; } 013_example.c
  • 173. Advanced C UDTs – Structures – Nesting struct College { struct Student { int id; char name[20]; char address[60]; } student; struct { int id; char name[20]; char address[60]; } faculty; }; int main() { struct College member; member.student.id = 10; member.faculty.id = 20; return 0; } 014_example.c
  • 174. Advanced C UDTs – Structures – Padding ● Adding of few extra useless bytes (in fact skip address) in between the address of the members are called structure padding. ● What!!?, wasting extra bytes!!, Why? ● This is done for Data Alignment. ● Now!, what is data alignment and why did this issue suddenly arise? ● No its is not sudden, it is something the compiler would be doing internally while allocating memory. ● So let's understand data alignment in next few slides
  • 175. Advanced C Data Alignment ● A way the data is arranged and accessed in computer memory. ● When a modern computer reads from or writes to a memory address, it will do this in word sized chunks (4 bytes in 32 bit system) or larger. ● The main idea is to increase the efficiency of the CPU, while handling the data, by arranging at a memory address equal to some multiple of the word size ● So, Data alignment is an important issue for all programmers who directly use memory.
  • 176. Advanced C Data Alignment ● If you don't understand data and its address alignment issues in your software, the following scenarios, in increasing order of severity, are all possible: – Your software will run slower. – Your application will lock up. – Your operating system will crash. – Your software will silently fail, yielding incorrect results.
  • 177. Advanced C Data Alignment int main() { char ch = 'A'; int num = 0x12345678; } Example ● Lets consider the code as given ● The memory allocation we expect would be like shown in figure ● So lets see how the CPU tries to access these data in next slides ch 78 56 34 12 ? ? ? 0 1 2 3 4 5 6 7
  • 178. Advanced C Data Alignment ● Fetching a character by the CPU will be like shown below 41 78 56 34 12 ? ? ? 0 1 2 3 4 5 6 7 0 4 Bytes 41 78 56 34 41 0 0 0 Example int main() { char ch = 'A'; int num = 0x12345678; }
  • 179. Advanced C Data Alignment ● Fetching integer by the CPU will be like shown below 41 78 56 34 12 ? ? ? 0 1 2 3 4 5 6 7 0 4 Bytes 41 78 56 34 Example int main() { char ch = 'A'; int num = 0x12345678; }
  • 180. Advanced C Data Alignment ● Fetching the integer by the CPU will be like shown below 41 78 56 34 12 ? ? ? 0 1 2 3 4 5 6 7 4 4 Bytes 41 78 56 34 12 ? ? ? Example int main() { char ch = 'A'; int num = 0x12345678; }
  • 181. Advanced C Data Alignment ● Fetching the integer by the CPU will be like shown below 41 78 56 34 12 ? ? ? 0 1 2 3 4 5 6 7 41 78 56 34 12 ? ? ? 78 56 34 0 Shift 1 Byte Up 0 0 0 12 78 56 34 12 Shift 3 Byte Down Combine Example int main() { char ch = 'A'; int num = 0x12345678; }
  • 182. Advanced C UDTs – Structures – Data Alignment - Padding ● Because of the data alignment issue, structures uses padding between its members if they don't fall under even address. ● So if we consider the following structure the memory allocation will be like shown in below figure struct Test { char ch1; int num; char ch2; } ch1 pad pad pad num num num num 0 1 2 3 4 5 6 7 ch2 pad pad pad 8 9 A B Example
  • 183. Advanced C UDTs – Structures – Data Alignment - Padding ● You can instruct the compiler to modify the default padding behavior using #pragma pack directive #pragma pack(1) struct Test { char ch1; int num; char ch2; }; ch1 num num num num ch2 0 1 2 3 4 5 Example
  • 184. Advanced C UDTs – Structures – Padding #include <stdio.h> struct Student { char ch1; int num; char ch2; }; int main() { struct Student s1; printf(“%zun”, sizeof(struct Student)); return 0; } 015_example.c
  • 185. Advanced C UDTs – Structures – Padding #include <stdio.h> #pragma pack(1) struct Student { char ch1; int num; char ch2; }; int main() { struct Student s1; printf(“%zun”, sizeof(struct Student)); return 0; } 016_example.c
  • 186. Advanced C UDTs – Structures – Bit Fields ● The compiler generally gives the memory allocation in multiples of bytes, like 1, 2, 4 etc., ● What if we want to have freedom of having getting allocations in bits?!. ● This can be achieved with bit fields. ● But note that – The minimum memory allocation for a bit field member would be a byte that can be broken in max of 8 bits – The maximum number of bits assigned to a member would depend on the length modifier – The default size is equal to word size
  • 187. Advanced C UDTs – Structures – Bit Fields struct Nibble { unsigned char lower : 4; unsigned char upper : 4; }; ● The above structure divides a char into two nibbles ● We can access these nibbles independently Example
  • 188. Advanced C UDTs – Structures – Bit Fields struct Nibble { unsigned char lower : 4; unsigned char upper : 4; }; int main() { struct Nibble nibble; nibble.upper = 0x0A; nibble.lower = 0x02; return 0; } ?1000 nibble ? ? ? ? ? ? ? ? 017_example.c
  • 189. Advanced C UDTs – Structures – Bit Fields 0xA?1000 nibble 1 0 1 0 ? ? ? ? struct Nibble { unsigned char lower : 4; unsigned char upper : 4; }; int main() { struct Nibble nibble; nibble.upper = 0x0A; nibble.lower = 0x02; return 0; } 017_example.c
  • 190. Advanced C UDTs – Structures – Bit Fields 0xA21000 nibble 1 0 1 0 0 0 1 0 struct Nibble { unsigned char lower : 4; unsigned char upper : 4; }; int main() { struct Nibble nibble; nibble.upper = 0x0A; nibble.lower = 0x02; return 0; } 017_example.c
  • 191. Advanced C UDTs – Structures – Bit Fields struct Nibble { unsigned char lower : 4; unsigned char upper : 4; }; int main() { struct Nibble nibble; printf(“%zun”, sizeof(nibble)); return 0; } 018_example.c
  • 192. Advanced C UDTs – Structures – Bit Fields struct Nibble { unsigned lower : 4; unsigned upper : 4; }; int main() { struct Nibble nibble; printf(“%zun”, sizeof(nibble)); return 0; } 019_example.c
  • 193. Advanced C UDTs – Structures – Bit Fields struct Nibble { char lower : 4; char upper : 4; }; int main() { struct Nibble nibble; nibble.upper = 0x0A; nibble.lower = 0x02; printf(“%dn”, nibble.upper); printf(“%dn”, nibble.lower); return 0; } 019_example.c
  • 194. Advanced C UDTs – Structures – Bit Fields struct Nibble { char lower : 4; char upper : 4; }; int main() { struct Nibble nibble = {0x02, 0x0A}; printf(“%#on”, nibble.upper); printf(“%#xn”, nibble.lower); return 0; } 020_example.c
  • 196. Advanced C UDTs – Unions ● Like structures, unions may have different members with different data types. ● The major difference is, the structure members get different memory allocation, and in case of unions there will be single memory allocation for the biggest data type
  • 197. Advanced C UDTs – Unions union Test { char option; int id; double height; }; ● The above union will get the size allocated for the type double ● The size of the union will be 8 bytes. ● All members will be using the same space when accessed ● The value the union contain would be the latest update ● So as summary a single variable can store different type of data as required Example
  • 198. Advanced C UDTs – Unions union Test { char option; int id; double height; }; int main() { union Test temp_var; temp_var.height = 7.2; temp_var.id = 0x1234; temp_var.option = '1'; return 0; } ? ? ? ? 1000 ? ? ? ? 1007 Total 8 Bytes allocated since longest member is double temp_var 021_example.c
  • 199. Advanced C UDTs – Unions 0xCC 0xCC 0X1C 0X40 1000 0xCD 0xCC 0xCC 0xCC 1007 double uses its memory temp_var union Test { char option; int id; double height; }; int main() { union Test temp_var; temp_var.height = 7.2; temp_var.id = 0x1234; temp_var.option = '1'; return 0; } 021_example.c
  • 200. Advanced C UDTs – Unions 0xCC 0xCC 0X1C 0X40 1000 0x34 0x12 0x00 0x00 1007 int shares double's memory temp_var union Test { char option; int id; double height; }; int main() { union Test temp_var; temp_var.height = 7.2; temp_var.id = 0x1234; temp_var.option = '1'; return 0; } 021_example.c
  • 201. Advanced C UDTs – Unions 0xCC 0xCC 0X1C 0X40 1000 0x31 0x12 0x00 0x00 1007 char shares double's memory temp_var union Test { char option; int id; double height; }; int main() { union Test temp_var; temp_var.height = 7.2; temp_var.id = 0x1234; temp_var.option = '1'; return 0; } 021_example.c
  • 202. Advanced C UDTs – Unions union FloatBits { float degree; struct { unsigned m : 23; unsigned e : 8; unsigned s : 1; } elements; }; int main() { union FloatBits fb = {3.2}; printf(“Sign: %Xn”, fb.elements.s); printf(“Exponent: %Xn”, fb.elements.e); printf(“Mantissa: %Xn”, fb.elements.m); return 0; } 1000 0xCD 0xCC 0x4C 0x401004 fb 022_example.c
  • 203. Advanced C UDTs – Unions union Endian { unsigned int value; unsigned char byte[4]; }; int main() { union Endian e = {0x12345678}; e.byte[0] == 0x78 ? printf(“Littlen”) : printf(“Bign”); return 0; } 023_example.c
  • 204. Advanced C UDTs - Typedefs ● Typedef is used to create a new name to the existing types. ● K&R states that there are two reasons for using a typedef. – First, it provides a means to make a program more portable. Instead of having to change a type everywhere it appears throughout the program's source files, only a single typedef statement needs to be changed. – Second, a typedef can make a complex definition or declaration easier to understand.
  • 205. Advanced C UDTs - Typedefs typedef unsigned int uint; int main() { uint number; return 0; } typedef int * int_ptr; typedef float * float_ptr; int main() { int_ptr ptr1, ptr2, ptr3; float_ptr fptr; return 0; } typedef int array_of_100[100]; int main() { array_of_100 array; printf(“%zun”, sizeof(array)); return 0; } 025_example.c 026_example.c 027_example.c
  • 206. Advanced C UDTs - Typedefs typedef struct _Student { int id; char name[30]; char address[150] } Student; void data(Student s) { s.id = 10; } int main() { Student s1; data(s1); return 0; } #include <stdio.h> typedef int (*fptr)(int, int); int add(int num1, int num2) { return num1 + num2; } int main() { fptr function; function = add; printf(“%dn”, function(2, 4)); return 0; } 028_example.c 029_example.c
  • 207. Advanced C UDTs - Typedefs #include <stdio.h> typedef signed int sint, si; typedef unsigned int uint, ui; typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; int main() { u8 count = 200; s16 axis = -70; printf(“%un”, count); printf(“%dn”, axis); return 0; } 030_example.c
  • 208. Advanced C UDTs – Typedefs - Standard size_t – stdio.h ssize_t – stdio.h va_list – stdarg.h Example
  • 209. Advanced C UDTs – Typedefs - Usage typedef struct Sensor { int id; char name[12]; int version; /* * The members of an anonymous union * are considered to be members of the * containing structure. */ union { // Anonymous union float temperature; float humidity; char motion[4]; }; } Sensor; 031_example.c
  • 210. Advanced C UDTs – Enums ● Set of named integral values ● Generally referred as named integral constants enum name { /* Members separated with , */ }; Syntax
  • 211. Advanced C UDTs – Enums enum bool { e_false, e_true }; int main() { printf(“%dn”, e_false); printf(“%dn”, e_true); return 0; } ● The above example has two members with its values starting from 0. i.e, e_false = 0 and e_true = 1. 032_example.c
  • 212. Advanced C UDTs – Enums ● The member values can be explicitly initialized ● There is no constraint in values, it can be in any order and same values can be repeated ● The derived data type can be used to define new members which will be uninitialized typedef enum { e_red = 1, e_blue = 4, e_green } Color; int main() { Color e_white = 0, e_black; printf(“%dn”, e_white); printf(“%dn”, e_black); printf(“%dn”, e_green); return 0; } 033_example.c
  • 213. Advanced C UDTs – Enums ● Enums does not have name space of its own, so we cannot have same name used again in the same scope. int main() { typedef enum { red, blue } Color; int blue; printf(“%dn”, blue); printf(“%dn”, blue); return 0; } 034_example.c
  • 214. Advanced C UDTs – Enums ● Size of Enum does not depend on number of members typedef enum { red, blue, green } Color; int main() { Color c; printf(“%zun”, sizeof(Color)); printf(“%zun”, sizeof(c)); return 0; } 035_example.c
  • 215. Advanced C UDTs - DIY ● WAP to accept students record. Expect the below output user@user:~]./students_record.out Enter the number of students : 2 Enter name of the student : Tingu Enter P, C and M marks : 23 22 12   Enter name of the student : Pingu Enter P, C and M marks : 98 87 87 -------------------------------------------------------------- Name Maths Physics Chemistry        -------------------------------------------------------------- Tingu 12 23 22          Pingu 87 98 87          -------------------------------------------------------------- Average          49.50            60.50            54.50       -------------------------------------------------------------- user@user:~] Screen Shot
  • 216. Advanced C UDTs - DIY ● WAP to program to swap a nibble using bit fields
  • 218. Advanced C File Input / Output ● Sequence of bytes ● Could be regular or binary file ● Why? – Persistent storage – Theoretically unlimited size – Flexibility of storing any type data
  • 219. Advanced C File Input / Output ^@^@^@^@^@^@^@^@^@^@^ @^@^@^@^@^@^@^@^@^F^@^ @^@^P^@^@^@RåtdÔ<91>^Z^ @^@^Pw·^X^Aù¿^@^@^@^@Øþø ¿0Éu·^@^@^@^@^@^@^@^@^@ ^@^@^@^C^@^@^@^@^@^@^ @ðÈu·H^Aù¿&ìu·^X^Aù ¿^@^ @^@^@^D^@^@^@x^Xw·^@^@^ @^@^T^Aù¿^P^Aù¿Í<8d>u·ýßX·^L^ Fu·^P^Aù¿^O^Aù¿^@ÿø¿ A regular file looks normal as it appears here. regular files are generally group of ASCII characters hence the Sometimes called as text files which is human readable. The binary file typically contains the raw data. The contents of a Binary file is not human readable Regular File Binary File
  • 220. Advanced C File Input / Output – Via Redirection ● General way for feeding and getting the output is using standard input (keyboard) and output (screen) ● By using redirection we can achieve it with files i.e ./a.out < input_file > output_file ● The above line feed the input from input_file and output to output_file ● The above might look useful, but its the part of the OS and the C doesn't work this way ● C has a general mechanism for reading and writing files, which is more flexible than redirection
  • 221. Advanced C File Input / Output ● C abstracts all file operations into operations on streams of bytes, which may be "input streams" or "output streams" ● No direct support for random-access data files ● To read from a record in the middle of a file, the programmer must create a stream, seek to the middle of the file, and then read bytes in sequence from the stream ● Let's discuss some commonly used file I/O functions
  • 222. Advanced C File IO – File Pointer ● stdio.h is used for file I/O library functions ● The data type for file operation generally is ● FILE pointer, which will let the program keep track of the file being accessed ● Operations on the files can be – Open – File operations – Close Type FILE *fp;
  • 223. Advanced C File IO – Functions – fopen() & fclose() Prototype FILE *fopen(const char *path, const char *mode); int fclose(FILE *stream); Where mode are: r - open for reading w - open for writing (file need not exist) a - open for appending (file need not exist) r+ - open for reading and writing, start at beginning w+ - open for reading and writing (overwrite file) a+ - open for reading and writing (append if file exists) #include <stdio.h> int main() { FILE *fp; fp = fopen(“test.txt”, “r”); fclose(fp); return 0; } 001_example.c
  • 224. Advanced C File IO – Functions – fopen() & fclose() #include <stdio.h> #include <stdlib.h> int main() { FILE *input_fp; input_fp = fopen(“text.txt”, “r”); if (input_fp == NULL) { return 1; } fclose(input_fp); return 0; } 002_example.c
  • 225. Advanced C File IO – DIY ● Create a file named text.txt and add some content to it. – WAP to print its contents on standard output – WAP to copy its contents in text_copy.txt
  • 226. Advanced C File IO – Functions – feof() #include <stdio.h> #include <stdlib.h> int main() { FILE *fptr; char ch; fptr = fopen(“/etc/shells”, “r”); /* Need to do error checking on fopen() */ while (ch = fgetc(fptr)) { if (feof(fptr)) break; fputc(ch, stdout); } fclose(fptr); return 0; } 003_example.c
  • 227. Advanced C File IO – Functions – ferror() and clearerr() #include <stdio.h> int main() { FILE *fptr; char ch; fptr = fopen(“file.txt”, “w”); ch = fgetc(fptr);/* This should fail since reading a file in write mode*/ if (ferror(fptr)) fprintf(stderr, “Error in reading from file : file.txtn”); clearerr(fptr); /* This loop should be false since we cleared the error indicator */ if (ferror(fptr)) fprintf(stderr, “Error in reading from file : file.txtn”); fclose(fptr); return 0; } 004_example.c
  • 228. Advanced C File IO – Functions – ftell() #include <stdio.h> #include <stdlib.h> int main() { FILE *fptr; char ch; fptr = fopen(“/etc/shells”, “r”); /* Need to do error checking on fopen() */ printf(“File offset is at -> %ldnn”, ftell(fptr)); printf(“--> The content of file is <--n”); while ((ch = fgetc(fptr)) != EOF) fputc(ch, stdout); printf(“nFile offset is at -> %ldn”, ftell(fptr)); fclose(fptr); return 0; } 005_example.c
  • 229. Advanced C File IO – DIY ● Create a file named text.txt and add “abcdabcbcdaabc”. – WAP program to find the occurrences of character 'c' using ftell()
  • 230. Advanced C File IO – Functions – fprintf(), fscanf() & rewind() #include <stdio.h> int main() { int num1, num2; float num3; char str[10], oper, ch; FILE *fptr; if ((fptr = fopen(“text.txt”, “w+”)) == NULL) { fprintf(stderr, “Can't open input file text.txt!n”); return 1; } fprintf(fptr, “%d %c %d %s %fn”, 2, '+', 1, “is”, 1.1); rewind(fptr); fscanf(fptr, “%d %c %d %s %f”, &num1, &oper, &num2, str, &num3); printf(“%d %c %d %s %fn”, num1, oper, num2, str, num3); fclose(fptr); return 0; } 006_example.c
  • 231. Advanced C File IO – Functions – fseek() #include <stdio.h> int main() { int num1, num2; float num3; char str[10], oper, ch; FILE *fptr; if ((fptr = fopen(“text.txt”, “w+”)) == NULL) { fprintf(stderr, “Can't open input file text.txt!n”); return 1; } fprintf(fptr, “%d %c %d %s %fn”, 2, '+', 1, “is”, 1.1); fseek(fptr, 0L, SEEK_SET); fscanf(fptr, “%d %c %d %s %f”, &num1, &oper, &num2, str, &num3); printf(“%d %c %d %s %fn”, num1, oper, num2, str, num3); fclose(fptr); return 0; } 007_example.c
  • 232. Advanced C File IO – Functions – fwrite() & fread() #include <stdio.h> int main() { int num1, num2, num3, num4; FILE *fptr; if ((fptr = fopen(“text.txt”, “w+”)) == NULL) { fprintf(stderr, “Can't open input file text.txt!n”); return 1; } scanf(“%d%d”, &num1, &num2); fwrite(&num1, sizeof(num1), 1, fptr); fwrite(&num2, sizeof(num2), 1, fptr); rewind(fptr); fread(&num3, sizeof(num3), 1, fptr); fread(&num4, sizeof(num4), 1, fptr); printf(“%d %dn”, num3, num4); fclose(fptr); return 0; } 008_example.c
  • 233. #include <stdio.h> int main() { struct Data d1 = {2, '+', 1, “is”, 1.1}; struct Data d2; FILE *fptr; if ((fptr = fopen(“text.txt”, “w+”)) == NULL) { fprintf(stderr, “Can't open input file text.txt!n”); return 1; } fwrite(&d1, sizeof(d1), 1, fptr); rewind(fptr); fread(&d2, sizeof(d2), 1, fptr); printf(“%d %c %d %s %fn”, d2.num1, d2.oper, d2.num2, d2.str, d2.num3); fclose(fptr); return 0; } Advanced C File IO – Functions – fwrite() & fread() struct Data { int num1; char oper; int num2; char str[10]; float num3; }; 009_example.c
  • 234. Advanced C File IO – DIY ● WAP to accept students record from user. Store all the data in as a binary file ● WAP to read out entries by the previous program user@user:~]./students_record_enrty.out Enter the number of students : 2 Enter name of the student : Tingu Enter P, C and M marks : 23 22 12   Enter name of the student : Pingu Enter P, C and M marks : 98 87 87 user@user:~]./read_students_record.out -------------------------------------------------------------- Name Maths Physics Chemistry        -------------------------------------------------------------- Tingu 12 23 22          Pingu 87 98 87          -------------------------------------------------------------- Average          49.50            60.50            54.50       -------------------------------------------------------------- user@user:~] Screen Shot
  • 236. Advanced C Miscellaneous - Volatile ● A datatype qualifier ● Most commonly used Embedded Applications ● A keyword instructing the compiler not apply any optimizations on objects qualified with it! ● Why?? – You know! the compiler sometimes act extra smart on the objects not qualified with volatile – Takes implicit assumption the the objects
  • 237. Advanced C Miscellaneous - Volatile #include <stdio.h> int main() { long int wait; unsigned char bit = 0; while (1) { bit = !bit; printf(“The bit is now: %dr”, bit); fflush(stdout); for (wait = 0xFFFFFFF; wait--; ); } return 0; } user@user:~] gcc 001_example.c Compile like ● Typical embedded bit toggle code ● The output would toggle between 0 and 1 (Depends on the system configuration, tune the delay as required) ● Note the toggle frequency and user@user:~] gcc -O3 001_example.c Compile like ● Now try the same code 001_example.c
  • 238. Advanced C Miscellaneous - Volatile user@user:~] gcc 001_example.c Compile like user@user:~] gcc -O3 001_example.c Compile like ● Should solve the issue! ● or ● What happens in the previous code is that the compiler see the for loop as an unnecessary code just delaying the system operation ● Hence it removes that statement in the final output ● Adding volatile to the wait restricts the compiler from optimizing the code #include <stdio.h> int main() { volatile long int wait; unsigned char bit = 0; while (1) { bit = !bit; printf(“The bit is now: %dr”, bit); fflush(stdout); for (wait = 0xFFFFFFF; wait--; ); } return 0; } 001_example.c
  • 239. Advanced C Miscellaneous - Volatile user@user:~] gcc 002_example.c Compile like user@user:~] gcc -O3 002_example.c Compile like ● Might take some time to see the output on screen!! ● Immediate output!! ● Compiler sees the same assignment operation is unnecessarily happening in the loop ● Optimizes the loop, by removing the for loop #include <stdio.h> int main() { unsigned int i; int num; for (i = 0; i < 0xFFFFFFFF; i++) { num = 5; } printf(“%dn”, num); return 0; } 002_example.c
  • 240. Advanced C Miscellaneous - Volatile user@user:~] gcc 002_example.c Compile like user@user:~] gcc -O3 002_example.c Compile like ● Should solve the issue! ● Both should behave the same way! ● or #include <stdio.h> int main() { volatile unsigned int i; int num; for (i = 0; i < 0xFFFFFFFF; i++) { num = 5; } printf(“%dn”, num); return 0; } 002_example.c
  • 241. Advanced C Miscellaneous - Volatile user@user:~] gcc 003_example.c Compile like user@user:~] gcc -O3 003_example.c Compile like ● Enter 1 and should not come out of the loop ● Terminate and run again with input 0, you should not enter the loop ● Enter 1 and should not enter the loop!! which shouldn't be the case #include <stdio.h> int main() { int get_out; int num = 0; scanf(“%d”, &get_out); while (get_out) { num++; } return 0; } 003_example.c
  • 242. Advanced C Miscellaneous - Volatile user@user:~] gcc 003_example.c Compile like user@user:~] gcc -O3 003_example.c Compile like ● Should solve the issue! ● Both should behave the same way! ● or #include <stdio.h> int main() { int get_out; volatile int num = 0; scanf(“%d”, &get_out); while (get_out) { num++; } return 0; } 003_example.c
  • 243. Advanced C Miscellaneous - Volatile user@user:~] gcc 004_example.c Compile like #include <stdio.h> int main() { int num1; int num2 = 1; num1 = ++num2 + num2++ + num2++ + num2++; printf(“%dn”, num1); return 0; } ● Use the precedence table to obtain the result and verify with output user@user:~] ./a.out Run 004_example.c
  • 244. Advanced C Miscellaneous - Volatile user@user:~] gcc 004_example.c Compile like ● and #include <stdio.h> int main() { int num1; volatile int num2 = 1; num1 = ++num2 + num2++ + num2++ + num2++; printf(“%dn”, num1); return 0; } 004_example.c user@user:~] ./a.out Run ● Hmmmh, is it ok now!!