C Programming Part 3
C Programming Part 3
Programming With C
[email protected]
Arrays
A sequential collection
SCS
DAVV
Arrays
An array is a collection of variables of the same type that are referred to through a common name. A specific element in an array is accessed by an index. In C, all arrays consist of contiguous memory locations. The lowest address corresponds to the first element and the highest address to the last element. Arrays can have from one to several dimensions.
SCS
DAVV
Single-Dimensional Arrays
Generic declaration: typename variablename[size]
typename is any type variablename is any legal variable name size is a constant number
To define an array of ints with subscripts ranging from 0 to 9, use: int a[10];
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
SCS
DAVV
Single-Dimensional Arrays
Array declared using int a[10]; requires 10*sizeof(int) bytes of memory To access individual array elements, use indexing: a[0]=10; x=a[2]; a[3]=a[2]; a[i]=a[i+1]+10; etc. To read a value into an array location, use scanf("%d",&a[3]); Accessing an individual array element is a fast operation
SCS
DAVV
SCS
DAVV
SCS
DAVV
Array-Bounds Checking
C, unlike many languages, DOES NOT check array bounds subscripts during: Compilation Runtime Programmer must take responsibility for ensuring that array indices are within the declared bounds
SCS
DAVV
Array-Bounds Checking
If you access beyond the end of an array: C calculates the address as usual Attempts to treat the location as part of the array Program may continue to run,OR may crash with a memory access violation error (segmentation fault, core dump error) Its better if the program crashes right away easier to debug
SCS
DAVV
Initializing Arrays
Initialization of arrays can be done by a comma separated list following its definition. Example: int array [4] = { 100, 200, 300, 400 }; is equivalent to: int array [4]; array[0] = 100; array[1] = 200; array[2] = 300; array[3] = 400; Or, you can let the compiler compute the array size: int array[ ] = { 100, 200,
300, 400};
10
SCS
DAVV
Example
#include <stdio.h> int main( ) { float expenses[12]={10.3, 9, 7.5, 4.3, 10.5, 7.5, 7.5, 8, 9.9, 10.2, 11.5, 7.8}; int count,month; float total; for (month=0, total=0.0; month < 12; month++) { total+=expenses[month]; } for (count=0; count < 12; count++) printf ("Month %d = %.2f \n", count+1, expenses[count]); printf("Total = %.2f, Average = %.2f\n", total, total/12); return 0; }
11
SCS
DAVV
Multidimensional Arrays
Arrays in C can have virtually as many dimensions as you want unlike coordinate geometry. Definition is accomplished by adding additional subscripts: int a [4] [3] ; defines a two dimensional array with 4 rows and 3 columns a can be thought of as a 1-dimensional array of 4 elements, where each element is of type int[3]
12
SCS
DAVV
Multidimensional Arrays
a[0] a[1] a[2] a[3]
a[0][0] a[0][1] a[0][2]
The array declared using int a [4] [3]; is normally thought of as a table.
13
SCS
DAVV
Multidimensional Arrays In memory, which is one-dimensional, the rows of the array are actually stored contiguously.
a[0]
14
a[1]
a[2]
SCS
DAVV
15
SCS
DAVV
#include <stdio.h> #include <stdlib.h> int main () { int random1[8][8]; int a, b; for (a = 0; a < 8; a++) for (b = 0; b < 8; b++) random1[a][b] = rand( )%2; for (a = 0; a < 8; a++) { for (b = 0; b < 8; b++) printf ("%c " , random1[a][b] ? 'x' : 'o'); printf("\n"); } return 0; }
Example
The function int rand( ); from <stdlib.h> returns a random int between 0 and RAND_MAX, a constant defined in the same library.
16
SCS
DAVV
The Value of the Array Name #include <stdio.h> int main(){ int a[3] = { 1, 2, 3 }; printf( %d\n, a[0]); scanf( %d, &a[0] ); printf( %d\n, a[0]); scanf( %d, a ); printf( %d \n, a[0]); }
When the array name is used alone, its value is the address of the array (a pointer to its first element) &a has no meaning if used in this program
17
SCS
DAVV
void inc_array(int a[ ],int size); main() { int test[3]={1,2,3}; int ary[4]={1,2,3,4}; int i; inc_array(test,3); for(i=0;i<3;i++) printf("%d\n",test[i]); inc_array(ary,4); for(i=0;i<4;i++) printf("%d\n",ary[i]); return 0; }
SCS
DAVV
Example
void bubbleSort(int a[ ],int size) { int i, j, x; for(i=0; i < size; i++) for(j=i; j > 0; j--) if(a[ j ] < a[ j-1]) { /* Switch a[ j ] and a[ j-1] */ x=a[ j ]; a[ j ]=a[ j-1]; a[j-1]=x; } } Actual parameter corresponding to formal parameter a[ ] can be any array of int values; its declared size does not matter
Function bubbleSort( ) sorts the first size elements of array a into ascending order
19
Pointers
The likelihood of a program crashing is in direct proportion to the number of pointers used in it.
SCS
DAVV
Pointer Variables
Pointers are often referred to as references The value in a pointer variable is interpreted as a memory address Usually, pointer variables hold references to specific kinds of data (e.g.: address of an int, address of a char, etc)
/* variable p can hold the address of a memory location that contains an int /* chptr can hold the address of a memory location that contains a char */ */
21
SCS
DAVV
Dereferencing Operator
The expression *p denotes the memory cell to which p points Here, * is called the dereferencing operator Be careful not to dereference a pointer that has not yet been initialized:
int *p; p *p = 7;
Attempt to put a value into an unknown memory location will result in a run-time error, or worse, a logic error
[email protected]
22
SCS
DAVV
23
SCS
DAVV
NULL
24
SCS
DAVV
Pointer Example
int *p, x, y, *q = NULL; p = &x; *p = 4; p p = &y; p x 4 y ? q x (or *p) 4 y ? q
. .
SCS
DAVV
Pointer Example
*p = 8; p x 4 y 8 *p q = p; p x 4 y 8 *p or *q q
26
SCS
DAVV
Pointer Example
p = &x; p x 4 *p *p = *q; p x 8 *p y 8 *q q y 8 *q q
27
SCS
DAVV
Arrays of Pointers
Its possible to have arrays of pointers The array name is a pointer to an array of pointers:
int * arrayOfPtr[ 4]; int j = 6; k = 4; 6 4 Pointers in array are not initialized yet k arrayOfPtr
28
? 0
? 1
? 2
? 3
SCS
DAVV
Arrays of Pointers
arrayOfPtr[0] = &k; arrayOfPtr[2]=&j;
6 j
4 k arrayOfPtr 0
? 1 2
? 3
29
SCS
DAVV
30
SCS
DAVV
31
SCS
DAVV
Generic Pointers
Sometimes we need to use pointer variables that arent associated with a specific data type In C, these generic pointers simply hold memory addresses, and are referred to as pointers to void: void* ptr;
32
SCS
DAVV
Generic Pointers
Any kind of pointer can be stored in a variable whose type is void* If we know that a value in a pointer p of type void* is really of a specific pointer type x, and we want to treat the value p points to as a value of type x, we have to cast the pointer to type x
33
SCS
DAVV
arr
? 0
? 1
? 2
? 3
? 4
? 5
34
SCS
DAVV
Generic Pointer Example arr[2] = (void*)&j; x ? k 5.9 // type cast is okay, but not needed here
7 ? 0 ? 1 2 ? 3 ? 4 ? 5
arr
35
SCS
DAVV
Generic Pointer Example arr[5] = &k; x ? k 5.9 // cast not needed, but could be used
7 ? 0 ? 1 2 ? 3 ? 4 ? 5
arr
36
SCS
DAVV
j arr
7 ? 0 ? 1 2 ? 3 ? 4 5
37
SCS
DAVV
5.9
5.9
j arr
7 ? 0 ? 1 2 ? 3 ? 4 5
38
SCS
DAVV
40
SCS
DAVV
41
SCS
DAVV
42
SCS
DAVV
43
SCS
DAVV
44
SCS
DAVV
45
SCS
DAVV
46
SCS
DAVV
Call stack
?
Heap
*p *p
unstable memory
24
24
SCS
DAVV
Call stack
?
Heap
? 8.0 ?
SCS
DAVV
SCS
DAVV
Call stack
ptrArray 7
Heap
? ? ? ?
k
50
SCS
DAVV
Call stack
ptrArray
Heap
? ?
7 ? *(ptrArray[3])
51
SCS
DAVV
52
Pointers as Parameters in C
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example:
add1 accepts as parameters an int a and a pointer to int b The call in the main is made, a is associated with a copy of main program variable j, and b is associated with a copy of the address of main program variable k Output from the program is: 5 9 4 9 (back in main) (in add1)
54
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example (contd):
Call stack immediately before the call to add1:
55
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example (contd):
Call stack after the call to add1, but before a++; is executed:
56
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example (contd):
After a++; is executed
57
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example (contd):
After (*b)++; is executed
58
SCS
DAVV
#include <stdio.h> void add1(int a, int *b) { a++; (*b)++; printf(%d\n, a); printf(%d\n, *b); return } int main() { int j = 4; k = 8; add1( j, &k ); printf(%d\n, j); printf(%d\n, k); return 0; }
Example (contd):
Upon returning from add1, its call frame is popped from the call stack, and execution continues at the first printf in main
59
SCS
DAVV
** k)
Inside fn, x is of type double*, and *x is of type double k is of type int**, *k is of type int*, and **k is of type int
60
SCS
DAVV
6.3 ? ? 15 ?
dptr1 dptr2 d c e f ? g ?
SCS
DAVV
fn ( &p, &c ); x k Recall the prototype: p q a b 6.3 ? ? 15 ? dptr1 dptr2 d c e f ? ? g void fn( double * x, int ** k) Recall from main: int b,*c=&b; double p=6.3;
62
SCS
DAVV
fn ( dptr1, &d ); x k Recall the prototype: void fn( double * x, int ** k) q a b ? ? 15 ? dptr2 d c e f ? ? g Recall from main: int a,*d=&a; double p=6.3, *dptr1=&p;
6.3
dptr1
63
SCS
DAVV
fn ( &q, f ); x ?? k Danger: f doesnt point at anything yet Recall the prototype: void fn( double * x, int ** k) ? ?? g Recall from main: int ** f; b 15 c f double q;
[email protected]
p q a
6.3 ? ? ?
dptr1 dptr2 d e
64
SCS
DAVV
fn ( dptr2, &e); ?? x k Danger: dptr2 is uninitialized Recall the prototype: void fn( double * x, int ** k) ? ? g Recall from main: int * e; b 15 c f double * dptr2;
[email protected]
p q a
6.3 ? ? ??
dptr1 dptr2 d e
65
SCS
DAVV
fn ( &p, g ); x k Recall the prototype: p q a b 6.3 ? ? 15 ? dptr1 dptr2 d c e f ? ? g void fn( double * x, int ** k) Recall from main: int *e, **g=&e; double p=6.3;
66
SCS
DAVV
67
SCS
DAVV
Arrays as Parameters
C does not allow arrays to be copied as parameters Recall: Array name is really a pointer to the first element (location 0) Indexing with square brackets has the effect of dereferencing to a particular array location
68
SCS
DAVV
Arrays as Parameters
When we put an array name in a list of actual parameters, we are really passing the pointer to the first element Do not use the address operator & when passing an array
69
SCS
DAVV
Arrays as Parameters
Suppose that we wish to pass an array of integers to a function fn, along with the actual number of array locations currently in use The following function prototypes are equivalent: void fn( int * arr, int size ); void fn( int [ ] arr, int size);
70
SCS
DAVV
#include <stdlib.h> void init1 ( int [ ] a, int s1, int * b, int s2 ) { for (int j = 0; j < s1; j++) a[ j ] = j; for (int k = 0; k < s2; k++) b[ k ] = s2 - k; } int main( ) { int s[4], *t; t = (int*)(malloc(6*sizeof(int)); t[0] = 6; init1( s, 4, t, t[0] );
71
SCS
DAVV
? Heap
72
SCS
DAVV
Example (contd) After call to init1, but before its execution begins:
local vars j and k have been ignored in the call frame for init1 a s1 4 b s2 6 Function prototype: void init1 ( int [ ] a, int s1, int * b, int s2 ); Function call: s ? ? ? ? init1( s, 4, t, t[0] );
t Call stack
73
? Heap
SCS
DAVV
t Call stack
74
4 Heap
SCS
DAVV
t Call stack
4 Heap
75
SCS
DAVV
Why Is ** Needed?
We may want a function to initialize or change a pointer Notation can also be used when creating or passing an array of pointers
76
SCS
DAVV
#include <stdlib.h> #include<time.h> void init2( int *** t, int ** j ) { int k = 3 + rand( )%10; *t = (int**)(malloc(k*sizeof(int*))); *j = (int*)(malloc(sizeof(int))); **j = k; } int main( ) { int **v; int *q; srand((unsigned int) time(NULL)); init2( &v, &q ); v[1] = q;
Example Dynamic allocation in init2 creates an array of pointers for main program variable v to point at, and an int location for q to point at; the value that q points at is also initialized Trace follows on next slides
77
SCS
DAVV
Call stack
78
SCS
DAVV
Example (contd)
int** j t int*** k int ?
? int**
79
SCS
DAVV
Example (contd)
int** j t int*** k int 7
? ? ? ? ? ? ?
Heap
80
SCS
DAVV
Example (contd)
int** j t int*** k int 7
? ? ? ? ? ? ?
81
SCS
DAVV
Example (contd)
int** j t int*** k int 7
? ? ? ? ? ? ?
82
SCS
DAVV
Example (contd) After returning to the main program, the call stack information for init2 has been recycled
? ? ? ? ? ? ?
83
SCS
DAVV
? ? ? ? ?
84
SCS
DAVV
85
SCS
DAVV
No warning from the final line: the value from the calling module thats being referenced is not modified; however, the functions copy of the values address changes
86
SCS
DAVV
88
SCS
DAVV
#include <stdlib.h> int * init3( int j ) { int *k, t; k = (int*)malloc(j*sizeof(int)); for (t=0; t<j; t++) k[t] = t; return k; } int main() { int *q; q = init3( 40 );
89
Example The function init3 dynamically allocates an array of int, initializes it, and returns a reference to it; in this case, the array has the capacity to hold 40 integers
SCS
DAVV
Example (contd) After the call to init3, but before body is executed:
int j 40 t int ? k int* ? Function prototype: int * init3( int j ); Function call: q = init3( 40 );
? int*
Call stack
90
SCS
DAVV
? int*
0 1 2 3
39
Call stack
91
SCS
DAVV
Example (contd) After returning from init3, and after execution of the assignment statement:
q = init3( 40 );
0 1 2 3
39
Heap
Portion of the call stack for the call to init3 has been recycled
92
SCS
DAVV
93
SCS
DAVV
#include <stdlib.h> #include <time.h> int ** init4( int ** size ) { int k, *arr; k = (int) 5 + rand( )%10; arr = (int*)malloc(k*sizeof(int)); *size = &k; // Wrong return &arr; // Wrong } int main() { int ** vals, *numvals; srand((unsigned int) time(NULL)); vals = init4( &numvals );
Example Local variables k and arr exist only while init4 is being executed Values stored at those locations will likely be overwritten the next time any function is called Values of vals and numvals (in main) would therefore be destroyed
94
SCS
DAVV
Example (contd) After the call to init4, but before body is executed:
int* arr ? size int** k int ? Function prototype: int ** init4( int ** size ); Function call: vals = init4( &numvals ); vals ? int** Call stack
95
numvals
? int*
SCS
DAVV
Example (contd)
int** size k
int 8 arr
int*
vals
? int**
? ? ? ? ? ? ? ? Heap
[email protected]
SCS
DAVV
Example (contd)
Heres what would happen after return, on completion of the assignment statement:
vals = init4( &numvals ); int* arr Value to be returned is address of arr
int** size k
int 8
numvals int*
vals int**
? ? ? ? ? ? ? ? Heap
[email protected]
Call stack
97
SCS
DAVV
Example (contd)
numvals int*
Call stack
98
Pointer Arithmetic
SCS
DAVV
Pointer Arithmetic
Pointers are really numeric memory addresses C allows programmers to perform arithmetic on pointers Most commonly used with arrays and strings, instead of indexing, but can be used with any pointer We wont use pointer arithmetic much, but you may need to understand it to read text books and other peoples code
100
SCS
DAVV
Pointer Arithmetic
When used with an int array a: a is a pointer to int, and points to a[0] a+1 points to array element a[1] a+2 points to array element a[2] , etc *(a+4) = 10; is equivalent to a[4] = 10; Can compare pointers using ==, !=, >, <=, etc
101
SCS
DAVV
Pointer Arithmetic
More examples: int a[10], *p, *q; p = &a[2]; q = p + 3; p = q 1; p++; p--; *p = 123; *q = *p; q = p;
102
/* q points to a[5] now */ /* p points to a[4] now */ /* p points to a[5] now */ /* p points to a[4] now */ /* a[4] = 123 */ /* a[5] = a[4] */ /* q points to a[4] now */
[email protected]
SCS
DAVV
Pointer Arithmetic
The difference between two pointers of the same type yields an int result int a[10], *p, *q , i; p = &a[2]; q = &a[5]; i = q - p; i = p - q; i = *p - *q; /* i is 3 */ /* i is 3 */ /* i = a[2] a[5] */
a[2] = 8; a[5] = 2;
103
SCS
DAVV
Pointer Arithmetic
Note that pointer arithmetic and int arithmetic are not, in general, the same In our previous examples: on most computers, an int requires 4 bytes (In Turbo C it is 2 Bytes) of storage Adding 1 to a pointer to int actually increments the address by 4, so that it points at the next memory location beyond the current int Casting a pointer to the wrong type leads to pointer arithmetic errors
104
SCS
DAVV
Pointer Arithmetic
int a[10], *p, *q , i; char s[25], *u, *v, k; p = &a[2]; q = &a[5]; i = q - p; q++; i = v u; /* i is 3, but the difference between the two addresses is 12: space for 3 ints */ /* address in q actually goes up by 4 bytes */ /* i is 6, and the difference between the two addresses is 6, because a char requires only 1 byte of storage */ u++;
105
u = &s[6]; v = &s[12];
SCS
DAVV
SCS
DAVV
Strings in C
No explicit string type in C; strings are simply arrays of characters that are subject to a few special conventions Example: char s [10]; declares a 10-element array that can hold a character string of up to 9 characters Convention: Use the null character '\0' to terminate all strings
107
SCS
DAVV
Strings in C
C does not know where an array ends at run time no boundary checking All C library functions that use strings depend on the null character being stored so that the end of the string can be detected Example: char str [10] = {'u', 'n', 'i', 'x', '\0'}; Length of str is 4 (not 5, and not the declared size of the array)
108
SCS
DAVV
109
SCS
DAVV
String Literals
Example: printf("Long long ago."); Other ways to initialize a string:
char s[10]="unix"; /* s[4] is automatically set to '\0; s can hold up to ten chars, including \0 */ char s[ ]="unix"; /* s has five elements: enough to hold the 4-character string plus the null character */
110
SCS
DAVV
111
SCS
DAVV
112
SCS
DAVV
Example
char str[11]="unix and c"; printf("%s\n", str); str[6]='\0'; printf("%s\n", str); printf(str); printf("\n"); str[2]='%'; str[3]= s'; printf(str,str); printf("\n");
113
SCS
DAVV
Use of const in this context indicates that the function will not modify the string parameter
114
SCS
DAVV
Printing with puts( ) Example: char sentence[ ] = "The quick brown fox\n"; puts(sentence); Prints out two lines: The quick brown fox
this blank line is part of the output
115
SCS
DAVV
116
SCS
DAVV
Newline character is not stored, but the null character is Make sure the array is big enough to hold the line being read; otherwise, input will overflow into other areas of memory
117
SCS
DAVV
118
SCS
DAVV
119
SCS
DAVV
Example
#include <stdio.h> int main ( ) { char lname[81], fname[81]; int count, age; puts ("Enter the last name, first name, and age, separated"); puts ("by spaces; then press Enter \n"); count = scanf ("%s%s%d", lname, fname, &age); printf ("%d items entered: %s %s %d\n", count, fname, lname, age); return 0; }
120
SCS
DAVV
121
SCS
DAVV
122
SCS
DAVV
123
SCS
DAVV
124
SCS
DAVV
Example
#include <string.h> #include <stdio.h> int main( ) { char str1[27] = "abc"; char str2[100]; printf("%d\n",strlen(str1)); strcpy(str2,str1); puts(str2); puts("\n"); strcat(str2,str1); puts(str2); }
125
SCS
DAVV
< 0 : str1 is less than str2 0 : str1 is equal to str2 > 0 : str1 is greater than str2
126
SCS
DAVV
127
SCS
DAVV
128
SCS
DAVV
129
SCS
DAVV
Functions from string.h Show the output #include <string.h> int main() { char str1[ ] = "The first string."; char str2[ ] = "The second string."; printf("%d\n", strncmp(str1, str2, 4) ); printf("%d\n", strncmp(str1, str2, 7) ); }
130
SCS
DAVV
Functions from string.h strchr: Find the first occurrence of a specified character in a string: char * strchr (const char * str, int ch) ; Search the string referenced by str from its beginning, until either an occurrence of ch is found or the end of the string (\0) is reached Return a pointer to the first occurrence of ch in the string; if no occurrence is found, return the NULL pointer instead
131
SCS
DAVV
Functions from string.h Value returned by strchr can be used to determine the position (index) of the character in the string: Subtract the start address of the string from the value returned by strchr This is pointer arithmetic: the result is offset of the character, in terms of char locations, from the beginning of the string Will work even if sizeof(char) is not 1
132
SCS
DAVV
SCS
DAVV
Functions from string.h strstr searches for the first occurrence of one string inside another: char * strstr (const char * str, char * query) ; If found, a pointer to the first occurrence of query inside str is returned; otherwise the NULL pointer is returned
134
SCS
DAVV
135
SCS
DAVV
136
SCS
DAVV
int atoi (const char *ptr); Ignores leading white space in the string Then expects either + or or a digit No white space allowed between the sign and the first digit Converts digit by digit until a non-digit (or the end of the string) is encountered
137
SCS
DAVV
138
SCS
DAVV
Like atoi, but for real values Handles a decimal point, and an exponent indicator (e or E) followed by an integer exponent
string s 12-6 -0.123.456 123E+3 123.1e-5 atof( s ) 12.000000 -0.123000 123000.000000 0.001231
139
SCS
DAVV
141
SCS
DAVV
142
SCS
DAVV
Passing Parameters to C
Often a user wants to pass parameters into the program from the command prompt :\tc\bin>progname arg1 arg2 arg3 This is accomplished in C using argc and argv Number of arguments, which includes the name of the executable Array of strings of length argc, with one argument per location
144
SCS
DAVV
Passing Parameters to C
#include <stdio.h> int main(int argc, char *argv[ ]) { int count; printf ("Program name: %s\n", argv [0]); if (argc > 1) { for (count=1; count<argc; count++) printf ("Argument %d: %s\n",count,argv[count]); } else puts ("No command line arguments entered."); return 0; }
145
SCS
DAVV
Passing Parameters to C
Suppose we compiled the previous program to the executable file myargs
C:\tc\bin>myargs first "second arg" 3 4 > myargs.out
146
SCS
DAVV
Passing Parameters to C
C program should check the command line arguments for validity: Are there the right number of arguments? Are numeric arguments in the expected range of acceptable values? If an argument is an input or output file, can it be opened successfully? Issue an error message and abort execution if arguments are incorrect
147
Compiler Directives
SCS
DAVV
The C Preprocessor
The C preprocessor is invoked by the compilation command before compiling begins Changes your source code based on instructions called preprocessor directives that are embedded in the source code The preprocessor creates a new version of your program and it is this new program that actually gets compiled
149
SCS
DAVV
The C Preprocessor
Normally, you do not see these new versions on the hard disk, as they are deleted after compilation You can force the compiler to keep them to see the results Each preprocessor directive appears in the source code preceded by a # sign
150
SCS
DAVV
151
SCS
DAVV
The #define Directive #include <stdio.h> #define PI 3.1416 #define PRINT printf int main( ) { PRINT(Approximate value of pi: %f, PI); return 0; }
152
SCS
DAVV
Function Macros
You can also define function macros:
#define MAX(A,B) ( (a) > (b) ? (a) : (b) ) printf("%d", 2 * MAX(3+3, 7)); /* is equivalent to */ printf("%d", 2 * ( (3+3) > (7) ? (3+3) : (7) );
153
SCS
DAVV
The output is: 5, 6, 3 If MAX was a function, the output would have been: 4, 5, 3
154
SCS
DAVV
Conditional Compilation
The pre-processor directives #if, #elif, #else, and #endif tell the compiler if the enclosed source code should be compiled Structure: #if condition_1 statement_block_1 #elif condition_2 statement_block_2 ... Any constant expression #elif condition_n If true (non-zero), compile statement_block_n statement_block_1 #else default_statement_block If false (zero), don't compile #endif statement_block_1
155
SCS
DAVV
Conditional Compilation
For the most part, the only things that can be tested are the things that have been defined by #define statements
#define ENGLAND 0 #define FRANCE 1 #define ITALY 0 #if ENGLAND #include "england.h" #elif FRANCE #include "france.h" #elif ITALY #include "italy.h" #else #include "canada.h" #endif
156
SCS
DAVV
Conditional Compilation
Conditional compilation can also be very useful for including debugging code When you are debugging your code you may wish to print out some information during the running of your program You may not need want this extra output when you release your program; youd need to go back through your code to delete the statements
157
SCS
DAVV
Conditional Compilation
Instead, you can use #if #endif to save time:
#define DEBUG 1 #if DEBUG printf("Debug reporting at function my_sort()!\n"); #endif
158
SCS
DAVV
Conditional Compilation
We can use a preprocessor function as the condition of compilation: defined ( NAME ) Returns true if NAME has been defined; else false Example:
#define DEBUG #if defined ( DEBUG ) printf("debug report at function my_sort() \n"); #endif
159
SCS
DAVV
Conditional Compilation
Note: Value of the defined function depends only on whether the name DEBUG has been defined It has nothing to do with which value (if any) DEBUG is defined to; in fact, we dont have to provide a value at all Can use the notation #ifdef NAME instead We also have #ifndef (if not defined)
160
SCS
DAVV
Conditional Compilation
The #undef directive makes sure that defined( ) evaluates to false. Example: Suppose that, for the first part of a source file, you want DEBUG to be defined, and for the last part, you want DEBUG to be undefined
161
SCS
DAVV
Conditional Compilation
A directive can also be set on the Unix/DOS command line at compile time:
tcc/cc DDEBUG myprog.c Compiles myprog.c with the symbol DEBUG defined as if #define DEBUG was in written at the top of myprog.c
162
SCS
DAVV
163
SCS
DAVV
164
SCS
DAVV
Structures in C
Structures are used in C to group together related data into a composite variable. This technique has several advantages: It clarifies the code by showing that the data defined in the structure are intimately related. It simplifies passing the data to functions. Instead of passing multiple variables separately, they can be passed as a single unit.
166
SCS
DAVV
Structures
Structure: Cs way of grouping a collection of data into a single manageable unit Defining a structure type: struct coord { int x ; int y ; }; This defines a new type struct coord; no variable is actually declared or generated
167
SCS
DAVV Defines the structured type struct coord and statically allocates space for two structures, first and second; the structures are not initialized
Structures
To define struct variables: struct coord { int x,y ; } first, second; Another approach: struct coord { int x,y ; }; ............... struct coord first, second; struct coord third;
168
Just defines the structured type Statically allocated variables are declared here
[email protected]
SCS
DAVV
Structures
You can use a typedef if you want to avoid two-word type names such as struct coord:
typedef struct coord coordinate; coordinate first, second;
In some compilers, and all C++ compilers, you can usually simply say just: coord first, second;
169
SCS
DAVV
Structures
Type definition can also be written as: typedef struct coord { int x,y ; } coordinate; In general, its best to separate the type definition from the declaration of variables
170
SCS
DAVV
Structures
Access structure members by the dot (.) operator Generic form:
structure_var.member_name
For example:
171
SCS
DAVV
Structures
struct_var.member_name can be used anywhere a variable can be used: printf ("%d , %d", second.x , second.y ); scanf("%d, %d", &first.x, &first.y);
172
SCS
DAVV
Structures
Can copy entire structures using = pair1 = pair2;
173
SCS
DAVV
174
SCS
DAVV
Structures Containing Structures Structures can have other structures as members: To define rectangle in terms of coordinate: typedef struct rect { coordinate topleft; coordinate bottomright; } rectangle;
? x topleft
175
? y
? x
? y
Rectangle blueprint
bottomright
[email protected]
SCS
DAVV
Structures Containing Structures To initialize the points describing a rectangle: struct rect mybox ; mybox.topleft.x = 0 ; mybox.topleft.y = 10 ; mybox.bottomright.x = 100 ; mybox.bottomright.y = 200 ;
0 x topleft
176
10 y
100 x
200 y
struct rect
bottomright
[email protected]
SCS
DAVV int main ( ) { int length, width; long area; rectangle mybox; mybox.topleft.x = 0; mybox.topleft.y = 0; mybox.bottomright.x = 100; mybox.bottomright.y = 50; width = mybox.bottomright.x mybox.topleft.x; length = mybox.bottomright.y mybox.topleft.y; area = width * length; printf (Area is %ld units.\n", area); }
[email protected]
Example
#include <stdio.h> typedef struct coord { int x; int y; }coordinate; typedef struct rect { coordinate topleft; coordinate bottomright; }rectangle;
177
SCS
DAVV
record
float
char[5]
178
SCS
DAVV
#include <stdio.h> struct data { float amount; char fname[30]; char lname[30]; } rec; int main () { struct data rec; printf ("Enter the donor's first and last names, \n"); printf ("separated by a space: "); scanf ("%s %s", rec.fname, rec.lname); printf ("\nEnter the donation amount: "); scanf ("%f", &rec.amount); printf ("\nDonor %s %s gave $%.2f.\n", rec.fname,rec.lname,rec.amount); }
[email protected]
Example
179
SCS
DAVV
Arrays of Structures Example: struct entry { char fname [10] ; char lname [12] ; This creates an char phone [8] ; array of 1000 }; structures of type struct entry list [1000]; struct entry Possible assignments: list [1] = list [6]; strcpy (list[1].phone, list[6].phone); list[6].phone[1] = list[3].phone[4] ;
180
SCS
DAVV
int main() { struct entry list[4]; int i; for (i=0; i < 4; i++) { printf ("\nEnter first name: "); scanf ("%s", list[i].fname); printf ("Enter last name: "); scanf ("%s", list[i].lname); printf ("Enter phone in 123-4567 format: "); scanf ("%s", list[i].phone); } printf ("\n\n"); for (i=0; i < 4; i++) { printf ("Name: %s %s", list[i].fname, list[i].lname); printf ("\t\tPhone: %s\n", list[i].phone); } }
[email protected]
Example
#include <stdio.h> struct entry { char fname [20]; char lname [20]; char phone [10]; };
181
SCS
DAVV
Initializing Structures
Example: struct sale { char customer [20] ; char item [20] ; int amount ; }; struct sale mysale = { "Acme Industries", "Zorgle blaster", 1000 } ;
182
SCS
DAVV
Initializing Structures
Example: Structures within structures: struct customer { char firm [20] ; char contact [25] ; }; struct sale { struct customer buyer ; char item [20] ; int amount ; } mysale = { { "Acme Industries", "George Adams"} , "Zorgle Blaster", 1000 };
183
SCS
DAVV
Initializing Structures
184
SCS
DAVV
Pointers to Structures struct part { float price ; char name [10] ; }; struct part *p , thing; p = &thing; /* The following two statements are equivalent */ thing.price = 50; (*p).price = 50; /* ( ) around *p is needed */
185
SCS
DAVV
Pointers to Structures
thing.price
thing.name [ ]
p
p is set to point to the first byte of the struct variable
186
SCS
DAVV
Pointers to Structures When we have a pointer to a structure, we must dereference the pointer before attempting to access the structures members The membership (dot) operator has a higher precedence than the dereferencing operator struct part *p , thing; p = &thing; (*p).price = 50;
187
SCS
DAVV
Pointers to Structures
C provides an operator -> that combines the dereferencing and membership operations into one, performed in the proper order Easier form to read (and to type) when compared with the two separate operators
struct part *p , thing; p = &thing; p->price = 50; /*equivalent to (*p).price = 50; and thing.price = 50; and (&thing)->price = 50;*/
188
SCS
DAVV
Pointers to Structures struct part * p, *q; p = (struct part *) malloc( sizeof(struct part) ); q = (struct part *) malloc( sizeof(struct part) ); p -> price = 199.99 ; strcpy( p -> name, "hard disk" ); (*q) = (*p); q = p; free(p); free(q); /* This statement causes a problem. Why? */
189
SCS
DAVV
Pointers to Structures You can allocate a structure array as well: struct part *ptr; ptr = (struct part *) malloc(10*sizeof(struct part) ); for( i=0; i< 10; i++) { ptr[ i ].price = 10.0 * i; sprintf( ptr[ i ].name, "part %d", i ); } free(ptr); }
190
SCS
DAVV
Pointers to Structures You can use pointer arithmetic to access the elements of the array:
{ struct part *ptr, *p; ptr = (struct part *) malloc(10 * sizeof(struct part) ); for( i=0, p=ptr; i< 10; i++, p++) { p -> price = 10.0 * i; sprintf( p -> name, "part %d", i ); } free(ptr); }
191
SCS
DAVV
? b
? c
? b
? c
NULL
SCS
DAVV
2 b ?
3 c ?
SCS
DAVV
194
SCS
DAVV
195
SCS
DAVV
SCS
DAVV
C handbook
197
SCS
DAVV
Values of the structs members were copied here; the string lies outside the structure, and was not copied
C handbook
198
SCS
DAVV
Unix handbook
199
SCS
DAVV
strdup( ) makes a dynamically allocated copy of a string at source, and returns a pointer to it; returns NULL instead if a copy cant be made Size of the new string is strlen(source)
200
SCS
DAVV
Only difference: b.name will have the capacity to store only 10 chars plus the null character, rather than the 50 chars it held in the original codeSize of the new string is strlen(source)
201
SCS
DAVV
202
SCS
DAVV
203
SCS
DAVV
SCS
DAVV
Passing Structures to Functions #include<stdio.h> struct book { float price; char abstract[5000]; }; void print_abstract( struct book *p_book) { puts( p_book->abstract ); };
205
SCS
DAVV
Unions
union Memory that contains a variety of objects over time Only contains one data member at a time Members of a union share space Conserves storage Only the last data member defined can be accessed union declarations Same as struct union Number { int x; float y; }; union Number value;
206
SCS
DAVV
Unions
Valid union operations Assignment to union of same type: = Taking address: & Accessing union members: . Accessing members using pointers: ->
207
SCS
DAVV
208
SCS
DAVV
unsigned short word = 0x1234; /* assumes sizeof ( short) == 2 */ unsigned char p = (unsigned char ) &word; if ( p[0] == 0x12 ) printf (Big Endian Machine\n); else printf ( Little Endian Machine\n);
209
SCS
DAVV
210
SCS
DAVV
Bit Fields
Bit fields allow one to specify members of a struct that only use a specified number of bits. The size of bits does not have to be a multiple of eight. A bit field member is defined like an unsigned int or int member with a colon and bit size appended to it.
212
SCS
DAVV
An example of bitfield
The first bitfield is assigned to the least significant bits of its word
213
SCS
DAVV
Bitwise Operators
All data represented internally as sequences of bits Each bit can be either 0 or 1 Sequence of 8 bits forms a byte
Operator & | ^ << Name
bitwise AND bitwise OR bitwise exclusive OR left shift
Description
The bits in the result are set to 1 if the corresponding bits in the two operands are both 1. The bits in the result are set to 1 if at least one of the corresponding bits in the two operands is 1. The bits in the result are set to 1 if exactly one of the corresponding bits in the two operands is 1. Shifts the bits of the first operand left by the number of bits specified by the second operand; fill from right with 0 bits. Shifts the bits of the first operand right by the number of bits specified by the second operand; the method of filling from the left is machine dependent. All 0 bits are set to 1 and all 1 bits are set to 0.
>>
right shift
Ones complement
214
Files in C
SCS
DAVV
FILE *
C uses the FILE* data type to access files FILE is defined in <stdio.h> #include <stdio.h> int main( ) { FILE * fp; fp = fopen("tmp.txt", "w"); fprintf(fp,"This is a test\n"); fclose(fp); return 0; }
216
SCS
DAVV
Opening a File
Must include <stdio.h> Prototype form: FILE * fopen (const char * filename, const char * mode) FILE is a structure type declared in stdio.h. Keeps track of the file mode (read, write, etc), position in the file that were accessing currently, and other details May vary from system to system
217
SCS
DAVV
Opening a File
fopen returns a pointer to a FILE structure Must declare a pointer of type FILE to receive that value when it is returned Use the returned pointer in all subsequent references to that file If fopen fails, NULL is returned. The argument filename is the name of the file to be opened
218
SCS
DAVV
Opening a File
Enclose the mode in double quotes or pass as a string variable Modes are: r: open the file for reading; fopen returns NULL if the file doesnt exist or cant be opened w: create file for writing; destroy old if file exists a: open for writing; create if not there; start at the end-of-file (append mode) r+: open for update (r/w); create if not there; start at the beginning w+: create for r/w; destroy old if there a+: open for r/w;create if not there; start at the end-of-file
219
SCS
DAVV
220
SCS
DAVV
221
SCS
DAVV
Formatted File I/O { FILE *fp1, *fp2; int n; fp1 = fopen("file1", "r"); fp2 = fopen("file2", "w"); fscanf(fp1, "%d", &n); fprintf(fp2, "%d", n); fclose(fp1); fclose(fp2); }
222
SCS
DAVV
These two functions read or write a single byte from or to a file fgetc returns the character that was read, converted to an integer fputc returns the value of parameter c if it succeeds; otherwise, returns EOF
223
SCS
DAVV
224
SCS
DAVV
225
SCS
DAVV
226
SCS
DAVV
227
SCS
DAVV
Example
#include<stdio.h> #define BUFSIZE 100 int main ( ) { char buf[BUFSIZE]; if ( (fp=fopen("file1", "r"))==NULL) { fprintf (stderr,"Error opening file."); exit (1); } while (!feof(fp)) { fgets (buf,BUFSIZE,fp); printf ("%s",buf); } fclose (fp); return 0; }
228
This program echoes the contents of file1 to standard output with one flaw: the last line is echoed twice; it would be better to use: while (fgets(buf, BUFSIZE, fp) != NULL) printf(%s,buf);
SCS
DAVV
230
SCS
DAVV
int fwrite (void *buf, int size, int count, FILE *fp) ; int fread (void *buf, int size, int count, FILE *fp) ;
buf: is a pointer to the region in memory to be written/read; it can be a pointer to anything (a simple variable, an array, a structure, etc) size: the size in bytes of each individual data item count: the number of data items to be written/read
231
SCS
DAVV
232
SCS
DAVV
233
SCS
DAVV
234
SCS
DAVV
void rewind (FILE * fp) ; A call to rewind resets the position indicator to the beginning of the file
235
SCS
DAVV
long ftell (FILE * fp) ; Returns a long giving the current position in bytes The first byte of the file is byte zero If an error occurs, ftell () returns -1
236
SCS
DAVV
Random Access
If were aware of the structure of a file, we can move the files position indicator anywhere we want within the file (random access):
int fseek (FILE * fp, long offset, int origin) ; offset is the number of bytes to move the position indicator origin says where to move from
237
SCS
DAVV
Random Access
Three options/constants are defined for origin: SEEK_SET: move the indicator offset bytes from the beginning SEEK_CUR: move the indicator offset bytes from its current position SEEK_END: move the indicator offset bytes from the end
238
SCS
DAVV
Random Access
Random access is most often used with binary input files, when speed of execution matters: we want to avoid having to read in data sequentially to get to a known location Writing to a location in a file other than the end does not insert content: it overwrites
239
SCS
DAVV
240
SCS
DAVV
241
SCS
DAVV
242
SCS
DAVV
243
SCS
DAVV
Example #include <stdio.h> int main () { char buffer[25]; tmpnam(buffer); printf ("Temporary name is: %s", buffer); return 0; }
Output:
Temporary name is: c:\tc\bin\aaaceaywB
244
SCS
DAVV
245
SCS
DAVV
246
SCS
DAVV
247
I/O Redirection, Unconditional Branching, Enumerated Data Type, Little Endian and Big Endian
SCS
DAVV
SCS
DAVV
250
SCS
DAVV
251
SCS
DAVV
Enumeration Constants
Enumeration Set of integer constants represented by identifiers Enumeration constants are like symbolic constants whose values are automatically set Values start at 0 and are incremented by 1 Values can be set explicitly with = Need unique constant names Example:
enum Months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
Creates a new type enum Months in which the identifiers are set to the integers 1 to 12 Enumeration variables can only assume their enumeration constant values (not the integer representations)
252
SCS
DAVV
Inline Functions
Recall the two different ways to compute the larger of two integers: #define max(a,b) ((a)>(b)? (a):(b)) int max(int a, int b) { return a>b?a:b; } To execute a function call, computer must: Save current registers Allocate memory on the call stack for the local variables, etc, of the function being called Initialize function parameters Jump to the area of memory where the function code is, and jump back when done
254
SCS
DAVV
Inline Functions
The macro approach is more efficient since it does not have function call overhead, but, this approach can be dangerous, as we saw earlier Modern C compilers provide inline functions to solve the problem: Put the inline keyword before the function header
255
SCS
DAVV
Inline Functions
You then use the inline function just like a normal function in your source code printf( "%d", max( x, y) ); When the compiler compiles your program, it will not compile it as a function; rather, it integrates the necessary code in the line where max( ) is called, and avoids an actual function call The above printf() is compiled to be something like: printf("%d", x>y?x:y);
256
SCS
DAVV
Inline Functions
Writing the small but often-used functions as inline functions can improve the speed of your program A small problem: You must include the inline function definition (not just its prototype) before using it in a file Therefore, inline functions are often defined in header (.h) files
257
SCS
DAVV
Inline Functions
Once you include a header file, you can use: Inline functions whose definitions are in the header file Normal functions whose prototypes are in the header file Another minor problem: Some debuggers get confused when handling inline functions it may be best to turn functions into inline functions only after debugging is finished
258
SCS
DAVV
259
SCS
DAVV
Type Qualifiers
Type qualifiers that control how variables may be accessed or modified const
Variables of type const may not be changed by your program. The compiler is free to place variables of this type into read-only memory (ROM). const int a=10; creates an integer variable called a with an initial value of 10 that your program may not modify. The const qualifier can be used to prevent the object pointed to by an argument to a function from being modified by that function. That is, when a pointer is passed to a function, that function can modify the actual object pointed to by the pointer.
260
SCS
DAVV
Volatile
The modifier volatile tells the compiler that a variable's value may be changed in ways not explicitly specified by the program. For example, a global variable's address may be passed to the operating system's clock routine and used to hold the system time. In this situation, the contents of the variable are altered without any explicit assignment statements in the program. This is important because most C compilers automatically optimize certain expressions by assuming that a variable's content is unchanging if it does not occur on the left side of an assignment statement; thus, it might not be reexamined each time it is referenced.
261
SCS
DAVV
Const + Volatile
You can use const and volatile together. For example, if 0x30 is assumed to be the value of a port that is changed by external conditions only, the following declaration would prevent any possibility of accidental side effects: const volatile char *port = (const volatile char *) 0x30;
262
SCS
DAVV
263
SCS
DAVV
Global Variables
Global variables are known throughout the program and may be used by any piece of code. Also, they will hold their value throughout the program's execution. You create global variables by declaring them outside of any function. Any expression may access them, regardless of what block of code that expression is in. In the following program, the variable count has been declared outside of all functions. Although its declaration occurs before the main( ) function, you could have placed it anywhere before its first use as long as it was not in a function. However, it is usually best to declare global variables at the top of the program.
264
SCS
DAVV
Global Variables ..
Storage for global variables is in a fixed region of memory set aside for this purpose by the compiler. Global variables are helpful when many functions in your program use the same data. You should avoid using unnecessary global variables, however. They take up memory the entire time your program is executing, not just when they are needed.
265
SCS
DAVV
Linkage
C defines three categories of linkage: external, internal, and none. In general, functions and global variables have external linkage. This means they are available to all files that constitute a program. File scope objects declared as static (described in the next section) have internal linkage. These are known only within the file in which they are declared. Local variables have no linkage and are therefore known only within their own block.
266
SCS
DAVV
Extern
The principal use of extern is to specify that an object is declared with external linkage elsewhere in the program. A declaration declares the name and type of an object. A definition causes storage to be allocated for the object. The same object may have many declarations, but there can be only one definition. In most cases, variable declarations are also definitions. However, by preceding a variable name with the extern specifier, you can declare a variable without defining it. Thus, when you need to refer to a variable that is defined in another part of your program, you can declare that variable using extern.
267
SCS
DAVV
Extern #include <stdio.h> int main(void) { extern int first, last; /* use global vars */ printf("%d %d", first, last); return 0; } /* global definition of first and last */ int first = 10, last = 20;
268
SCS
DAVV
Multiple-File Programs
An important use of extern relates to multiple-file programs. C allows a program to be spread across two or more files, compiled separately, and then linked together. When this is the case, there must be some way of telling all the files about the global variables required by the program. The best (and most portable) way to do this is to declare all of your global variables in one file and use extern declarations in the other.
269
SCS
DAVV
Multiple-File Programs
int x, y; char ch; int main(void) { /* . . . */ } void func1(void) { x = 123; } extern int x, y; extern char ch; void func22(void) { x = y / 10; } void func23(void) { y = 10; }
270
SCS
DAVV
Static Variables
Variables declared as static are permanent variables within their own function or file. Unlike global variables, they are not known outside their function or file, but they maintain their values between calls. This feature makes them useful when you write generalized functions and function libraries that other programmers may use. The static modifier has different effects upon local variables and global variables.
271
SCS
DAVV
An example of a function that benefits from a static local variable is a number series generator that produces a new value based on the previous one.
272
SCS
DAVV
273
SCS
DAVV
Register Variables
The register specifier requested that the compiler keep the value of a variable in a register of the CPU rather than in memory, where normal variables are stored. This meant that operations on a register variable could occur much faster than on a normal variable because the register variable was actually held in the CPU and did not require a memory access to determine or modify its value. The register storage specifier originally applied only to variables of type int, char, or pointer types. type of variable.
274
Any Questions