int - Piazza

advertisement
C++ Programming Languages
Lecturer:
Omid Jafarinezhad
Spring 2014
Lecture 1
c programming language overview
Department of Computer Engineering
Review Of Course Materials
•
Overview of the C-portions of C++
– e.g., loops, structs, arrays, basic data types, etc.
• A quick tour through C++, focusing primarily on classes, templates,
inheritance, and dynamic binding
• An in-depth look at defining
–
–
–
–
–
–
–
abstract data types in C++
focusing primarily on classes, templates, and exception handling
single and multiple inheritance
dynamic binding
pointer-to-member functions in C++
dynamic memory management in C++
container classes in C++
• Traps and pitfalls of using C++ and how to workaround them
• Thread and Graphic (2D and 3D) programming, Refactoring, TDD, Qt, …
References
• P. Deitel, H. Deitel, C++: How to Program, 9th
Edition, Prentice Hall, 2011.
•
J. Soulie, C++ Language Tutorial, 2009. Available at http://www.cplusplus.com/doc/tutorial/
•
M. Fowler, K. Beck, J. Brant, W. Opdyke, D. Roberts, Refactoring: Improving the Design of
Existing Code, Addison Wesley, 1999.
Grading policy
•
•
•
•
•
•
Assignments : 4 pts
Projects: 4 pts
Quizzes: 2 pts
Midterm: 4 pts
Final Exam: 6 pts
Programming Contest: +1 pt (bonus)
C History
• BCPL ,1967, Martin Richards
– writing operating-systems software and compiler
• B, 1969, Ken Thomson
– based on BCPL
• C, 1972, Dennis Ritchie
– based on BCPL and B
– at Bell Laboratories
– originally implemented on a DEC PDP-11
C++ Programming Language
• early 1980s, Bjarne Stroustrup
– at Bell Labroratory
– C++ a superset of C
– object-oriented programming
• Objects are essentially reusable software components
that model items in the real world
• filename.cpp
Simple C Program
• Examples:
// Simplest c program
// int is return data type
int main()
// main is entrance function
{
int main()
return 0;
}
{
statement 1;
/*
statement 1;
Objective: print on screen
// ….
*/
return 0;
#include <stdio.h> // preprocessor statements have not ;
int main()
}
welcome to c!!!
{
printf("welcome to c!!!");
return 0; // indicate that program ended successfully
}
Example
–
–
–
–
–
–
Header file
Constant
Main function
Variables
Input and output
Process
#include <stdio.h> // (preprocessor )
#define PI 3.14 // PI constant (preprocessor )
// calculating area of circle
int main()
{
/* variable definition */
float Radius;
float Area = 0;
// get radius of circle form user
printf("Enter Radius :\n");
scanf("%f", &Radius);
// calculating area of circle
Area = PI * Radius * Radius;
printf(“Area = %f", Area );
system("Pause");
return 0;
}
Variable declaration
• Before using a variable, you must declare it
 Data_Type Identifier;
• int width; // width of rectangle
• float area; // result of calculating area stored in it
• char separator; // word separator
 Data_Type Identifier = Initial_Value;
• int width = 10; // width of rectangle
• float area = 255; // result of calculating area stored in it
• char seperator = ‘,’; // word separator
 Data_Type Identifier, Identifier, Identifier ,….;
• int width, length, temporary;
• float radius, area = 0;
Data types
• Minimal set of basic data types
– primitive data types
•
•
•
•
•
int
float
double
char
Void
• The size and range of these data types may
vary among processor types and compilers
Data type qualifiers
• Modify the behavior of data type to which they
are applied:
– Size qualifiers: alter the size of the basic data types:
•
•
•
•
short: multiply by 0.5
long: multiply by 2
short can be applied to: int
long can be applied to: int and double
– Sign qualifiers: can hold both positive and negative
numbers, or only positive numbers.:
• signed: + and • unsigned: +
• they can be applied to : int and char
Data type size and range
Data type Qualifier
char
int
float
double
Example
signed char c;
signed
char c;
unsigned unsigned
char c;
signed short i;
signed short int i;
unsigned int i;
int i;
signed int i;
signed
short i;
unsigned short int i;
long i;
short
long
long int i;
signed long i;
signed long int i;
long long i;
long long int i;
signed long long i;
signed long long int i;
float f;
double d;
long
long double d;
Size
8
8
8
16
16
16 or 32
16 or 32
16 or 32
16
16
32
32
32
32
64
64
64
64
64
64
80
Range
-128 .. 127
0 .. 255
-128 .. 127
signed (16): -32768 .. 32767
unsigned (16): 0 .. 65535
signed (32):
-2147483648 .. 2147483647
unsigned (32): 0 .. 4294967295
+/- 3.4e +/- 38 (~7 digits)
+/- 1.7e +/- 308 (~15 digits)
Overflow and Underflow
/* The # character indicate a pre-processor directive; it's an instruction to the compiler to make it do something
The <> character tell C to look in the system area for the file stdio.h.
If I had given the name #include "stdio.h" instead it would tell the compiler to look in the current directory
/*
#include <stdio.h>
/*
* Function main begins program execution
* Semi-colon is statement terminator, so it is as a signal to the compiler for end of line
*/
int main()
{
/* The 2 curly brackets { }, are used to specify the limits of the program block */
char letter = 'A'; // char variable to show ASCII code
short shortVariable = 32769; // short variable for test overflow
// printf command display string on the monitor
printf("current value of shortVariable is = %d\n", shortVariable);
printf("current value of letter is = %d", letter);
printf("current value of letter is = %c", letter);
system("PAUSE"); // pause the execution to show press any key …
return 0; // indicate that program ended successfully
}
current value of shortVariable is = -32767
current value of letter is = 65
current value of letter is = A
Program Error
• Compile-time or syntax
– is caused when the compiler cannot recognize a
statement
• Run-time
– E.g. division by zero
• Logical
– E.g. Overflow and Underflow
Integer constant value
• Base 10: 1 915 +8 -90
• Base 8: 074 0123 084
• Base 16: 0x1 0X5 0x7fab
•
•
•
•
unsigned: 5000u 4U
long: 123456789l 56L
unsigned long: 536489ul
long long : 5361254865LL 25lL
• Example :
– 0xABu 0123uL 017LL
floating-point constant value
• A floating-point value contains a decimal point
– 33.5 0.0 -657.983 .2
6.
• For example, the value 150.4582 is represented
in scientific notation as
– 1.504582 X 102
• and is represented in exponential notation (by
the computer) as
– 1.504582E+02
– This notation indicates that 1.504582 is multiplied by
10 raised to the second power (E+02)
• The E stands for “exponent”
Char and string constant value
• Char
char c;
c = 'A'; // d = 65;
• String
printf("string is array of char!!!");
printf("example of escape sequence is \n");
Constant
• Constants provide a way to define a variable
which cannot be modified by any other part in
the code
– #define: without memory consume
– const: memory consume
• #define Identifier constant_value
– #define PI 3.14
– #define ERROR "Disk error "
– #define ERROR "multiline \
message"
– #define ONE 1
#define TWO ONE + ONE
Constant
• const [Data_Type] Identifier = constant_value;
– const p = 3; // const int p = 3;
– const p;
p = 3.14; // compile error
– const p = 3.14; // p = 3 because default is int
– const float p = 3.14;
Operators
• Arithmetic Operators
– unary operators
• operators that require only one operand
– binary operators
• operators that require two operands
•
•
•
•
•
•
•
Assignment Operators
Equality and Relational Operators
Logical Operators
Bitwise Operators
Conditional Operator
Comma Operator
sizeof
Operator
Width * High
Operand
Arithmetic Operators
• Unary Operator
C operation
Operator Expression
Explanation
Positive
+
a = +3;
Negative
-
b = -4;
Increment
++
i++;
Equivalent to i = i + 1
Decrement
--
i - -;
Equivalent to i = i - 1
Arithmetic Operators
• Binary Operators
C operation
Operator Expression
Addition
+
b = a + 3;
Subtraction
-
b = a – 4;
Multiplication
*
b = a * 3;
Division
/
b = a / c;
Modulus (integer)
%
b = a % c;
Division
• The division of variables of type integer will
always produce a variable of type integer as
the result
• Example
Since b is declared as an integer,
the result of a/2 is 3, not 3.5
int a = 7, b;
float z;
b = 3,
b = a / 2;
z = a / 2.0;
printf("b = %d, z = %f\n", b, z);
z = 3.500000
Modulus
• You could only use modulus (%) operation on
integer variables (int, long, char)
 z = a % 2.0; // error
 z = a % 0; // error
• Example
int a = 7, b, c;
b = a % 2;
c = a / 2;
printf("b = %d\n", b);
printf("c = %d\n", c);
Modulus will result in the
remainder of a/2.
-
7
2
6
3
a/2
integral
1
a%2
remainder
Assignment Operators
• lvalue = rvalue;
int i;
float f;
i = 2; // *&i = 2;
2 = i; // error: invalid lvalue in assignment
f = 5.6;
i = f; // i = 5;
i = -5.9; // i = -5;
Assignment Operators
• Assignment operators are used to combine the '='
operator with one of the binary arithmetic or
bitwise operators
Operator
Expression
Equivalent Statement
Results
+=
c += 7;
c = c + 7;
c = 16
-=
c -= 8;
c = c – 8;
c=1
*=
c *= 10;
c = c * 10;
c = 90
/=
c /= 5;
c = c / 5;
c=1
%=
c %= 5;
c = c % 5;
c=4
&=
c &= 2 ;
c = c & 2;
c=0
^=
c ^= 2;
c = c ^ 2;
c = 11
• Example :
|=
c |= 2;
c = c | 2;
c = 11
<<=
c <<= 2;
c = c << 2;
c = 36
– c = 9;
>>=
c >>= 2;
c = c >> 2;
c=2
Equality and Relational Operators
• Equality Operators:
Operator Example
Meaning
==
x == y x is equal to y
!=
x != y x is not equal to y
• Relational Operators:
Operator
>
<
>=
<=
Example
x>y
x<y
x >= y
x <= y
Meaning
x is greater than y
x is less than y
x is greater than or equal to y
x is less than or equal to y
Logical Operators
• Logical operators are useful when we want to test
multiple conditions
– AND
– OR
– NOT
• C has not bool data type, but:
– 0: evaluate to false
• If(0) printf(" …");
– other: evaluate to true
• If(1) printf(" …");
• If(-13) printf(" …");
&& - Logical AND
• All the conditions must be true for the whole
expression to be true
– Example: if (a == 1 && b == 2 && c == 3)
• means that the if statement is only true when a == 1
and b == 2 and c == 3
If (a = 5) …
e1
e2
Result = e1 && e2
e1
e2
Result = e1 && e2
0
0
0
false
false
false
0
1
0
false
true
false
1
0
0
true
false
false
1
1
1
true
true
true
|| - Logical OR
• The truth of one condition is enough to make
the whole expression true
• Example: if (a == 1 || b == 2|| c == 3)
– means the if statement is true when
either one of a, b or c has the right value
e1
e2
Result = e1 || e2
e1
e2
Result = e1 || e2
0
0
0
false
false
false
0
1
1
false
true
true
1
0
1
true
false
true
1
1
1
true
true
true
! - Logical NOT
• Reverse the meaning of a condition
• Example: if (!(radius > 90))
– Means if radius not bigger than 90.
e1
Result = !e1
e1
Result = !e1
0
1
false
true
1
0
true
false
Bitwise Operators
• Apply to all kinds of int and char types:
– signed and unsigned
– char, short, int, long, long long
Operator
Name
&
AND
Result is 1 if both operand bits are 1
|
OR
Result is 1 if either operand bit is 1
^
XOR
Result is 1 if operand bits are different
~
Description
Not (Ones Complement) Each bit is reversed
<<
Left Shift
Multiply by 2
>>
Right Shift
Divide by 2
Bitwise Operators
• Applicable for low level programming, e.g.:
– Port manipulation
– I/O programming
• Usually:
– &: set OFF one bit
– |: set ON one bit
– ^: reverse one bit
Conditional Operator
• The conditional operator (?:) is used to simplify
an if/else statement
– Condition ? Expression1 : Expression2;
• The statement above is equivalent to:
if (Condition)
Expression1;
else
Expression2;
• Which are more readable?
Comma Operator
• (Expression1 ,Expression2,…);
• Example:
– int x, y, z;
– z = (x = 2, y = x + 1);
– printf("z = %d", z);
int x, y, z;
x = 2;
y = x + 1;
z = y;
printf("z = %d", z);
sizeof
• The sizeof keyword returns the number of bytes of the
given expression or type
– returns an unsigned integer result
• sizeof variable_Identifier;
• sizeof (variable_Identifier);
• sizeof (Data_Taype);
• Example:
–
–
–
–
int x;
printf("size of x = %d", sizeof x);
printf("size of long long = %d", sizeof(long long));
printf("size of x = %d", sizeof (x));
Type Casting
• Explicit Type cast: carried out by programmer using casting
int k, i = 7;
float f = 10.14;
char c = 'B';
k = (i + f) % 3; // error
k = (int)(i + f) % 3;
• Implicit Type cast: carried out by compiler automatically
f = 65.6;
i = f; //f = (int)f;
c = i; // c = (int)i;
Precedence Rules
Primary Expression Operators
() [] . ->
Unary Operators
* &
+
left-to-right
-
!
~
++expr
--expr (typecast)
sizeof
right-to-left
* / %
+ >> <<
< > <= >=
Binary Operators
== !=
left-to-right
&
^
|
&&
||
Ternary Operator
?:
right-to-left
Assignment Operators
= += -= *= /= %= >>= <<= &= ^= |=
right-to-left
Post increment
expr++
-
Comma
,
expr--
left-to-right
Control Structures
• Sequence
• Decision selection statement
– The if statement is called a single-selection statement because it
selects or ignores a single action.
– The if…else statement is called a double-selection statement
because it selects between two different actions.
– The switch statement is called a multiple-selection statement
because it selects among many different actions
• Repetition
– while
– do…while
– for
Compound Statements
• A statement is a specification of an action to
be taken by the computer as the program
executes
• Compound Statements is a list of statements
enclosed in braces, { }
Decision Structure
• One of two possible actions is taken,
depending on a condition
• Selection structures are used to choose
among alternative courses of action
NO
YES
NO
YES
x < y?
Process A
Process B
Decision Structure
• The flowchart segment below shows how a
decision structure is expressed in C as an
if/else statement
Flowchart
NO
C programming language
YES
x < y?
if (x < y)
a = x * 2;
Calculate a as
x plus y.
Calculate a as
x times 2.
else
a = x + y;
Decision Structure
• The flowchart segment below shows a
decision structure with only one action to
perform
Flowchart
NO
C programming language
YES
if (x < y)
x < y?
a = x * 2;
Calculate a
as x times 2.
Combining Structures
NO
YES
x > min?
if (x > min)
Display “x is outside
{
the limits.”
if (x < max)
printf("x is within the limits");
else
printf("x is outside the limits");
}
else
printf("x is outside the limits");
NO
YES
x < max?
Display “x is outside
the limits.”
Display “x is
within limits.”
Example
if(x)
if(y)
printf("Yes");
else
printf("No");
if (x < 0)
sign = -1;
else if (x == 0)
sign = 0;
else
sign = 1;
if(x)
{
if(y)
printf("Yes");
else
printf("No");
}
if (x < 0.25)
count1++;
else if (x >= 0.25 && x < 0.5)
count2++;
else if (x >= 0.5 && x < 0.75)
count3++;
else
count4++;
if(x)
{
if(y)
printf("Yes");
}
else
printf("No");
Case Structure
• One of several possible actions is taken,
depending on the contents of a variable
Case Structure
• indicates actions to perform depending on the
value in years_employed
If years_employed = 2,
bonus is set to 200
If years_employed = 1,
bonus is set to 100
1
bonus = 100
If years_employed = 3,
bonus is set to 400
If years_employed is
any other value, bonus
is set to 800
CASE
years_employed
2
3
bonus = 200
bonus = 400
Other
bonus = 800
switch
• A switch statement allows a single variable (integer
or char) to be compared with several possible
constants
– A constant can not appear more than once, and
there can only be one default expression
switch
switch (variable)
{
case const:
statements...;
default:
statements...;
}
switch (c = toupper(getch()))
{
case ‘R’:
printf("Red");
break;
case ‘G’:
printf("Green");
break;
default:
printf("other");
}
Example
switch(betty)
{
case 1:
printf("betty = 1\n");
case 2:
printf("betty=2\n");
break;
case 3:
printf("betty=3\n");
break;
default:
printf("Not sure\n");
}
CASE
betty?
1
betty = 1
2
betty = 2
3
betty = 3
Other
Not sure
Repetition Structure
• A loop tests a condition, and if the condition
exists, it performs an action. Then it tests the
condition again. If the condition still exists, the
action is repeated. This continues until the
condition no longer exists
YES
x < y?
Process A
Repetition Structure
• The flowchart segment below shows a
repetition structure expressed in C as a while
loop
Flowchart
C programming language
while (x < y)
x++;
YES
x < y?
Add 1 to x
While
while (loop_repetition_condition)
statement;
OR
//Compound statement
while (loop_repetition_condition)
{
statement1;
statement2; // …
}
Controlling a Repetition Structure
• The action performed by a repetition structure
must eventually cause the loop to terminate.
Otherwise, an infinite loop is created
• In this flowchart segment, x is never changed.
Once the loop starts, it will never end
• How can this flowchart
be modified so it is no
longer an infinite loop?
YES
x < y?
Display x
Controlling a Repetition Structure
• Adding an action within the repetition that
changes the value of x
YES
x < y?
Display x
Add 1 to x
A Pre-Test Repetition Structure
• This type of structure is known as a pre-test
repetition structure. The condition is tested
BEFORE any actions are performed
– if the condition does not exist, the loop will never
begin
YES
x < y?
Display x
Add 1 to x
Example
while (1);
int counter = 0;
while (counter < 1000) ;
int counter = 0;
while (counter < 9)
printf("%d\n", counter ++);
int counter = 9;
while (counter > 0)
printf("%d\n", counter --);
int counter = 0;
while (counter < 9)
{
printf("%d\n", counter);
counter++;
}
int counter = 0;
while (counter < 9)
{
printf("%d\n", counter ++);
}
A Post-Test Repetition Structure
• The condition is tested AFTER the actions are
performed
– A post-test repetition structure always performs
its actions at least once
C programming language
do
{
printf(…);
x++;
} while (x < y);
Display x
Add 1 to x
x < y?
YES
do-while
do
statement;
while (loop_repetition_condition)
OR
do //Compound statement
{
statement1;
statement2; // …
}
while (loop_repetition_condition)
For
for (initial_value ; condition; update_counter)
statement;
OR
// Compound statement
for (initial_value ; condition; update_counter)
{
statement;
statement; // …
}
Array
• Generic declaration:
typename variablename[size];
–
–
–
–
–
–
typename is any type
variablename is any legal variable name
size is a number the compiler can figure out
For example :
int a[10];
Defines an array of ints with subscripts ranging from 0 to 9
There are 10*sizeof(int) bytes of memory reserved for this
array.
0
a
1
2
3
4
5
6
7
8
10
– You can use a[0]=10; x=a[2]; a[3]=a[2]; etc.
– You can use scanf("%d",&a[3]);
9
Array Representation
int A[3];
0x1008
A[2]
0x1004
A[1]
0x1000
A[0]
All elements of same type – homogenous
Last element (index size - 1)
First element (index 0)
A[-1]
array[0] = 3;
array[2] = 4;
array[10] = 5;
array[-1] = 6;
No bounds checking!
3 * 4 = 12
sizeof(A)?
sizeof(A[0]) = sizeof(A[1]) = sizeof(A[2])?
4
Using Constants to Define Arrays
• It is useful to define arrays using constants:
#define MONTHS 12
float a [MONTHS];
• However, in ANSI C, you cannot
int n;
scanf(“%d”, &n);
float a[n];
• In GNU C, the variable length array is allowed.
Initializing Arrays
• Initialization of arrays can be done by a comma
separated list following its definition
• For example:
int array [4] = { 100, 200, 300, 400 };
– This is equivalent to:
int array [4];
array[0] = 100;
array[1] = 200;
array[2] = 300;
array[3] = 400;
• You can also let the compiler figure out the array
size for you:
int array[] = { 100, 200, 300, 400};
Initializing Arrays
• For example:
int array [4] = { 100, 200 };
• Also can be done by
int array [4] = { 100, 200, 0, 0 };
– This is equivalent to
int array [4];
array[0] = 100;
array[1] = 200;
array[2] = 0;
array[3] = 0;
Multidimensional Arrays
• Arrays in C can have virtually as many dimensions
as you want
• Definition is accomplished by adding additional
subscripts when it is defined
• For example:
– int a [4] [3] ;
• 2-dimensional array
• 4 * 3 * sizeof(int)
– int a[4][3][2]
• 3-dimention array
• 4 * 3 * 2 * sizeof(int)
Multidimensional Arrays Representation
a[0][0]
a[0][1]
a[0][2]
a[0][3]
Row 0
Row 1
Row 2
Column 0
Column 1
Column 2
Column 3
a[ 0 ][ 0 ]
a[ 0 ][ 1 ]
a[ 0 ][ 2 ]
a[ 0 ][ 3 ]
a[ 1 ][ 0 ]
a[ 1 ][ 1 ]
a[ 1 ][ 2 ]
a[ 1 ][ 3 ]
a[ 2 ][ 0 ]
a[ 2 ][ 1 ]
a[ 2 ][ 2 ]
a[ 2 ][ 3 ]
a[1][0]
a[1][1]
a[1][2]
Column subscript
Array name
Row subscript
a[1][3]
a[2][0]
a[2][1]
a[2][2]
a[2][3]
int a[n][m] ;
&a[i][j] = [(m * i) + j] * (sizeof(int)) + &a[0]
Initializing Multidimensional Arrays
• The following initializes a[4][3]:
int a[4] [3] = { {1, 2, 3} ,
{4, 5, 6} ,
{7, 8, 9} ,
{10, 11, 12} };
• Also can be done by:
int a[4] [3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
– is equivalent to
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
...
a[3][2] = 12;
Examples
• Initialization
– Example:
• short b[ 2 ][ 2 ] = { { 1, 2 }, { 3, 4 } };
1
2
3
4
– If not enough, unspecified elements set to zero
• short b[ 2 ][ 2 ] = { { 1 }, { 3, 4 } };
1
0
3
4
Examples
int a[10]; // Ok
int a[2.5]; // Syntax error
int a[-5]; // Syntax error
int a[0]; // Logical error
a[3.6] = 10; // Syntax error or a[3] = 10;
a[3.2] = 10; // Syntax error or a[3] = 10;
int b[2][3] = { {1, 2}, {3, 4}, {5, 6} }; // Syntax error
Strings are Character Arrays
• Strings in C are simply arrays of characters
– Example:char s [10];
• This is a ten (10) element array that can hold a
character string consisting of  9 characters
• This is because C does not know where the end of an
array is at run time
– By convention, C uses a NULL character '\0' to terminate all
strings in its library functions
• For example:
char str [10] = {'u', 'n', 'I', 'x', '\0'};
• It’s the string terminator (not the size of the array) that
determines the length of the string
Accessing Individual Characters
• The first element of any array in C is at index 0. The
second is at index 1, and so on ...
char s[10];
s[0] = 'h';
s[1] = 'i’;
s[2] = '!';
s[3] = '\0';
h
s
i
!
\0
?
?
?
?
?
[0] [1] [2] [3] [4] [5] [6] [7] [8]
?
[9]
• This notation can be used in all kinds of statements and
expressions in C:
– For example:
c = s[1];
if (s[0] == '-') …
switch (s[1]) ...
String Literals
• String literals are given as a string quoted by
double quotes
– printf("Long long ago.");
• Initializing char array ...
– char s[10] = "unix"; /* s[4] is '\0';
*/
– char s[ ] = "unix"; /* s has five elements */
Pointer Fundamentals
• When a variable is defined the
compiler (linker/loader actually)
allocates a real memory address
for the variable
– int x;
– &x = 22f54;
// &x = 22f54;
// Error
x
&
*
22F54
00000000
522F5
00000000
22F56
00000000
22F57
00000011
• When a value is assigned to a variable, the
value is actually placed to the memory that
was allocated
– x = 3;
// * (&x) = 3;
– *x = 3; // Error
Pointer Fundamentals
• When the value of a variable is used, the contents in the
memory are used
– y = x;
&
*
– y = *(&x);
x
22F54
00000000
522F5
00000000
22F56
00000000
22F57
00000011
• &x can get the address of x (referencing operator &)
• The address can be passed to a function:
– scanf("%d", &x);
• The address can also be stored in a variable …
Pointers
• To declare a pointer variable
type * PointerName;
x
• For example:
int
x;
int * p;
//p is a int pointer
// char *p2;
p1 = &x;
/* Initializing p1 */
p
&
*
22F50
?
22F51
?
22F52
?
22F53
?
22F54
00
522F5
02
22F56
2F
22F57
50
…
Initializing Pointers
• Like other variables, always initialize pointers before
using them!!!
*
22F50
?
22F51
?
22F52
?
22F53
Compiler
p 22F54
?
00
522F5
02
22F56
2F
22F57
50
x
…
Developer
void main()
{
int x;
int *p;
scanf("%d", p); /*
*/
Don’t
p = &x;
scanf("%d", p); /* Correct */
}
&
Using Pointers
• You can use pointers to access the values of other variables,
i.e. the contents of the memory for other variables
• To do this, use the * operator (dereferencing operator)
– Depending on different context, * has different meanings
• For example:
& *
int n, m = 3, *p;
n
p = &m; // Initializing
m 3
n = *p;
printf("%d\n", n); // 3
printf("%d\n", *p); // 3 p
*P = 10;
printf("%d\n", n); // 3
printf("%d\n", *p); // 10
& *
& *
& *
n
n
n
m 3
m 3
m 10
p
p
p
3
3
Pointer Assignment
int a = 2, b = 3;
int *p1, *p2;
p1 = &a;
p2 = &b;
printf("%p %p", p1 ,p2);
*p1 = *p2;
printf("%d %d", *p1, *p2);
p2 = p1;
printf("%p %p", p1, p2);
printf("%p %p", &p1, &p2);
&
*
b
3
a
2
p1
p2
&
*
b
3
a
3
p1
p2
Constant Pointers
• A pointer to const data does not allow
modification of the data through the pointer
const int a = 10, b = 20;
a = 5; // Error
const int *p;
int *q;
p = &a;
*p = 100; // Error : p is (const int *)
p = &b;
q = &a;
*q = 100; // OK !!!
Constant Pointers
int x; /* define x */
int y; /* define y */
/*ptr is a constant pointer to an integer that can be
modified through ptr, but ptr always points to the
same memory location */
int * const ptr = &x;
*ptr = 7; /* allowed: *ptr is not const */
ptr = &y; /* error: cannot assign new address */
Constant Pointers
int x = 5; /* initialize x */
int y;
/* define y */
/*ptr is a constant pointer to a constant integer. ptr
always points to the same location; the integer at
that location cannot be modified */
const int * const ptr = &x;
*ptr = 7; /* error: cannot assign new value */
ptr = &y; /* error: cannot assign new address */
Multiple indirection
int a = 3;
int *b = &a;
int **c = &b;
int ***d = &c;
int ****f = &d;
&
*
a
3
b
c
d
f
NULL Pointer
• Special constant pointer NULL
– Points to no data
– Dereferencing illegal
– To define, include <stdlib.h> or <stdio.h>
– int *q = NULL;
Generic Pointers: void *
• void *: a pointer to anything
void
*p;
int
i;
char
c;
p = &i;
p = &c;
putchar(*(char *)p);
type cast: tells the compiler to change an
object’s type (for type checking purposes
– does not modify the object in any way)
• Lose all information about what type of thing
is pointed to
– Reduces effectiveness of compiler’s type-checking
– Can’t use pointer arithmetic
Arithmetic Operations
• A pointer may be incremented or decremented
– An integer may be added to or subtracted from a
pointer.
– Pointer variables may be subtracted from one another
int a, b;
int *p = &a, *q = &b;
p = p + q ; // Error
p = p * q; // Error
p = p / q; // Error
p = p - q; // OK
p = p + 3;
p += 1.6; // Error
p %= q; // Error
Arithmetic Operations
• When an integer is added to or subtracted
from a pointer, the new pointer value is
changed by the integer times the number of
bytes in the data variable the pointer is
pointing to
– For example, if the pointer p contains the address
of a double precision variable and that address is
234567870, then the statement:
p = p + 2; // 234567870 + 2 * sizeof(double)
would change p to 234567886
Logical Operations
• Pointers can be used in comparisons
int a[10], *p, *q , i;
p = &a[2];
q = &a[5];
i = q - p;
/* i is 3*/
i = p - q;
/* i is -3 */
a[2] = a[5] = 0;
i = *p - *q; // i = a[2] – a[5]
if (p < q) ...;
/* true */
if (p == q)...;
/* false */
if (p != q) ...;
/* true */
&
*
p
q
[0]
?
[1]
?
[2]
?
[3]
?
[4]
?
[5]
?
[6]
?
[7]
?
[8]
?
[9]
?
Pointers and Arrays
Array  pointer to the initial
(0th) array element
a  &a[0]
a[i]  *(a+i)
&a[i]  a + i
Example:
int a, *p;
p=&a;
*p = 1;
p[0] = 1;
a
[0]
p
[1]
int a[ 10 ], *p;
p = &a[2];
p[0] = 10;
p[1] = 10;
printf("%d", p[3]);
int a[ 10 ], *p;
a[2] = 10;
a[3] = 10;
printf("%d", a[5]);
p[0]
p[1]
p[2]
p[3]
p[4]
p[5]
p[6]
p[7]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
Pointers and Arrays
Array  pointer to the initial (0th) array element
a  &a[0]
a[i]  *(a+i)
&a[i]  a + i
int
int
i;
array[10];
for (i = 0; i < 10; i++)
{
array[i] = …;
}
0
a
1
2
3
a+1 a+2 a+3
int *p;
int array[10];
for (p = array; p < &array[10]; p++)
{
*p = …;
}
These two blocks of code are functionally equivalent
An Array Name is Like a Constant Pointer
• Array name is like a constant pointer which
points to the first element of the array
int a[10], *p, *q;
int * const a
p = a;
/* p = &a[0] */
q = a + 3;
/* q = &a[0] + 3 */
a ++;
/* Error !!! */
Example
int a[10], i;
int *p = a; // int *p = &a[0];
for (i = 0; i < 10; i++)
scanf("%d", a + i); // scanf("%d", &a[i]);
for (i = 9; i >= 0; --i)
printf("%d", *(p + i));
// printf("%d", a[i]);
//printf("%d", p[i]);
for (p = a; p < &a[10]; p++)
printf("%d", *p);
An example
int a[10], *p, *q;
p = &a[2];
q = p + 3;
p = q – 1;
p++;
q--;
*p = 123;
*q = *p;
q = p;
printf("%d", *q);
&
*
&
p
p
q
q
*
[0]
?
[0]
?
[1]
?
[1]
?
[2]
?
[2]
?
[3]
?
[3]
?
[4]
?
[4]
123
[5]
?
[5]
123
[6]
?
[6]
?
[7]
?
[7]
?
[8]
?
[8]
?
[9]
?
[9]
?
An Example
int a[10], *p;
a++; //Error
a--; // Error
a += 3; //Error
p = a; // p = &a[0];
p ++; //OK
p--; // Ok
P +=3; // Ok
Strings
• In C, strings are just an array of characters
– Terminated with ‘\0’ character
– Arrays for bounded-length strings
– Pointer for constant strings (or unknown length)
char
H
e
l
l
str1[15] = "Hello, world!“;
o
,
char str1[]
char *str2
H
e
l
l
o
,
w
o
r
l
d
!
\0
!
\0
= "Hello, world!";
= "Hello, world!";
w
o
r
l
d
An Example
void copy1(char * const s1, const char * const s2)
{
int i; /* counter */
/* loop through strings */
for ( i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ ); /* do nothing in
body */
}
void copy2(char *s1, const char *s2)
{
/* loop through strings */
for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ ); /* do nothing in
body */
}
Multi-Dimensional Arrays
int a[row][col];
a[row][col]  *(*(a + row) + col)
a[row][col]  *(a[row] + col)
&a[row][col]  a[row] + col
a  a[0][0]  a[0]
a[0] + 2
scanf(" %d ", &a[0][0])  scanf(" %d ", a[0])
printf (" %d ", a[0][0])  printf(" %d ", *a[0])
scanf(" %d ", &a[2][2])  scanf(" %d ", a[2]+ 2)
printf (" %d ", a[2][2])  printf(" %d ", *(a[2] + 2))
a[0]

[0][0] [0][1] [0][2] [0][3] [0][4] [0][5] [0][6] [0][7] [0][8] [0][9]
a[1]

[1][0] [1][1] [1][2] [1][3] [1][4] [1][5] [1][6] [1][7] [1][8] [1][9]
a[2]

[2][0] [2][1] [2][2] [2][3] [2][4] [2][5] [2][6] [2][7] [2][8] [2][9]
a[3]

[3][0] [3][1] [3][2] [3][3] [3][4] [3][5] [3][6] [3][7] [3][8] [3][9]
a[4]

[4][0] [4][1] [4][2] [4][3] [4][4] [4][5] [4][6] [4][7] [4][8] [4][9]
Array of Pointers
char *suit[ 4 ] = { "Hearts", "Diamonds", "Clubs",
"Spades" };
suit[0]

H
e
a
r
t
s
\0
suit[1]

D
i
a
m
o
n
d
suit[2]

C
l
u
b
s
\0
suit[3]

S
p
a
d
e
s
\0
s
\0
Array of Pointers
int a=1, b=2, c=3, d=4;
int *k[4] = {&a, &b, &c, &d};
&
*
k[0]
k[1]
k[2]
k[3]
k[0]

a
1
a
1
k[1]

b
2
b
2
k[2]

c
3
c
3
k[3]

d
4
d
4
printf("%d %d %d %d", *k[0], *k[1],*k[2],*k[3]);
Functions
• Every C program starts with main() function
• Functions could be
– Pre-defined library functions
• e.g., printf, sin, tan
– Programmer-defined functions
• e.g., my_printf, area
int main()
{
…
}
Functions - Definition Structure
• Function 'header'
– Return data type
(if any)
– Name
type function_name (type arg1, type arg2 )
{
statements;
}
• Descriptive
– Arguments (or parameter list)
A function that calculates
the product of two numbers
• Notice: data type and name
• Statements
– Variable declaration
– Operations
– Return value (if any)
double product(double x, double y)
{
double result;
result = x * y;
return result;
}
An Example
Function prototype
–
Like a variable declaration
•
•
•
Tells compiler that the function will be defined later
Helps detect program errors
Note semicolon!!
Function definition
–
–
See previous slide
Note, NO semicolon
Function return
–
–
–
return statement terminates execution of the
current function
Control returns to the calling function
if return expression;
•
•
then value of expression is returned as the value
of the function call
Only one value can be returned this way
Function call
–
–
–
–
main() is the 'calling function'
product() is the 'called function'
Control transferred to the function code
Code in function definition is executed
#include <stdio.h>
/* function prototype */
double product(double x, double y);
int main()
{
double var1 = 3.0, var2 = 5.0;
double ans;
ans = product(var1, var2);
printf("var1 = %.2f\n"
"var2 = %.2f\n",var1,var2);
printf("var1*var2 = %g\n", ans);
return 0;
}
/* function definition */
double product(double x, double y)
{
double result;
result = x * y;
return result;
}
Formal and Actual Parameters
#include <stdio.h>
int calSum(int,int);
Formal Parameters
/*function prototype*/
int main(void)
Actual Parameters
{
…..
…..
sum = calSum(num1,num2); /* function call */
…..
}
int calSum(int val1, int val2) /*function header*/
{
……
Formal Parameters
……
……
}
An Example
• If the function requires some arguments to be passed along, then
the arguments need to be listed in the ( ) according to the specified
order
void Calc(int, double, char, int);
int main(void)
{
int a, b;
double c;
char d;
…
Calc(a, c, d, b);
return (0);
}
Function Call
Functions that do not return a value
• Use the return type of void
– void functionName( DataType arg_1,…)
– void functionName()
– void functionName( void)
Function Call – An Example
#include <stdio.h>
1
//function prototype
//global variable declaration
2
int main(void)
{
local variable declaration;
statements;
fn1( );
fn2( );
return (0);
}
3
4
void fn1(void)
{
local variable declaration;
statements;
}
void fn2(void)
{
local variable declaration;
statements;
return;
}
Call by value And Call by reference
• Call by value
– In this method, only the copy of variable’s value (copy of actual
parameter’s value) is passed to the function. Any modification
to the passed value inside the function will not affect the actual
value
– In all the examples that we have seen so far, this is the method
that has been used
• Call by reference
– In this method, the reference (memory address) of the variable
is passed to the function. Any modification passed done to the
variable inside the function will affect the actual value
– To do this, we need to have knowledge about pointers and
arrays
Call by value – An Example
#include <stdio.h>
int calSum(int,int);
/*function protototype*/
int main(void)
{
int sum, num1, num2;
printf("Enter two numbers to calculate its sum:\n");
scanf("%d%d",&num1,&num2);
sum = calSum(num1,num2); /* function call */
printf("\n %d + %d = %d", num1, num2, sum);
return(0);
num2
?
4
num1
9?
sum
13
?
val2
100
4
val1
9
sum
?
13
}
int calSum(int val1, int val2) /*function definition*/
{
int sum;
sum = val1 + val2;
val2 = 100;
Enter two numbers
return sum;
4
9
}
to calculate its sum:
4 + 9 = 13
Press any key to continue
Call by reference
#include <stdio.h>
void CalByVal(int a, int b)
{
a = 0; b = 10;
}
void CalByRef(int *a, int *b) // CalByRef(int *p, int *q)
{
*a = 0; *b = -5; // a = 0; !!!!
}
int main(void)
{
int a = 1, b = 5;
printf("Before cal CalByVal: a = %d, b = %d\n", a, b);
CalByVal(a, b);
printf("After cal CalByVal: a = %d, b = %d\n", a, b);
printf("Before cal CalByRef: a = %d, b = %d\n", a, b);
CalByRef(&a, &b);
printf("After cal CalByRef: a = %d, b = %d\n", a, b);
getch();
return 0; /* Exit program. */
}
b
10
5
CalByVal
a
b
1
0
CalByRef
b
-5
5
main
a
1
0
a
Pointers and Arrays
• Recall that the value of an array name is also an address
void main()
{
int x[10];
ReOrder(x); // ReOrder(&x);
}
void ReOrder(int *x)
{
int i, j, t;
for(i = 0; i < 9; i++)
for(j = i + 1; i < 10; ++j)
if(x[i] < x[j])
{
t = x[i]; x[i] = x[j]; x[j] = t;
}
}
Organizing Multi-File Programs
• A large C program should be divided into multiple files
// main.c
#include <stdio.h>
void Test()
{
// …
}
int main()
{
// …
return 0;
}
// math.c
double mathVar;
double sin()
{
double tempSin;
// …
return tempSin;
}
Identifiers and Scope
• Identifier
– The name of a variable, function, label, etc.
• int my_var1; /* a variable */
• pow_table();/* a function */
• start:
/* a label */
• Question:
– Does it make a difference where in a program an
identifier is declared?
YES! --> concept of ‘scope’
Scope of Identifiers
• Scope of a declaration of an identifier
– The region of the program that the declaration is
active (i.e., can access the variable, function, label,
etc.)
• Five types of scope:
– Program (global scope)
– File
– Function prototype
– Function
– Block ("between the { } scope")
Scope of Identifiers - Program Scope
• Program (global) scope
– if declared outside of all
functions
– "Visible" to all functions
from point of declaration
– Visible to functions in other
source files
– Use only when necessary
and then very carefully!!
– If there exist a local variable
and a global variable with
the same name, the
compiler will refer to the
local variable
#include <stdio.h>
int a = 10;
double product(double x, double y);
int main()
{
double var1 = 3.0, var2 = 5.0;
double ans;
a = 10
ans = product(var1, var2);
// …
a = 20
}
/* function definition */
double product(double x, double y)
{
double result; a = 20;
result = x * y;
return result;
}
An Example
// File name: main.c
#include <stdio.h>
int a = 10;
// File name: ExternFile.c
extern
int a = 10;
/* function definition */
void TestExtern()
{
// …
a = 90;
// …
}
/* function definition */
double product(double x, double y)
{
double result;
// …
a = 70;
return result;
}
int main()
{
a = 80;
}
Scope of Identifiers - File Scope
• File scope
– Keyword static
• Makes variable a ‘visible’
only within this source file
– Use file scope to avoid
naming conflict if multiple
source files are used
#include <stdio.h>
static int a = 10;
double product(double x, double y);
int main()
{
double var1 = 3.0, var2 = 5.0;
double ans;
ans = product(var1, var2);
// …
}
/* function definition */
double product(double x, double y)
{
double result;
result = x * y;
return result;
}
An Example
// File name: main.c
#include <stdio.h>
static int a = 10;
// File name: ExternFile.c
extern
int a = 10;
/* function definition */
void TestExtern()
{
// …
a = 90;
// …
}
/* function definition */
double product(double x, double y)
{
double result;
// …
a = 70;
return result;
}
int main()
{
a = 80;
}
Scope of Identifiers - Function Prototype Scope
• Function prototype scope
– Identifiers x and y are not
visible outside the prototype
– Thus, names in the prototype
do not have to match names in
the function definition
• MUST match types, however!
#include <stdio.h>
double product(double x, double y);
int main()
{
int a = 10;
double var1 = 3.0, var2 = 5.0;
double ans;
ans = product(var1, var2);
printf("var1 = %.2f\n"
"var2 = %.2f\n",var1,var2);
printf("var1*var2 = %g\n", ans);
}
/* function definition */
double product(double A, double B)
{
double result;
result = A * B;
return result;
}
Scope of Identifiers - Function Scope
• Function scope
– Active from the beginning to the end of a function
#include <stdio.h>
int main()
{
int a;
// …
return 0;
}
int FunctionScopeTest()
{
int b;
// …
return 0;
}
Scope of Identifiers - Block Scope
• Block (local) scope
– A block is a series of
statements enclosed in braces
{}
– The identifier scope is active
from the point of declaration
to the end of the block ( } )
– Nested blocks can
both declare the same
variable name and not
interfere
#include <stdio.h>
double product(double x, double y);
int main()
{
int a = 10;
double var1 = 3.0, var2 = 5.0;
double ans;
ans = product(var1, var2);
// …
}
/* function definition */
double product(double x, double y)
{
double result; // a = 60; Error
result = x * y;
return result;
}
An Example
#include <stdio.h>
int a = 10;
int f1()
{
int a;
a = 70;
{
int a;
a = 100;
}
return a;
}
void main()
{
a = 80;
f1();
}
a=?
a = 70
a = 100
a = 70
a = 10
a = 80
Storage Classes
• Refers to the lifetime of a variable
• Local variables only exist within a function by
default. When calling a function repeatedly, we
might want to
– Start from scratch – reinitialize the variables
• The storage class is ‘auto’
– Continue where we left off – remember the last value
• The storage class is ‘static’
• Another two storage classes (seldomly used)
– register (ask to use hardware registers if available)
– extern (global variables are external)
Auto storage class
• Variables with automatic storage duration are
created when the block in which they are
declared is entered, exist when the block is active
and destroyed when the block is exited.
• The keyword auto explicitly declares variables of
automatic storage duration. It is rarely used
because when we declare a local variable, by
default it has class storage of type auto.
– int a, b; // is the same as
– auto int a, b;
Static storage class
• However the static keyword can be applied to
a local variable so that the variable still exist
even though the program has gone out of the
function. As a result, whenever the program
enters the function again, the value in the
static variable still holds
Auto - Example
#include <stdio.h>
void auto_example(void);
int main(void)
{
int i;
printf("Auto example:\n");
auto_example( );
auto_example( );
auto_example( );
return(0);
}
void auto_example(void)
{
auto int num = 1;
printf(" %d\n",num);
num = num + 2;
}
Auto example:
1
1
1
Press any key to continue
Static - Example
#include <stdio.h>
void auto_example(void);
int main(void)
{
int i;
printf("Static example:\n");
static_example( );
static_example( );
static_example( );
return(0);
}
void static_example(void)
{
static int num = 1;
printf(" %d\n",num);
num = num + 2;
}
Static example:
1
3
5
Press any key to continue
Recursion
•
Recursion is a technique that solves a problem by solving a smaller problem of the
same type
•
A recursive function is a function invoking itself, either directly or indirectly
– Recursion: A → B → C → D → A
•
Concept of recursive function (generally):
– A recursive function is called to solve a problem
– The function only knows how to solve the simplest case of the problem. When the simplest
case is given as an input, the function will immediately return with an answer
– However, if a more complex input is given, a recursive function will divide the problem into 2
(or more) pieces: a part that it knows how to solve and another part that it does not know
how to solve
if (stopping case)
solve it
else
reduce the problem using recursion
Recursion solution of xy
#include <stdio.h>
double XpowerY(double, int);
int main(void)
{
double power, x; int y;
printf("Enter the value of x and y:\n");
scanf("%lf%d", &x, &y);
power = XpowerY(x, y);
printf("%.2f to the power of %d is %.2f\n\n", x, y, power);
return(0);
Enter the value of x and y:
}
2
double XpowerY(double x, int y)
3
2.00 to the power of 3 is 8.00
{
Press any key to continue
if (y ==1)
return x;
else
return x * XpowerY(x, y-1);
}
Recursive Steps of xy
#include <stdio.h>
double XpowerY(double, int);
int main(void)
2
{
double power, x; int y;
printf("Enter the value of x and y:\n");
scanf("%lf%d", &x, &y);
power = XpowerY(x, y);
2*2
printf("%.2f to the power of %d is %.2f\n\n", x, y, power);
return(0);
}
double XpowerY(double x, int y)
2*4
{
if (y ==1)
return x;
else
2*8
return x * XpowerY(x, y-1);
}
x = 2; y = 2;
return x;
x = 2; y = 2;
x * XpowerY(2, 1)
x = 2; y = 3;
x * XpowerY(2, 2)
x = 2; y = 4;
x * XpowerY(2, 3)
Pointer to Function
#include <stdio.h>
void f1(float a){ printf("F1 %g", a);}
void f2(float a){ printf("F2 %g", a);}
int main(){
void (*ptrF)(float a);
ptrF = f1;
ptrF(12.5);
ptrF = f2;
ptrF(12.5);
getch();
return 0;
}
A function pointer is defined in
the same way as a function
prototype, but the function
name is replaced by the
pointer name prefixed with an
asterisk and encapsulated with
parenthesis
Example:
int (*fptr)(int, char)
fptr = some_function;
(*ftpr)(3,'A');
some_function(3,'A');
Array of Functions
#include<stdio.h>
void func1() { printf("Function 1 Called\n"); }
void func2() { printf("Function 2 Called\n"); }
void func3() { printf("Function 3 Called\n"); }
int main(int argc, char *argv[])
{
void (*ptr[3]) () = {func1, func2, func3};
int k = 0;
for(k = 0; k < 3; k++)
ptr[k]();
getch();
return 0;
}
Passing Arrays to Functions
#include <stdio.h>
void display(int a)
{
printf("%d",a);
}
int main()
{
int c[] = {2,3,4};
display(c[2]); //Passing array element c[2] only
return 0;
}
Passing Arrays to Functions
#include <stdio.h>
float average(float a[], int count); // float average(float *a, int count)
int main(){
float avg, c[]={23.4, 55, 22.6, 3, 40.5, 18};
avg=average(c, 6);
/* Only name of array is passed as argument */
printf("Average age=%.2f", avg);
return 0;
}
float average(float a[], int count){ // float average(float
int I; float avg, sum = 0.0;
for(I = 0;I < count; ++i) sum += a[i];
avg = (sum / 6);
return avg;
}
*a)
void func (int* x); /* this is a pointer */
void func (int x[]); /* this is a pointer */
void func (int x[10]); /* this is a pointer */
Passing Arrays to Functions
#include <stdio.h>
void f1(float *a) { a[1] = 100;}
void f2(float a[]){ a[2] = 200;}
void printArrat(float a[])
{
int i = 0;
for(; i < 6; i++) printf("%g ", a[i]);
}
int main(){
float c[]={23.4, 55, 22.6, 3, 40.5, 18};
f1(c);
printArrat(c);
puts("");
f2(c);
printArrat(c);
getch();
return 0;
}
Passing Array By Reference
23.4
55
22.6
3
40.5
18
23.4
100
22.6
3
40.5
18
23.4
100
200
3
40.5
18
Passing 2D, 3D,… Array to Functions
• Only the first dimension may be omitted
– int m[5][7];
– func(m);
– void func(int a[5][7]) { ... }
– void func(int a[][7]) { ... }
Allocating Memory for a Pointer
// The following program is wrong!
// This one is correct:
#include <stdio.h>
#include <stdio.h>
int main()
int main()
Don’t
{
{
int *p;
int *p;
scanf("%d", p);
int a;
return 0;
p = &a;
}
scanf("%d", p);
return 0;
}
malloc
• Prototype: void *malloc(size_t size); #include <stdlib.h>
– function returns the address of the first byte
– programmers responsibility to not lose the pointer
• Example:
Key
int *ptr;
ptr = (int *)malloc(sizeof(int)); // new allocation
new allocation
10
ptr
Memory
0
previously allocated
1
2
3
4
5
6
7
8
9
10 11 12 13 14 15 16
free
• Prototype: void free(void *ptr)
– releases the area pointed to by ptr
– ptr must not be null
#include <stdlib.h>
• trying to free the same area twice will generate an error
2
p2
5
p1
initial memory
0
1
2
3
2
p2
4
5
6
7
free(p1);
NULL
p1
after free
0
1
2
3
4
5
6
7
Key
allocated memory
free memory
Allocating Memory for a Pointer
• There is another way to allocate memory so the
pointer can point to something:
#include <stdio.h>
#include <stdlib.h>
int main(){
int *p;
p = (int *) malloc( sizeof(int) ); /* Allocate 4 bytes */
scanf("%d", p);
printf("%d", *p);
// ....
free(p); /* This returns the memory to the system*/
/* Important !!! */
}
Allocating Memory for a Pointer
• You can use malloc and free to dynamically
allocate and release the memory
int *p;
p = (int *) malloc(1000 * sizeof(int) );
for(i=0; i<1000; i++)
p[i] = i;
p[999]=3;
p[1000]=3; /* Wrong! */
free(p);
p[0]=5;
/* Wrong! */
Structures
• Structures
– Be able to use compound data structures in programs
• Unions
– Be able to share storage space of their members
• Bit fields Structures
– Be able to do simple bit-vector manipulations
• Enumerations
– Be able to use compound symbolic constants
User Defined Data Types (typedef)
• The C language provides a facility called typedef for creating
synonyms for previously defined data type names.
• For example, the declaration:
typedef int Length;
makes the name Length a synonym (or alias) for the data type int.
• The data type name Length can now be used in declarations in
exactly the same way that the data type int can be used:
Length a, b, len ;
Length numbers[10] ;
typedef char String[50];
typedef int Array[10];
String name;
Array ages;
Structures (struct)
• Structures—sometimes referred to as aggregates—are collections
of related variables under one name
• Structures may contain variables of many different data types—in
contrast to arrays that contain only elements of the same data type
• Structures are commonly used to define records to be stored in
files
• Pointers and structures facilitate the formation of more complex
data structures such as linked lists, queues, stacks and trees
• Structures are derived data types—they are constructed using
objects of other types
Declaring Structures (struct)
• The name "employee" is called a structure tag
• Variables declared within the braces of the structure
definition are the structure’s members
struct employee
struct employee
{
{
char firstName[ 20 ];
char firstName[ 20 ];
char lastName[ 20 ];
char lastName[ 20 ];
int age;
char gender;
int age;
double hourlySalary;
char gender;
double hourlySalary; } Ali, Sara, empDTS[20];
};
struct employee Reza,
struct employee Ali,
*emp;
emp[10];
struct
{
char firstName[ 20 ];
char lastName[ 20 ];
int age;
char gender;
double hourlySalary;
} Ali;
Declaring Structures (struct)
• Often, typedef is used in combination with struct to declare a
synonym (or an alias) for a structure:
typedef struct
{
char firstName[ 20 ];
char lastName[ 20 ];
int age;
char gender;
double hourlySalary;
} employee; /* The "alias"
employee
Ali; /* Create a struct variable */
struct employee
{
char firstName[ 20 ];
char lastName[ 20 ];
int age;
char gender;
double hourlySalary;
} Ali, Sara, empDTS[20];
struct employee Reza, *emp;
Declaring Structures (struct)
• Members of the same structure type must have
unique names, but two different structure types may
contain members of the same name without conflict
struct employee
{
char Name[ 20 ];
char Name[ 20 ]; // Error!!!
int age;
char gender;
double hourlySalary;
} Ali, Sara, empDTS[20];
struct employee Reza, *emp;
struct Student
{
char Name[ 20 ]; // OK
int age;
char gender;
};
struct Student Ce40153[80];
• Each structure definition must end with a semicolon
Declaring Structures (struct)
• A structure cannot contain an instance of itself
• For example, a variable of type struct employee cannot
be declared in the definition for struct employee A
pointer to struct employee, however, may be included
struct employee2 {
// …
double hourlySalary;
struct employee2 person; /* ERROR */
struct employee2 *ePtr; /* pointer */
};
• A structure containing a member that is a pointer to
the same structure type is referred to as a selfreferential structure
Declaring Structures (struct)
• The structure tag name is optional
struct
{
char firstName[ 20 ];
char lastName[ 20 ];
int age;
char gender;
double hourlySalary;
} Ali;
• If a structure definition does not contain a
structure tag name, variables of the structure
type may be declared only in the structure
definition—not in a separate declaration
Memory layout
struct COST {
int amount;
char currency_type[2];
}
struct PART {
char id[2];
struct COST cost;
int num_avail;
}
id
currency_type
amount
num_avail
cost
• Here, the system uses 4-byte alignment of integers, so amount and
num_avail must be aligned Four bytes wasted for each structure!
Memory layout
struct COST {
int amount;
char currency_type[2];
}
struct PART {
struct COST cost;
char id[2];
int num_avail;
currency_type
}
amount
cost
• Implementation dependent!!!
id
num_avail
Accessing Struct Members
• Individual members of a struct variable may be accessed using the
structure member operator (the dot, "."):
myEmp.firstName ;
struct employee
{
employee. firstName; // Error
char firstName[ 20 ];
// …
} myEmp;
• Or , if a pointer to the struct has been declared and initialized
employee *emp = &myEmp ;
– by using the structure pointer operator :
emp -> firstName; // arrow operator
– which could also be written as:
(* emp).firstName;
An Example - Initialization
//Create a struct but don’t reserve space
struct personal
{
long id; // student ID
float gpa; // grade point average
};
struct identity js = {"Joe", "Smith",
js.person.id = 123456789 ;
js.person.gpa = 3.4 ;
struct identity
{
char FirstName[30];
char LastName[30];
unsigned age;
struct personal person;
};
25}, *ptr = &js ;
jsstrcpy(js.FirstName,
=js.{"Joe",
"Smith",
9, 10}
"Joe");
personal
.id 25,
Error
printf ("%s %s %d %ld %f\n", js.FirstName, js.LastName, js.age, js.person.id, js.person.gpa) ;
printf ("%s %s %d %ld %f\n", ptr->FirstName, ptr->LastName,ptr->age, ptr->person.id,
ptr->person.gpa) ;
An Example - Assignment
//Create a struct but don’t reserve space
struct personal
{
long id; // student ID
float gpa; // grade point average
};
struct identity
{
char FirstName[30];
char LastName[30];
unsigned age;
struct personal person;
};
struct identity js = {"Joe", "Smith", 25}, oj ;
js.person.id = 123456789 ;
js.person.gpa = 3.4 ;
oj = js;
printf ("%s %s %d %ld %f\n", oj.FirstName, oj.LastName, oj.age, js.person.id, oj.person.gpa) ;
printf ("%s %s %d %ld %f\n", ptr->FirstName, ptr->LastName,ptr->age, ptr->person.id,
ptr->person.gpa) ;
Arrays of Structures
struct identity sharifC40153[80] = {"omid", "Jafarinezhad", 14, 9140153, 20,
struct identity
//Create a struct but don’t reserve space
"Samad", "Shekarestani", 90, 2222222, 20} ;
{
struct personal
strcpy(sharifC40153[2].FirstName, "Khaje Nezam");
char FirstName[30];
{
strcpy(sharifC40153[2].LastName, "Shekarestani");
char LastName[30];
long id; // student ID
sharifC40153[2]. age = 100;
unsigned age;
float gpa; // grade point average
sharifC40153[2]. person.id = 11111111;
struct personal person;
};
sharifC40153[2]. person. gpa = 20;
} students[4];
FirstName
LastName
age
students[0]
omid
Jafarinezhad
Students[1]
Samad
students[2]
Khaje Nezam
students[3]
person
id
gpa
14
9140153
20
Shekarestani
90
2222222
20
Shekarestani
100
11111111
20
Pointers to Structures
Date create_date1(int month,
void create_date2(Date *d,
int day,
int month,
int year)
int day,
Pass-by-reference
{
int year)
Date d;
{
d->month = month;
d.month = month;
d->day
= day;
d.day
= day;
d->year = year;
d.year = year;
}
return (d);
}
Date today;
Copies date
today = create_date1(9, 4, 2008);
create_date2(&today, 9, 4, 2008);
Pointers to Structures
void create_date2(Date *d,
int month,
int day,
int year)
{
d->month = month;
d->day
= day;
d->year = year;
}
void foo(void)
{
Date today;
create_date2(&today, 9, 4, 2008);
}
0x30A8
year:
2008
0x30A4
day:
4
0x30A0
month:
9
0x3098
d:
0x1008
today.year:
2008
0x1004
today.day:
4
0x1000
today.month:
9
0x1000
Compression of Structures
• Structures may not be compared using
operators == and !=, because structure
members are not necessarily stored in
consecutive bytes of memory
struct a {
int a; // OK
int b;
};
struct a b, c;
b.a = 10;
b.b = 30;
c = b;
if(c == b) // Error
Enumeration
• Enumeration is a user-defined data type. It is defined using the
keyword enum and the syntax is:
enum tag_name {name_0, …, name_n} ;
• The tag_name is not used directly. The names in the braces are
symbolic constants that take on integer values from zero through n.
As an example, the statement:
enum colors { red, yellow, green } ;
– creates three constants. red is assigned the value 0, yellow is assigned 1 and
green is assigned 2
Enumeration
• Values in an enum start with 0, unless specified otherwise, and are
incremented by 1
• The identifiers in an enumeration must be unique
• The value of each enumeration constant of an enumeration can be
set explicitly in the definition by assigning a value to the identifier
• Multiple members of an enumeration can have the same constant
value
• Assigning a value to an enumeration constant after it has been
defined is a syntax error
• Use only uppercase letters enumeration constant names. This
makes these constants stand out in a program and reminds you that
enumeration constants are not variables
An Example
/* enumeration constants represent months of the year */
enum months {JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
enum months month;
/* initialize array of pointers */
const char *monthName[] = { "", "January", "February", "March",
"April", "May", "June", "July", "August", "September", "October",
/* loop through months */
for (month = JAN; month <= DEC; month++ )
{
printf( "%2d%11s\n", month, monthName[month] );
}
Unions
• A union is a derived data type—like a structure—with
members that share the same storage space
• For different situations in a program, some variables may
not be relevant, but other variables are—so a union shares
the space instead of wasting storage on variables that are
not being used
• The members of a union can be of any data type
• The number of bytes used to store a union must be at least
enough to hold the largest member
• Only one member, and thus one data type, can be
referenced at a time
Unions representation
union myDataUnion {
int
i;
char c;
float f;
} u1, u2;
union myDataUnion u3;
u1.i = 4;
u1.c = ’a’;
u2.i = 0xDEADBEEF;
c
i
f
Unions
• The operations that can be performed on a union
are the following:
– assigning a union to another union of the same type
– taking the address (&) of a union variable
– accessing union members using the structure member
operator and the structure pointer operator
• Unions may not be compared using operators ==
and != for the same reasons that structures
cannot be compared
Unions
• In a declaration, a union may be initialized
with a value of the same type as the first
union member
union a
{
int a; // OK
char b[4];
};
union a b = {10};
printf("%d", b.a);
Unions
• A union value doesn’t "know" which case it contains
union AnElt {
int i;
char c;
} elt1, elt2;
elt1.i = 4;
elt2.c = ’a’;
elt2.i = 0xDEADBEEF;
if (elt1 currently has a char) …
How should your program keep track whether
elt1, elt2 hold an int or a char?
Basic answer: Another variable holds that info
Tagged Unions
• Tag every value with its case
enum Union_Tag {IS_INT, IS_CHAR};
struct TaggedUnion {
enum Union_Tag tag;
union {
int
i;
char c;
} data;
};
Enum must be external to struct,
so constants are globally visible
Struct field must be named
Bit-field Structures
• C enables you to specify the number of bits in which an
unsigned or int member of a structure or union is stored
• This is referred to as a bit field
• Bit fields enable better memory utilization by storing data
in the minimum number of bits required
• Bit field members must be declared as int or unsigned
• A bit field is declared by following an unsigned or int
member name with a colon (:) and an integer constant
representing the width of the field (i.e., the number of bits
in which the member is stored)
Bit-field Structures
• Notice that bit field members of structures are
accessed exactly as any other structure member
struct Flags
{
int
unsigned int
unsigned int
} foo;
foo.f1 = -2;
foo.f2 = 1;
foo.f3 = 2;
f1:3;
f2:1;
f3:2;
f3
…8 bit …
…8 bit …
…8 bit …
…
…
1
f2
0
• Padded to be an integral number of words
– Placement is compiler-specific
1
f1
1
1
0
Unnamed Bit-field
struct example {
unsigned a : 13;
unsigned : 19;
unsigned b : 4;
};
• uses an unnamed 19-bit field as padding—nothing can be stored in
those 19 bits
• An unnamed bit field with a zero width is used to align the next bit
field on a new storage-unit boundary
• For example, the structure definition
struct example {
unsigned a : 13;
unsigned : 0;
unsigned b : 4;
};
uses an unnamed 0-bit field to skip the remaining bits (as many as
there are) of the storage unit in which a is stored and to align b on
the next storage-unit boundary
An Example - disk drive controller
• Frequently device controllers (e.g. disk drives)
and the operating system need to
communicate at a low level. Device controllers
contain several registers which may be packed
together in one integer
An Example - disk drive controller
struct DISK_REGISTER {
unsigned ready:1;
unsigned error_occured:1;
unsigned disk_spinning:1;
unsigned write_protect:1;
unsigned head_loaded:1;
unsigned error_code:8;
unsigned track:9;
unsigned sector:5;
unsigned command:5;
};
struct DISK_REGISTER *disk_reg = (struct DISK_REGISTER *) DISK_REGISTER_MEMORY;
/* Define sector and track to start read */
disk_reg->sector = new_sector;
disk_reg->track = new_track;
disk_reg->command = READ;
/* wait until operation done, ready will be true */
while ( ! disk_reg->ready ) ;
/* check for errors */
if (disk_reg->error_occured)
{ /* interrogate disk_reg->error_code for error type */
switch (disk_reg->error_code)
......
}
Download