- •Vasyl Yatskiv,
- •Content
- •Introduction
- •1. Theory
- •1.1. Arithmetic Operators
- •1.2. Relational Operators
- •1.3. Logical Operators
- •1.4. Increment/Decrement Operators
- •1.6. Conditional Operator
- •1.7. Comma Operator
- •1.5. Assignment Operator
- •1.8. The sizeof Operator
- •1.9. Operator Precedence
- •1.10. Simple Type Conversion
- •2. Lab Overview
- •3. Report Structure
- •4. Control Exercises
- •5. References
- •Lab #2. Control structures
- •1. Theory
- •1.1. Simple and Compound Statements
- •1.2. The if Statement
- •1.3. The switch Statement
- •1.4. The while Statement
- •1.5. The do Statement
- •1.6. The for Statement
- •1.7. The continue Statement
- •1.8. The break Statement
- •1.9. The goto Statement
- •1.10. The return Statement
- •2. Lab Overview
- •3. Report Structure
- •4. Control Exercises
- •5. References
- •1. Theory
- •1.1. A Simple Function
- •1.2. Parameters and Arguments
- •1.3. Global and Local Scope
- •1.4. Scope Operator
- •1.5. Symbolic Constants
- •1.6. Inline Functions
- •1.7. Recursion
- •1.8. Default Arguments
- •2. Lab Overview
- •3. Report Structure
- •4. Control Exercises
- •5. References
- •Lab #4. Arrays, pointers, references and dynamic variables
- •1. Theory
- •1.1 Arrays
- •1.2 Multidimensional Arrays
- •1.3 Pointers
- •1.4 Dynamic Memory
- •1.5 Pointer Arithmetic
- •1.6 References
- •2. Lab Overview
- •3. Report Structure
- •4. Control Exercises
- •5. References
- •Lab #5. Structures
- •1. Theory
- •1.1 Introducing Structures
- •1.2 Using a Structure in a Program
- •1.3 Program Notes
- •1.4 Other Structure Properties
- •1.5 Arrays of Structures
- •2. Lab Overview
- •3. Report Structure
- •4. Control Exercises
- •5. References
- •Lab #6. Strings
- •1. Theory
- •1.1. Introduction to Strings
- •1.2. Concatenating String Constants
- •1.3. Using Strings in an Array
- •1.4. Reading String Input a Line at a Time
- •1.5. Line-Oriented Input with gets()
- •1.6. Introducing the string Class
- •1.7. Assignment, Concatenation, and Appending
- •1.8. More string Class Operations
- •1.9. More on string Class I/o
- •2. Lab Overview
- •3. Report Structure
- •4. Control Questions
- •5. References
- •Annex a Report’s Title Page
- •From discipline “Algorithmization and Programming” Topic: _______________________________________________
1.6. Inline Functions
Suppose that a program frequently requires to find the absolute value of an integer quantity. For a value denoted by n, this may be expressed as:
(n > 0 ? n : -n)
However, instead of replicating this expression in many places in the program, it is better to define it as a function:
int Abs (int n) {
return n > 0 ? n : -n;
}
The function version has a number of advantages. First, it leads to a more readable program. Second, it is reusable. And third, it avoid undesirable side-effects when the argument is itself an expression with side-effects.
The disadvantage of the function version, however, is that its frequent use can lead to a considerable performance penalty due to the overheads associated with calling a function. For example, if Abs is used within a loop which is iterated thousands of times, then it will have an impact on performance. The overhead can be avoided by defining Abs as an inline function:
inline int Abs (int n) {
return n > 0 ? n : -n;
}
The effect of this is that when Abs is called, the compiler, instead of generating code to call Abs, expands and substitutes the body of Abs in place of the call. While essentially the same computation is performed, no function call is involved and hence no stack frame is allocated.
Because calls to an inline function are expanded, no trace of the function itself will be left in the compiled code. Therefore, if a function is defined inline in one file, it may not be available to other files. Consequently, inline functions are commonly placed in header files so that they can be shared. Generally, the use of inline should be restricted to simple, frequently used functions.
1.7. Recursion
A function which calls itself is said to be recursive. Recursion is a general programming technique applicable to problems which can be defined in terms of themselves. Take the factorial problem, for instance, which is defined as:
Factorial of 0 is 1.
Factorial of a positive number n is n times the factorial of n-1.
The second line clearly indicates that factorial is defined in terms of itself and hence can be expressed as a recursive function:
int Factorial (unsigned int n) {
return n == 0 ? 1 : n * Factorial(n-1);
}
For n set to 3, the Table below provides a trace of the calls to Factorial. The stack frames for these calls appear sequentially on the runtime stack, one after the other.
Call |
n |
n == 0 |
n * Factorial(n-1) |
Returns |
First |
3 |
0 |
3 * Factorial(2) |
6 |
Second |
2 |
0 |
2 * Factorial(1) |
2 |
Third |
1 |
0 |
1 * Factorial(0) |
1 |
Fourth |
0 |
1 |
|
1 |
A recursive function must have at least one termination condition which can be satisfied. Otherwise, the function will call itself indefinitely until the runtime stack overflows. The Factorial function, for example, has the termination condition n == 0 which, when satisfied, causes the recursive calls to fold back.
As a general rule, all recursive functions can be rewritten using iteration. For factorial, for example, an iterative version will be:
int Factorial (unsigned int n) {
int result = 1;
while (n > 0) result *= n--;
return result;
}
