C Programming - Structures
C Programming
- Structures
Structures containing arrays
A structure member that is an array does not ‘behave’ like an ordinary array
When copying a structure that contains a member which is an array, the array is copied element by element Not just the address gets copied For example - array_member.c
Reminder – ordinary arrays can’t be copied simply by using the ‘=‘ operator They must be copied using a loop
Structures containing arrays
When passing the structure to a function by value Changing the array field inside the function won’t
change it in the calling function
Reminder – when passing an ordinary array to a function, all that gets passed is the address of its first element Hence every change to the array within the function,
changes the array in the calling function
C Programming
Pointers
Pointers
A new type of variable Its value is the address of another
variable We declare a pointer variable by
adding a ‘*’ before the variable name:
type *variable_name;
Understanding Pointers
int i = 5;
TypeName address valueinti 2000 5
int j = 10; intj 2004 10int*p 2008 2000int* p = &i;
int*q 2012 2000int* q = p;
j = *p;
address of iThe value of q equals the value of p
• Evaluate the right hand side of the assignment:
Go to the variable pointed by p andtake its value
Referencing
The unary operator & gives the address of a variable
The statement: ptr = &c;
assigns the address of c to the pointer variable ptr, and now ptr points to c
Referencing - Example
int n;
int *iptr; /* Declare iptr as a pointer to int */
n = 7;
iptr = &n;
n
3 4… …
173172 174 175 176 177 178 179 180 181
3 4… …
iptr
833832 834 835 836 837 838 839 840 841
7
174
Dereferencing
The unary operator * is the dereferencing operator
Applied ONLY on pointers Access the object the pointer points to The statement:*iptr = 5;
puts 5 in the variable pointed by iptr
Dereferencing
printf(“%d”, *iptr); /* Prints out ‘7’ */
*iptr = 181;printf(“%d”, n); /* Prints out ‘181’ */iptr = 181; /* This is unadvisable!! */
n
3 4… …
173172 174 175 176 177 178 179 180 181
3 4… …
iptr
833832 834 835 836 837 838 839 840 841
181
1817
174
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
1 2
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
…
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
1 2
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
120
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
1 1
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
120
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
0 1
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
120
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
0 1
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
364
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
0 1
364
5 6 7
Z[0] Z[1] Z[2]
120 248
364 368 372
372
564 772
Pointers Example
int x=1, y=2, z[3]={5,6,7};int *ip;
ip = &x; y = *ip; *ip = 0; ip = z;ip = &z[2]; *ip = 1;
x y
z ip
0 1
364
5 6 1
Z[0] Z[1] Z[2]
120 248
364 368 372
372
564 772
Common errors
It is an error to define pointers to constants or expressions. i = &3 j = &(k + 5)
It is an error to change a variable’s address (because it is not for us to determine!). &a = 150 &a = &b
Dereferencing un-initialized pointersint* a;...*a = 5;
What will be printed?
int main() {int a=3,b=6,c;int *x=&a;
printf(“c=%d\n”,c);}
c=b*(*x);c=b**x;
Function Arguments
Functions receive their arguments “by value”
Cannot change the value in the caller
void increment_counter(int counter){ counter++;}
Pointers as Function Arguments
If we want to change a variable in the function we can pass its address –
a pointer! Call “by reference”
void increment_counter(int* counter){ (*counter)++;}
Caller Callee
main
incerement_counter(X)
X
by value
increment_counter(int counter)
by reference
increment_counter(int* counter)
copy of X
counter
main
incerement_counter(&X)
Wrong Swap
A swap that gets integers as variables does not change the value in the original variables.
void swap(int x, int y) {
int tmp = x;
x = y;
y = tmp;
}
How can we fix it?
We can define swap so it gets pointers to integers instead of integers
void swap(int *x, int *y)
{
…swap *x and *y…
} We then call swap by swap(&x, &y); This is passing values by address
Right Swap – add_swap.c
void swap(int *x, int *y) { int tmp = *x;
*x = *y;*y = tmp;
}
Back to scanf
We can now understand the & in scanf("%d", &a);
The argument list in scanf is simply passed by address, so scanf can change its content
Exercise
Implement the function: void split(double d, int* int_part, double* frac_part)
The function accepts a double parameter and returns its integer and fraction parts.
Write a program that accepts a number from the user and prints out its integer and fraction parts.
Solutionvoid split(double num, int *int_part, double *frac_part){ *int_part = (int)num; *frac_part = num - *int_part;}
int main(void){ double num, fraction; int integer;
printf("Please enter a real number: "); scanf("%lf", &num);
split(num, &integer, &fraction); printf("The integer part is %d\n", integer); printf("The remaining fraction is %g\n", fraction);
return 0;}
Pointers and Arrays
An array is consecutive bytes in memory
The name of the array is the address of the first element. arr is the address of arr[0]
Unlike pointers this address cannot be changed
Pointers Vs. Arrays - Example
int arr[3] = {1, 2, 3};int *ptr;const int* cptr;
arr = ptr;ptr = arr;*ptr = 3;cptr = arr;*cptr = 5;ptr = cptr;*arr = 6; same as arr[0] = 6
Pointer arithmetic
Pointers can be incremented and decremented
If p is a pointer to a particular type, p+1 yields the correct address of the next variable of the same type
p++, p+i, and p += i also make sense
Pointer arithmetic
If p and q point to elements in an array, q-p yields the number of elements between p and q.
You can’t add two pointers There is a difference between pointer
arithmetic and “regular” arithmetic.
Pointer arithmetic - exampleint main(void){ int a[3] = {17,289,4913}, *p, *q;
p = a; /* p points to the beginning of a, that is &a[0] */ q = p+2; /* q points to a[2]. Equivalent to q = &a[2] */
printf(“a is %p\n", a); printf("p is %p, q is %p\n", p, q); printf("p points to %d and q points to %d\n", *p, *q); printf("The pointer distance between p and q is %d\n", q-p); printf("The integer distance between p and q is %d\n", (int)q-(int)p); return 0;} a is 0012FECC
p is 0012FECC, q is 0012FED4p points to 17 and q points to 4913The pointer distance between p and q is 2The integer distance between p and q is 8
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘!’ ‘!’ ‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘!’ ‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘!’ ‘!’ ‘!’ ‘!’
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘!’ ‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘!’ ‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘!’ ‘!’ ‘!’
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘!’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘s’
‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘s’ ‘!’ ‘!’
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘s’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘s’ ‘!’ ‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Strcpy – step by step
‘y’
‘e’
‘s’ ‘\0’
‘%’
src
dest
‘y’
‘e’
‘s’ ‘\0’
‘!’
void my_strcpy(char *dest, char *src){
while (*src != '\0'){
*dest = *src;dest++;src++;
} *dest = '\0';
}
Pointers, Arrays and Function Arguments
Consider the following function prototypes
These are all identical
void foo(char str[10]);
void foo(char str[]);
void foo(char* str);
Exercise
Write a function with the prototype:void replace_char(char *str,
char c1, char c2);
It replaces each appearance of c1 by c2 in the string str. Do not use the [] operator!
Demonstrate your function with a program that uses it
Solution
void replace_char(char *str, char c1, char c2)
{ while (*str != '\0') { if (*str == c1) *str = c2;
++str; }}
Exercise
Write a function with the prototype:int *find_max (int *array, size); that returns a pointer to the largest element
of the array Do not use the [] operator!
Use pointer arithmetics
Solution
int* find_max(int *array, int size){
int *ptr = array, *max = array;for (ptr=array;ptr<array+size; ptr++){
if (*ptr > *max) max = ptr;}return max;
}