C Lectures
C Lectures
5
History of the C programming language
• In 1972, computer scientist Dennis Ritchie created
a new programming language called 'C' at the Bell
Laboratories.
• It was created from 'ALGOL', 'BCPL' and 'B'
programming languages.
• 'C' programming language contains all the features of
these languages and many more additional concepts
that make it unique from other languages.
• 'C' is a powerful programming language which is
strongly associated with the UNIX operating system.
Even most of the UNIX operating system is coded in 'C’.
• Initially 'C' programming was limited to the UNIX
operating system.
• Today 'C' runs under a variety of operating systems and
hardware platforms.
• To assure that 'C' language will remain standard,
American National Standards Institute (ANSI) defined a
commercial standard for 'C' language in 1989. Later, it
was approved by the International Standards
Organization (ISO) in 1990. 'C' programming language
is also called as 'ANSI C'.
6
Elements of a typical C program development
environment
• Preprocessing statements #include <stdio.h>
7
Simple input and output statements
• A normal program receives input data, process it, and give an output.
• Data received are stored in variables.
• C is a "strongly-type" language. Once the type of a variable is declared, it can only store a
value belonging to this particular type.
• In C, you can declare a variable anywhere inside the program, as long as it is declared
before used. (In C prior to C99, all the variables must be declared at the beginning of
functions.) It is recommended that your declare a variable just before it is first used.
• C is a case-sensitive language (e.g. number, Number, and NUMBER are different variables)
• scanf() is used to read values from keybord.
• printf() is used to display results on screen.
• Use printf() to prompt user for values. #include <stdio.h>
• Do not forget the return statement.
int main() {
int x;
printf("Enter an integer: ");
scanf("%d", &x);
printf("You have entered %d", x);
return 0;
} 8
Fundamental data types
• Characters (letters and symbols) char
• Integer numbers
• Shorts integers short or short int
int
• Normal integers long or long int
• Long integers
• Real numbers
• Single precision reals float
double
• Double precision reals long double
• Long doubles
• Modifiers
• Unsigned short integers unsigned short or unsigned short int
unsigned int
• Unsigned integers unsigned long or unsigned long int
• Unsigned long integers
9
printf() and scanf() conversion specification
10
Adding two numbers program
/* add.c
Addition program */
#include <stdio.h>
11
Computer memory concepts
• Each variable has four characters:
• ID (name)
• Contains letters and digits
• Start with a letter or underscore
• ?, !, %, +, *, … are forbidden
• Type
• Value
• Location (address in the memory)
12
Arithmetic Operators
13
Precedence of arithmetic operators
14
Precedence of arithmetic operators (cont.)
15
Equality and Relational Operators
16
Simple decision making statements
#include <stdio.h>
18
C language keywords
19
Expressions: datatypes and more
• Variables’ declaration
𝑡𝑦𝑝𝑒 𝑣𝑎𝑟𝑖𝑎𝑏𝑙𝑒_𝑙𝑖𝑠𝑡;
or
𝑡𝑦𝑝𝑒 𝑣𝑎𝑟1 = 𝑣𝑎𝑙𝑢𝑒1 , 𝑣𝑎𝑟2 = 𝑣𝑎𝑙𝑢𝑒2 … ;
Where:
• 𝑡𝑦𝑝𝑒 must be a valid data type plus any modifiers, and
• 𝑣𝑎𝑟𝑖𝑎𝑏𝑙𝑒 − 𝑙𝑖𝑠𝑡 may consist of one or more identifier names separated
by commas.
int i, j = 10, l;
short int si;
unsigned int ui;
double balance, profit, loss;
20
Where Variables Are Declared?
• Local Variables
• Variables that are declared inside a function are called local variables
(automatic variables).
• Used only by statements that are inside the block in which the variables are
declared.
• Exist only while the block of code in which they are declared is executing.
i.e. a local variable is created upon entry into its block and destroyed upon
exit.
• A variable declared within one code block has no bearing on or relationship
to another variable with the same name declared within a different code
block.
• Most programmers declare all the variables used by a function immediately
after the function's opening curly brace and before any other statements
(obligatory before C99). However, you may declare local variables within
any code block. The block defined by a function is simply a special case.
21
Examples of Local Variables
void func1(void) { int main() {
int x; int x;
x = 10; x = 10;
} if (x == 10) {
void func2(void) { int x;
int x; x = 99;
x = -199; printf("Inner x: %d\n", x);
} }
printf("Outer x: %d\n", x);
int main() { return 0;
int t; }
printf("Enter an integer: ");
scanf("%d", &t); void f() {
if (t==1) { int i;
char c = 'T'; i = 10;
printf("%c\n", c); int j; // Error before C99
} j = 20;
printf("%d\n", t); }
}
22
Where Variables Are Declared? (cont.)
• Formal Parameters
• If a function is to use arguments, it must declare variables that will
accept the values of the arguments.
• They behave like any other local variables inside the function.
• Their declarations occur after the function name and inside
parentheses.
• They receive the value of the arguments passed to the function.
• They are destroyed upon exit from the function.
23
Example of Formal Parameters
24
Where Variables Are Declared? (cont.)
• Global Variables
• They are known throughout the program and may be used by any piece
of code.
• They will hold their value throughout the program's execution.
• They are created by declaring them outside of any function. Any
expression may access them, regardless of what block of code that
expression is in.
• They could be placed 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.
• They take up memory the entire time your program is executing.
25
Example of Formal Parameters
int count;
void func1();
void func2();
int main() {
count = 100;
func1();
return 0;
}
void func1() {
int temp;
temp = count;
func2();
}
void func2() {
printf("%d\n", count);
}
26
C Scopes of Vision
• File scope
• Starts at the beginning of the file (also called a translation unit) and ends
with the end of the file. It refers only to those identifiers that are declared
outside of all functions. File scope identifiers are visible throughout the
entire file. Variables that have file scope are global.
• Block scope
• Begins with the opening { of a block and ends with its associated closing }.
However, block scope also extends to function parameters in a function
definition. That is, function parameters are included in a function's block
scope. Variables with block scope are local to their block.
• Function prototype scope
• Identifiers declared in a function prototype; visible within the prototype.
• Function scope
• Begins with the opening { of a function and ends with its closing }. Function
scope applies only to labels. A label is used as the target of a goto statement,
and that label must be within the same function as the goto.
27
const Type Qualifier
• Variables of type const may not be changed by your program.
(A const variable can be given an initial value, however.) The
compiler is free to place variables of this type into read-only
memory (ROM).
const int a = 10;
28
static Specifiers
• Permanent variables within their own function or file.
• They are not known outside their function or file, but they
maintain their values between calls.
• The static modifier has different effects upon local variables
and global variables.
• static Local Variables
• The compiler creates permanent storage for it, much as it creates
storage for a global variable.
• a static local variable is a local variable that retains its value between
function calls.
• static Global Variables
• A global variable known only to the file in which it is declared.
31
register Specifiers
• Originally applied only to variables of type int, char, or pointer
types.
• in Standard C, register's definition has been broadened so that
it can be applied to any type of variable.
• Requested that the compiler keep the value of a variable in a
register of the CPU rather than in memory.
• Both C89 and C99 simply state that ''access to the object be as
fast as possible.“
• You can only apply the register specifier to local variables and
to the formal parameters in a function. Global register variables
are not allowed.
32
More on operators
• The Assignment Operator
𝑣𝑎𝑟_𝑛𝑎𝑚𝑒 = 𝑒𝑥𝑝𝑟𝑒𝑠𝑠𝑖𝑜𝑛;
• 𝑣𝑎𝑟 − 𝑛𝑎𝑚𝑒 is called 𝑙𝑣𝑎𝑙𝑢𝑒 while the 𝑒𝑥𝑝𝑟𝑒𝑠𝑠𝑖𝑜𝑛 is called 𝑟𝑣𝑎𝑙𝑢𝑒.
• 𝑙𝑣𝑎𝑙𝑢𝑒 should be modifiable.
• Multiple assignment
x = y = z = 0;
• Compound Assignments
x = x + 2; --> x += 2;
33
The Increment and Decrement Operators
x = x + 1; --> ++x; or x++;
x = x - 1; --> --x; or x--;
x = 10;
y = ++x; // x = 11 and y = 11
x = 10;
y = x++; // x = 11 and y = 10
34
Type Conversion in Expressions
IF an operand is a long double
THEN the second is converted to long double
ELSE IF an operand is a double
THEN the second is converted to double
ELSE IF an operand is a float
THEN the second is converted to float
ELSE IF an operand is an unsigned long
THEN the second is converted to unsigned long
ELSE IF an operand is long
THEN the second is converted to long
ELSE IF an operand is unsigned int
THEN the second is converted to unsigned int
35
Casting
• Explicit conversion of types
𝑡𝑦𝑝𝑒 𝑒𝑥𝑝𝑟𝑒𝑠𝑠𝑖𝑜𝑛
double x = 7.5;
int y = x; // Error
int y = (int)x; // ok
36
Control Statements
• Selection Statements
• The if-else statement
• The ?: alternative
• The switch statement
• Iteration Statements
• The for statement
• The while statement
• The do..while statement
• Jump Statements
• The return statement
• The goto statement
• The break statement
• The continue statement
• The exit() function
37
The if selection statements
if( condition ) {
...
statements;
...
}
if( condition )
single statement;
38
The if-else selection statements
if( condition ) {
...
statements;
...
} else {
...
statements;
...
}
if( condition )
single statement;
else
single statement;
39
Nested if-else selection statements
if( condition 1 ) { if( condition 1 )
... if( condition 2 )
if( condition 2 ) { statement;
...
statements; if( condition 1 )
... if( condition 2 )
} else { statement;
... else
statements; statement;
...
} if( condition 1 )
} else { if( condition 2 )
... statement;
if( condition 3 ) { else
... statement;
statements;
... if( condition 1 ) {
} else { if( condition 2 )
... statement;
statements; } else
... statement;
}
...
}
40
The if-else-if ladder
if (condition 1) int main()
statement 1; {
else int grade;
if (condition 2) printf("Please, enter your grade: ");
statement 2; scanf("%d", &grade);
...
else printf("Your rank is ");
if (condition N) if (grade >= 90)
statement N; printf("Excellent");
else else if (grade >= 80)
last statement; printf("Very good");
else if (grade >= 65)
if (condition 1) printf("Good");
statement 1; else if (grade >= 50)
else if (condition 2) printf("Passed");
else
statement 2;
printf("Fail");
... }
else if (condition N)
statement N;
else
last statement;
41
The ?: operator
int main()
{
int grade;
char * rank;
42
The switch statement
switch (expression) {
case constant1:
code block 1;
break;
case constant2:
code block 2;
break;
case constant3:
code block 3;
break;
.
.
.
default:
code block N;
}
43
The switch statement (example 1)
int main()
{
char choice;
choice = getchar();
switch (choice) {
case '1':
printf("One");
break;
case '2':
printf("Two");
break;
case '3':
printf("Three");
break;
default:
printf("Nothing correct");
}
}
44
The switch statement (example 2)
int main()
{
int choice;
printf("Enter a digit (1-9): ");
scanf("%d", &choice);
switch (choice) {
case 1:
case 2:
case 3:
case 4:
printf("it is between 1 and 4");
break;
case 5:
case 6:
printf("it is either 5 or 6");
break;
case 7:
case 8:
case 9:
printf("it is between 7 and 9");
break;
default:
printf("Nothing correct");
}
45
}
Nested switch statement (example 3)
int main()
{
int x, y;
printf("Enter two numbers: ");
scanf("%d%d", &x, &y);
switch (x) {
case 1:
switch (y) {
case 0:
printf("Division over zero");
break;
default:
printf("Y reciproque = %f", 1/(double)y);
break;
}
break;
default:
printf("%d * %d = %d", x, y, x*y);
}
}
46
The for statement
• Syntax
for(initialization; condition; iteration) {
// body
}
47
The for statement (example 1)
int main() {
int x, n;
int sum = 0;
48
The for statement (example 2)
int main() {
int x, y;
int main() {
int x, y;
49
Nested for statement (example 3)
int main()
{
int i, j;
return 0;
} 1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
5 10 15 20
50
The while statement
• Syntax
while(condition) {
// body of loop
}
51
The while statement (example)
#include <stdio.h>
#include <conio.h>
int main() {
char ch = '\0';
while (ch != 's' && ch != 'S'){
ch = getch();
printf("%c\n", ch);
// Do something...
}
return 0;
}
52
The do-while statement
• Syntax
do {
// body of loop
} while (condition);
53
The do-while statement (example)
#include <stdio.h>
#include <conio.h>
int main() {
char stop;
do {
// Doing something...
printf("\nDo you want to stop? (Y/N) ");
stop = getche();
} while (stop !='y' && stop !='Y');
return 0;
}
54
for statement → while statement
initialization;
while(condition) {
body;
iteration;
}
55
for statement → do-while statement
initialization;
if(condition) {
do {
body;
iteration;
} while(condition);
}
56
The return statement
• Syntax
return [expression];
57
The goto statement
• Syntax
goto label;
.
.
.
label:
• MUST BE AVOIDED
58
The goto statement (example)
int main() {
int x = 1;
loop1:
printf("%d\n", x);
x++;
if (x <= 100)
goto loop1;
}
59
The break statement
• Syntax
break;
• Two usages
• To terminates a statement sequence in a switch statement.
• To exit a loop (stop the loop completely).
60
The break statement (example)
int main() {
int t;
for (t = 0; t < 100; t++) {
printf("%d ", t);
if(t == 10)
break;
}
return 0;
}
61
The continue statement
• Syntax
continue;
62
The continue statement (example)
int main() {
int i;
for (i = 0; i < 10; i++) {
printf("%d ", i);
if(i % 2 == 0)
continue; 01
printf("\n"); 23
} 45
return 0; 67
} 89
63
The exit() function
• Syntax
void exit(int return_code);
64
Functions
• Syntax ret_type function_name(parameter_list) {
body of the function
}
• ret-type specifies the type of data that the function returns. A function may
return any type of data except an array.
• parameter-list is a comma-separated list of variable names and their
associated types.
• The parameters receive the values of the arguments when the function
is called.
• An empty parameter list can be explicitly specified as such by placing
the keyword void inside the parentheses.
• all function parameters must be declared individually, each including
both the type and name. It takes this general form:
65
Scope of a Function
• Each function is a discrete block of code. Thus, a function
defines a block scope.
• Function's code is private to that function and cannot be
accessed by any statement in any other function except
through a call to that function.
• The code that constitutes the body of a function is hidden from
the rest of the program, and unless it uses global variables, it
can neither affect nor be affected by other parts of the program.
• Variables that are defined within a function are local variables.
• They are created when the function is entered and are destroyed upon
exit.
• They cannot hold their values between function calls.
• Argument variables are local variables.
66
Functions (example 1)
int min(int a, int b) {
if (a < b)
return a;
else
return b;
}
67
Functions (example 2)
#define PI 3.14159265358979323846
int fact(int n) {
int result, i;
for (i = result = 1; i <=n; i++)
result *= i;
return result;
}
5! = 120
int main() {
sin(30.000000) = 0.500183
int n = 5;
sin(30.000000) = 0.500000
double x = 30;
sin(30.000000) = 0.500000
double pi = 3.14159265358979323846;
sin(30.000000) = 0.500000
printf("%d! = %d\n", n, fact(n));
printf("sin(%f) = %f\n", x, sin(x*22/7/180));
printf("sin(%f) = %f\n", x, sin(x*355/113/180));
printf("sin(%f) = %f\n", x, sin(x*pi/180));
printf("sin(%f) = %f\n", x, sin(x*PI/180));
}
68
Call-by-value vs Call-by-reference
• Call-by-value
• Copies the value of an argument into the formal parameter of the
subroutine.
• Changes made to the parameter have no effect on the argument outside
the function.
• Call-by-reference
• The address of an argument is copied into the parameter.
• The address is used to access the actual argument used in the call.
• Changes made to the actual parameter through the address affect the
argument outside the function.
C supports call-by-value only
69
Call-by-value vs Call-by-reference (example 1)
void swap(int a, int b) {
int temp = a;
printf("Begin swap() : a = %d & b = %d\n", a , b);
a = b;
b = temp;
printf("End swap() : a = %d & b = %d\n", a , b);
}
int main() {
int x = 5, y = 7;
70
Call-by-value vs Call-by-reference (example 2)
void swap(int *a, int *b) {
int temp = *a;
printf("Begin swap() : a = %d & b = %d\n", *a , *b);
*a = *b;
*b = temp;
printf("End swap() : a = %d & b = %d\n", *a , *b);
}
int main() {
int x = 5, y = 7;
71
Returning from a Function
• A function terminates execution and returns to the caller in
two ways:
• The first occurs when the last statement in the function has executed,
and, conceptually, the function's ending curly brace (}) is encountered.
• Most functions rely on the return statement to stop execution either
because a value must be returned or to make a function's code simpler
and more efficient.
• The return Statement has two important uses:
• It causes an immediate exit from the function. That is, it causes program
execution to return to the calling code.
• It can be used to return a value.
72
Returning Values
• All functions, except those of type void, return a value specified by the
return statement.
• In C89, if a non-void function executes a return statement that does not include
a value, then a garbage value is returned (bad practice).
• In C99 (and C++), a non-void function must use a return statement that
returns a value.
• If a function is specified as returning a value, any return statement within it must
have a value associated with it.
• However, if execution reaches the end of a non-void function (that is, encounters the
function's closing curly brace), a garbage value is returned.
73
Types of functions
• Computational
• These functions are specifically designed to perform operations on their
arguments and return a value based on that operation.
• A computational function is a ''pure" function.
• Examples: sqrt() and sin().
• Manipulator
• They manipulates information and returns a value that simply indicates
the success or failure of that manipulation.
• Examples: fclose() (0 if successful, EOF if not).
• Procedure
• They have no explicit return value. The function is strictly procedural
and produces no value.
• Examples: exit().
74
Recursion
• A function can call itself. In this case, the function is said to be
recursive.
• Recursion is the process of defining something in terms of
itself, and is sometimes called circular definition.
• Requirements:
• Recursive formula
• Stop condition
• Testing the stop condition before the recursive call
75
Recursion (example 1)
/* non-recursive */
int factorial(int n) {
int i, answer;
answer = 1;
for (i = 1; i <= n; i++)
answer = answer * i;
return answer;
}
int main() {
int n = 5;
76
Recursion (example 2)
/* recursive */
int factorial(int n) {
int answer;
if (n == 1)
return 1;
answer = factorial(n - 1) * n; /* recursive call */
return answer;
}
int main() {
int n = 5;
77
Function Prototypes
• In modern, properly written C programs, all functions must be declared
before they are used.
• Function prototypes were not part of the original C language, but were
added by C89. However, prototypes are required by C++.
• Prototypes enable the compiler to provide stronger type checking.
• The compiler will also catch differences between the number of arguments
used to call a function and the number of parameters in the function.
type func_name(type parm_namel, type parm_name2, ..., type parm_nameN);
• The use of parameter names is optional. However, they enable the compiler
to identify any type mismatches by name when an error occurs, so it is a
good idea to include them.
78
Function Prototypes (example)
void f(int a, int b); void f(int a, int b) {
void f(int, int); printf("%d ", a % b);
}
79
Bizarre! (1)
#include <stdio.h>
int main() {
int n;
n = 5; n++, n, n : 5, 6, 6
printf("n++, n, n : %d, %d, %d\n", n++, n, n); n:6
printf("n : %d\n\n", n);
n, n++, n : 6, 5, 6
n = 5;
n:6
printf("n, n++, n : %d, %d, %d\n", n, n++, n);
printf("n : %d\n\n", n);
n, n, n++ : 6, 6, 5
n = 5; n:6
printf("n, n, n++ : %d, %d, %d\n", n, n, n++);
printf("n : %d\n\n", n);
return 0;
}
82
Bizarre! (2)
#include <stdio.h>
int main() {
int n;
n = 5; ++n, n, n : 6, 6, 6
printf("++n, n, n : %d, %d, %d\n", ++n, n, n); n:6
printf("n : %d\n\n", n);
n, ++n, n : 6, 6, 6
n = 5;
n:6
printf("n, ++n, n : %d, %d, %d\n", n, ++n, n);
printf("n : %d\n\n", n);
n, n, ++n : 6, 6, 6
n = 5; n:6
printf("n, n, ++n : %d, %d, %d\n", n, n, ++n);
printf("n : %d\n\n", n);
return 0;
}
83
Bizarre! (3)
#include <stdio.h>
int main() {
int n;
return 0;
}
84
Bizarre! (4)
#include <stdio.h>
int main() {
int n;
n = 5; ++n, n, ++n: 7, 7, 7
printf("++n, n, ++n: %d, %d, %d\n", ++n, n, ++n); n:7
printf("n : %d\n\n", n);
n++, n, ++n : 6, 7, 7
n = 5;
printf("n++, n, ++n : %d, %d, %d\n", n++, n, ++n);
n:7
printf("n : %d\n\n", n);
n, ++n, n++ : 7, 7, 5
n = 5; n:7
printf("n, ++n, n++ : %d, %d, %d\n", n, ++n, n++);
printf("n : %d\n\n", n);
return 0;
}
85
Bizarre! (5)
#include <stdio.h>
int main() {
int n;
n = 5; n++, ++n, n : 6, 7, 7
printf("n++, ++n, n : %d, %d, %d\n", n++, ++n, n); n:7
printf("n : %d\n\n", n);
++n, n, n++ : 7, 7, 5
n = 5;
printf("++n, n, n++ : %d, %d, %d\n", ++n, n, n++); n:7
printf("n : %d\n\n", n);
++n, n++, n : 7, 5, 7
n = 5; n:7
printf("++n, n++, n : %d, %d, %d\n", ++n, n++, n);
printf("n : %d\n\n", n);
return 0;
}
86
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.
• The most common array is the string, which is simply an array
of characters terminated by a null.
87
Single-Dimension Array
• Syntax: type var_name[size];
double balance[100];
88
Single-Dimension Array (example)
int main(void) {
int x[10]; /* this declares a 10-integer array */
int t;
/* load x with values 0 through 9 */
for (t = 0; t < 10; ++t)
x[t] = t;
/* display contents of x */
for (t = 0; t < 10; ++t)
printf("%d ", x[t]);
89
Array storage and Bound checking
• As a programmer, it is your job to provide bounds checking
where needed.
• The following code will compile without error (bug):
int count[10], i;
/* this causes count to be overrun */
for(i=0; i<100; i++) count[i] = i;
90
Generating a Pointer to an Array
• The name of the array is a pointer to the first element:
int *p;
int sample[10];
p = sample;
91
Passing Single-Dimension Arrays to Functions
• In C, you cannot pass an entire array as an argument to a
function.
• You can, however, pass a pointer to an array by specifying the array's
name without an index.
void func1(int *x) { /* pointer */
/* . . . */
}
void func1(int x[10]) { /* sized array */
/* . . . */
}
void func1(int x[]) { /* unsized array */
/* . . . */
}
int main(void) {
int i[10];
func1(i);
/* . . . */
}
92
Strings
• In C, a string is a null-terminated character array. (A null is
zero.)
• Thus, a string contains the characters that make up the string followed
by a null.
• The null-terminated string is the only type of string defined by C.
• When declaring a character array that will hold a string, you
need to declare it to be one character longer than the largest
string that it will hold.
• Example: declare an array str that can hold a 10-character string:
char str[11];
93
Some common string functions
• Include the header <string.h>
Name Function
strcpy(s1, s2) Copies s2 into s1
strcat(s1, s2) Concatenates s2 onto the end of s1
strlen(s1) Returns the length of s1
strcmp(s1, s2) Returns 0 if s1 and s2 are the same; less than 0 if
s1<s2; greater than 0 if s1>s2
strchr(s1, ch) Returns a pointer to the first occurrence of ch in s1
strstr(s1, s2) Returns a pointer to the first occurrence of s2 in s1
94
Strings (example)
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[80], s2[80];
gets(s1);
gets(s2);
printf("lengths: %d %d\n", strlen(s1), strlen(s2));
if (!strcmp(s1, s2))
printf("The strings are equal\n");
strcat(s1, s2);
printf("%s\n", s1); hello
strcpy(s1, "This is a test.\n");
hello
printf(s1);
if (strchr("hello", 'e')) lengths: 5 5
printf("e is in hello\n"); The strings are equal
if (strstr("hi there", "hi")) hellohello
printf("found hi"); This is a test.
return 0; e is in hello
} found hi
95
Two-Dimensional Arrays
• A two-dimensional array is, essentially, an array of one-
dimensional arrays.
#include <stdio.h> 1 2 3 4
int main(void) { 5 6 7 8
int num[3][4]; 9 10 11 12
int t, i;
for (t = 0; t < 3; ++t)
for (i = 0; i < 4; ++i)
num[t][i] = (t * 4) + i + 1;
/* now print them out */
for (t = 0; t < 3; ++t) {
for (i = 0; i < 4; ++i)
printf("%3d ", num[t][i]);
printf("\n");
}
return 0;
}
96
Arrays of Strings
• To create an array of strings, use a two-dimensional character
array:
char str_array[30][80];
or
gets(&str_array[2][0]);
97
Multidimensional Arrays
• To declare N dimension array:
type name[Size1][Size2][Size3] . . .[SizeN];
98
Indexing Pointers
• An array name without an index is a pointer to the first
element in the array.
char p[10];
p == &p[0];
99
Indexing Pointers (cont.)
#define HEIGHT 3 printf("\n");
#define WIDTH 4 for (i = 0; i < HEIGHT; i++) {
for (j = 0; j < WIDTH; j++) {
int main(void) { printf("%d\t", *((int *)a + i * WIDTH + j));
int i, j; }
int a[HEIGHT][WIDTH]; printf("\n");
int *p = (int *)a; }
1 2 3 4
2 4 6 8
3 6 9 12
100
#include <stdio.h>
int main()
{
int array[] = {1, 2, 3};
printf("L00: array[0]=%d \n", array[0]); L00: array[0]=1
printf("L01: array[1]=%d \n", array[1]); L01: array[1]=2
printf("L02: array[2]=%d \n", array[2]); L02: array[2]=3
printf("L03: &array[0]=%p \n", &array[0]); L03: &array[0]=000000000061FE14
printf("L04: &array[1]=%p \n", &array[1]); L04: &array[1]=000000000061FE18
printf("L05: &array[2]=%p \n", &array[2]); L05: &array[2]=000000000061FE1C
printf("L06: array=%p \n", array); L06: array=000000000061FE14
printf("L07: &array=%p \n", &array); L07: &array=000000000061FE14
return 0;
}
101
#include <stdio.h>
int main()
{
char *array[] = {"First", "Second", "Third"};
printf("L00: array[0]=%s \n", array[0]); L00: array[0]=First
printf("L01: array[1]=%s \n", array[1]); L01: array[1]=Second
printf("L02: array[2]=%s \n", array[2]); L02: array[2]=Third
printf("L03: &array[0]=%p \n", &array[0]); L03: &array[0]=000000000061FE00
printf("L04: &array[1]=%p \n", &array[1]); L04: &array[1]=000000000061FE08
printf("L05: &array[2]=%p \n", &array[2]); L05: &array[2]=000000000061FE10
printf("L06: array=%p \n", array); L06: array=000000000061FE00
printf("L07: &array=%p \n", &array); L07: &array=000000000061FE00
return 0;
}
102
Arrays initialization
• Syntax:
char array_name[size] = "string";
char str[9] = "I like C";
char str[9] = {'I', ' ', 'l', 'i', 'k', 'e',' ', 'C', '\0’};
int sqrs[4][2] ={
{ 1, 1 },
{ 2, 4 },
{ 3, 9 },
{ 4, 16 }
};
103
Unsized Array Initializations
char e1[12] = "Read error\n";
char e2[13] = "Write error\n";
char e3[18] = "Cannot open file\n";
• If, in an array initialization statement, the size of the array is
not specified, the compiler automatically creates an array big
enough to hold all the initializers present.
char e1[] = "Read error\n";
char e2[] = "Write error\n";
char e3[] = "Cannot open file\n";
int sqrs[][2] ={
{ 1, 1 },
{ 2, 4 },
{ 3, 9 },
{ 4, 16 }
};
104
Variable-Length Arrays (C99)
• In C99, you can declare an array whose dimensions are
specified by any valid expression, including those whose value
is known only at run time.
• Only local arrays (that is, those with block scope or prototype scope)
can be of variable length.
void f(int dim) {
char str[dim]; /* a variable-length character array */
/* . . . */
}
105
Pointers
• YOU MUST UNDERSTAND POINTERS because:
1. pointers provide the means by which functions
can modify their calling arguments.
2. pointers support dynamic allocation.
3. pointers can improve the efficiency of certain
routines.
4. pointers provide support for dynamic data
structures, such as binary trees and linked lists.
• A pointer is a variable that holds a memory
address. This address is the location of
another object (typically another variable) in
memory.
106
Pointer Variables
• Syntax:
type *name;
• The base type of the pointer defines the type of object to which
the pointer will point.
• Technically, any type of pointer can point anywhere in memory.
• However, all pointer operations are done relative to the
pointer's base type.
107
The Pointer Operators
• Two pointer operators:
• The & operator:
• A unary operator that returns the memory address of its operand.
m = &count;
• The * operator:
• A unary operator that returns the value located at the address that
follows.
q = *m;
108
Pointer Expressions
• Pointer Assignments
#include <stdio.h>
int main() {
int x = 99;
int *p1, *p2;
p1 = &x;
p2 = p1;
/* print the value of x twice */
printf("Values at p1 and p2: %d %d\n", *p1, *p2);
/* print the address of x twice */
printf("Addresses pointed to by p1 and p2: %p %p", p1, p2);
return 0;
}
Values at p1 and p2: 99 99
Addresses pointed to by p1 and p2: 000000000061FE0C 000000000061FE0C
109
Generic pointer
• In C, it is permissible to assign a void * pointer (generic
pointer) to any other type of pointer.
• It is also permissible to assign any other type of pointer to a
void * pointer.
• The void * type allows a function to specify a parameter that is
capable of receiving any type of pointer argument without
reporting a type mismatch.
• Used to refer to raw memory (such as that returned by the
malloc() function)
110
Pointer Conversions
• Except for void *, all other pointer conversions must be
performed by using an explicit cast. (C++ includes void *)
• Conversion of one type of pointer into another type may create
undefined behavior.
#include <stdio.h>
int main() {
double x = 100.1, y;
int *p;
/* The next statement causes p (which is an
integer pointer) to point to a double. */
p = (int *) &x;
/* The next statement does not operate as expected. */
y = *p; /* attempt to assign y the value x through p */
/* The following statement won't output 100.1. */
printf("\nThe (incorrect) value of x is: %f", y);
return 0;
}
The (incorrect) value of x is: 1717986918.000000
111
Pointer Operations
• Two arithmetic operations:
• Addition
• Subtraction
• Pointer Comparisons
• According to the location in the memory
112
Pointers and Arrays
char str[80], *p1;
p1 = str;
str[4] == *(p1+4);
• Arrays of Pointers:
int var;
int *x[10];
x[2] = &var;
113
Multiple Indirection
• A pointer point to another pointer that points to the target
value.
#include <stdio.h>
int main() {
int x, *p, **q;
x = 10;
p = &x;
q = &p;
/* print the value of x */
printf("%d", **q);
return 0;
}
114
Initializing Pointers
char *p = 0;
char *p = NULL;
#include <stdio.h>
#include <string.h>
int search(char *p[], char *name);
/* null pointer constant ends the list */
char *names[] ={ "Herb", "Rex", "Dennis", "John", NULL };
int main() {
if (search(names, "Dennis") != -1)
printf("Dennis is in list.\n");
if (search(names, "Bill") == -1)
printf("Bill not found.\n");
return 0;
}
/* Look up a name. */
int search(char *p[], char *name) {
register int t;
for (t=0; p[t]; ++t)
if (!strcmp(p[t], name)) return t;
return -1; /* not found */
}
115
Constant pointer vs Pointer to constant
121
Structures, Unions, Enumerations, and typedef
• The C language gives you five ways to create a custom data
type:
• The structure: a grouping of variables under one name and is called an
aggregate data type.
• The union: enables the same piece of memory to be defined as two or
more different types of variables.
• The bit-field: a special type of structure or union element that allows
easy access to individual bits.
• The enumeration: a list of named integer constants.
• The typedef keyword: defines a new name for an existing type.
122
Structures
• A collection of variables referenced under one name, providing
a convenient means of keeping related information together.
• A structure declaration forms a template that can be used to
create structure objects (i.e. instances of a structure).
• The variables that make up the structure are called members
(elements or fields also).
123
Declaring structures and their variables
• Syntax:
struct tag { struct tag {
type member-name; type member-name;
type member-name; type member-name;
type member-name; type member-name;
. .
. .
. .
}; } structure-variables;
124
Structures (example)
struct addr {
char name[30];
char street[40];
char city[20];
char state[3];
unsigned long int zip;
};
struct addr addr_info;
struct addr { struct {
char name[30]; char name[30];
char street[40]; char street[40];
char city[20]; char city[20];
char state[3]; char state[3];
unsigned long int zip; unsigned long int zip;
} addr_info; } addr_info;
125
Accessing Structure Members
• Syntax: object_name.member_name
addr_info.zip = 12345;
printf("%lu", addr_info.zip);
gets(addr_info.name);
126
Structure Assignments
#include <stdio.h>
int main() {
struct {
int a;
int b;
} x, y;
x.a = 10;
y = x; /* assign one structure to another */
printf("%d", y.a);
return 0;
}
127
Arrays of Structures
struct addr addr_list[100];
printf("%lu", addr_list[2].zip);
addr_list[2].name[0] = 'X';
128
A Mailing List Example
#include <stdio.h> int main(void) {
#include <stdlib.h> char choice;
/* initialize the structure array */
#define MAX 100 init_list();
for (;;) {
struct addr { choice = menu_select();
char name[30]; switch (choice) {
char street[40]; case 1:
char city[20]; enter();
char state[3]; break;
unsigned long int zip; case 2:
} addr_list[MAX]; delete ();
break;
void init_list(void), enter(void); case 3:
void delete (void), list(void); list();
int menu_select(void), find_free(void); break;
case 4:
exit(0);
}
}
return 0;
}
129
A Mailing List Example (cont.)
/* Initialize the list. */ /* Input addresses into the list. */
void init_list(void) { void enter(void) {
register int t; int slot;
for (t = 0; t < MAX; ++t) char s[80];
addr_list[t].name[0] = '\0'; slot = find_free();
} if (s1ot == -1) {
printf("\nList Full");
/* Get a menu selection. */ return;
int menu_select(void) { }
char s[80]; printf("Enter name: ");
int c; gets(addr_list[slot].name);
printf("1. Enter a name\n"); printf("Enter street: ");
printf("2. Delete a name\n"); gets(addr_list[slot].street);
printf("3. List the file\n"); printf("Enter city: ");
printf("4. Quit\n"); gets(addr_list[slot].city);
do { printf("Enter state: ");
printf("\nEnter your choice: "); gets(addr_list[slot].state);
gets(s); printf("Enter zip: ");
c = atoi(s); gets(s);
} while (c < 1 || c > 4); addr_list[slot].zip = strtoul(s, '\0', 10);
return c; }
}
130
A Mailing List Example (cont.)
/* Display the list on the screen. */
void list(void) {
register int t;
/* Find an unused structure. */
for (t = 0; t < MAX; ++t) {
int find_free(void) {
if (addr_list[t].name[0]) {
register int t;
printf("%s\n", addr_list[t].name);
for (t = 0; addr_list[t].name[0] && t < MAX; ++t)
printf("%s\n", addr_list[t].street);
;
printf("%s\n", addr_list[t].city);
if (t == MAX)
printf("%s\n", addr_list[t].state);
return -1; /* no slots free */
printf("%lu\n\n", addr_list[t].zip);
return t;
}
}
}
printf("\n\n");
/* Delete an address. */
}
void delete (void) {
register int slot;
char s[80];
printf("enter record #: ");
gets(s);
slot = atoi(s);
if (s1ot >= 0 && slot < MAX)
addr_list[slot].name[0] = '\0';
}
131
Passing Structures to Functions
struct fred {
char x;
int y;
float z;
char s[10];
} mike;
132
Passing Structures to Functions
• Passing Entire Structures to Functions
/* Define a structure type. */ struct struct_type {
struct struct_type { int a, b;
int a, b; char ch;
char ch; };
};
struct struct_type2 {
void f1(struct struct_type parm); int a, b;
char ch;
int main(void) { };
struct struct_type arg;
arg.a = 1000; void f1(struct struct_type2 parm);
f1(arg);
return 0; int main(void) {
} struct struct_type arg;
arg.a = 1000;
void f1(struct struct_type parm) { f1(arg); /* type mismatch */
printf("%d", parm.a); return 0;
} }
int main() {
/* declare a structure pointer */
struct bal *p;
p = &person;
(*p).balance = 123.45;
p–> balance = 123.45;
return 0;
}
134
Nested Structures
struct emp {
/* nested structure */
struct addr address;
float wage;
} worker;
worker.address.zip = 93456;
135
Unions
• Syntax: union tag {
type member_name;
type member_name;
type member_name;
.
.
.
} union_variables;
union u_type {
int i;
char ch;
};
union u_type cnvt;
136
Unions (example)
#include <stdio.h>
#include <stdlib.h>
union pw {
short int i;
char ch[2];
};
int putw(short int num, FILE *fp);
int main(void) {
FILE *fp;
fp = fopen("test.tmp", "wb+");
if (fp == NULL) {
printf("Cannot open file.\n");
exit(1);
}
putw(1025, fp); /* write the value 1025 */
fclose(fp);
return 0;
}
int putw(short int num, FILE *fp) {
union pw word;
word.i = num;
putc(word.ch[0], fp); /* write first half */
return putc(word.ch[1], fp); /* write second half */
}
137
Bit-Fields
• Allows you to access a single bit.
• If storage is limited, you can store several Boolean (true/false) variables
in one byte.
• Certain devices transmit status information encoded into one or more
bits within a byte.
• Certain encryption routines need to access the bits within a byte.
138
Bit-Fields
(status port of a serial communications adapter)
struct status_type { Bit Meaning When Set
unsigned delta_cts : 1; 0 Change in clear-to-send line
unsigned delta_dsr : 1;
unsigned tr_edge : 1; 1 Change in data-set-ready
unsigned delta_rec : 1; 2 Trailing edge detected
unsigned cts : 1; 3 Change in receive line
unsigned dsr : 1;
unsigned ring : 1; 4 Clear-to-send
unsigned rec_line : 1; 5 Data-set-ready
} status;
6 Telephone ringing
status = get_port_status();
7 Received signal
if (status.cts)
printf("clear to send");
if (status.dsr)
printf("data ready");
status.ring = 0;
139
Bit-Fields (bypassing & mixing)
struct status_type { • Restrictions:
unsigned : 4;
unsigned cts : 1; • You cannot take the address of
unsigned dsr : 1; a bit-field.
} status; • Bit-fields cannot be arrayed.
struct emp { • You cannot know, from
struct addr address; machine to machine, whether
float pay; the fields will run from right to
/* lay off or active */
left or from left to right;
unsigned lay_off : 1;
/* hourly pay or wage */
unsigned hourly : 1;
/* IRS deductions */
unsigned deductions : 3;
};
140
Enumerations
• A set of named integer constants.
• Syntax: switch (money) {
case penny:
enum tag { enumeration list } variable_list; printf("penny");
break;
case nickel:
enum coin { penny, nickel, dime, quarter,
printf("nickel");
half_dollar, dollar};
break;
case dime:
enum coin money; printf("dime");
break;
case quarter:
if (money == quarter) printf("quarter");
printf("Money is a quarter.\n"); break;
case half_dollar:
printf("half_dollar");
printf("%d %d", penny, dime); break;
case dollar:
printf("dollar");
}
141
Enumeration (cont.)
enum coin { penny, nickel, dime, quarter, half_dollar, dollar };
char name[][12] = {
"penny",
"nickel",
"dime",
"quarter",
"half_dollar",
"dollar“
};
printf("%s", name[money]);
142
An Important Difference between C and C++
struct MyStruct {
int a;
int b;
};
• C variable declaration:
struct MyStruct obj;
143
Using sizeof()
struct s { union u {
char ch; char ch;
int i; int i;
double f; double f;
}; 1 }; 1
int main() { 4 int main() { 4
char ch; 8 char ch; 8
int i; 16 int i; 8
double f; double f;
struct s s_var; union u u_var;
printf("%d\n", sizeof(ch)); printf("%d\n", sizeof(ch));
printf("%d\n", sizeof(i)); printf("%d\n", sizeof(i));
printf("%d\n", sizeof(f)); printf("%d\n", sizeof(f));
printf("%d\n", sizeof(s_var)); printf("%d\n", sizeof(u_var));
return 0; return 0;
} }
144
typedef
• Define new data type names.
• Syntax: typedef type newname;
typedef float balance;
balance over_due;
typedef balance overdraft;
#define BALANCE float
struct s {
char ch;
int i;
double f;
};
typedef struct s sStruct;
145
Preprocessor directives
#define #undef #ifdef #ifndef
146
#define
• Syntax:
#define macro-name char-sequence
#define LEFT 1
#define RIGHT 0
printf("%d %d %d", RIGHT, LEFT, LEFT + 1);
#define ONE 1
#define TWO ONE+ONE
#define THREE ONE+TWO
#define E_MS "standard error on input\n"
/* . . . */
printf(E_MS);
#define LONG_STRING "this is a very long \
string that is used as an example"
147
Defining Function-like Macros
#define ABS(a) (a) < 0 ? -(a) : (a)
148
#error
• Syntax:
#error error-message
149
Conditional Compilation Directives
#if constant-expression
statement sequence
#endif
#if expression
statement sequence
#elif expression 1
statement sequence
#elif expression 2
statement sequence
#elif expression 3
statement sequence
#elif expression 4
...
#elif expression N
statement sequence
#else statement sequence
#endif
150
Conditional Compilation Directives (cont.)
#ifdef macro-name
statement sequence
#endif
#ifndef macro-name
statement sequence
#endif
• Using defined:
#if defined macro-name
statement sequence
#endif
151
#line
• Changes the contents of __LINE__ and __FILE__, which are
predefined identifiers in the compiler:
• The __LINE__ identifier contains the line number of the currently
compiled line of code.
• The __FILE__ identifier is a string that contains the name of the source
file being compiled.
#line number "filename"
152
The # and ## Preprocessor Operators
• Are used with the #define statement.
• The # operator, which is generally called the stringize operator,
turns the argument it precedes into a quoted string.
#define mkstr(s) #s
/* ... */
printf(mkstr(I like C));
printf("I like C");
153