Top Banner
1 Nico Ludwig (@ersatzteilchen) (3) Basics of the C++ Programming Language
23

(3) cpp procedural programming

Jul 05, 2015

Download

Technology

Nico Ludwig

Check out these exercises: http://de.slideshare.net/nicolayludwig/3-cpp-procedural-programmingexercises

- Procedural Programming
- Predefined and User defined Functions
- Declaration and Definition of Functions
- Procedural and recursive Function Calling
- Namespaces and separated Function Definitions
- A Glimpse of Separated Compilation and Translation Units
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: (3) cpp procedural programming

1

Nico Ludwig (@ersatzteilchen)

(3) Basics of the C++ Programming Language

Page 2: (3) cpp procedural programming

2

TOC

● (3) Basics of the C++ Programming Language

– Procedural Programming

– Predefined and User defined Functions

– Declaration and Definition of Functions

– Procedural and recursive Function Calling

– Namespaces and separated Function Definitions

– A Glimpse of Separated Compilation and Translation Units

● Sources:

– Bruce Eckel, Thinking in C++ Vol I

– Bjarne Stroustrup, The C++ Programming Language

Page 3: (3) cpp procedural programming

3

Procedural Programming

● Imperative programming reaches its limits very soon.

– It is needed to repeat identical code parts all over in the program.

– If a repeated part contains a bug, this bug is present on all occurrences!

– We have to copy a code part to reuse it, or to share it with other developers.

– In general: Don't Repeat Yourself! DRY

– DRY in programming results in the the "Top-Down" approach.

● In engineering, complex problems are getting separated into smaller problems.

– In programming, problems are broken into procedures or functions.

– We call this the "Bottom-Up" approach, or functional decomposition.

● Procedural programming is all about the "Top-Down" and "Bottom-Up" notions.

– Top-Down: Programmers rework their code into functions to make it reusable.

– Bottom-Up: Programmers code new functions that solve subproblems.

● Procedural programming extends imperative programming with the concept of (reusable) functions.

Page 4: (3) cpp procedural programming

4

Procedural Programming in C/C++

● In C/C++, procedural programming is implemented with functions.

● A function is a part of code that can be called independently.

– Formerly known as "sub program".

– In C/C++ there is no difference between procedures and functions.

– In functions, statements can be executed imperatively.

– In functions, further functions can be called as well.

● This code style is rather verb-oriented: "do this" and "call that" etc.

● Procedural code in C/C++:

– Program execution starts in the function main(), from where other functions are being called.

– In fact coding functions is the central activity of C/C++ programmers!

● What is a procedure?

Page 5: (3) cpp procedural programming

5

Using predefined Functions in own Code

● The C/C++ standard library provides a plethora of functions for us.

– The C/C++ standards team already had their "Top-Down" specs on... :-)

– These functions allow reusing foreign code to solve own problems.

– E.g: std::pow(), std::qsort(), std::bsearch(), std::transform() etc.

– Some functions open the gate to the OS, like std::system().

● How to use functions from the standard library?

– #include the respective standard h-file, where the function declaration resides.

– (Optionally add a using directive for the namespace std.)

– Call the standard function within own code.

– (Mind to pass the lib file, where the functions' definition resides, to the linker.)

● "There is a problem with the usage of std::system()." What does this statement mean?● Well, std::system() accepts commands that are

highly platform-dependent in most cases.

Page 6: (3) cpp procedural programming

6

Declaration and Definition of Functions

int GetCount (int x, int y)

{ // A block of code (function body).

}return 42;

Type of returned value or void. Function name Parameter list

Function bodyReturn value from function.

int GetCount (int x, int y = 0);Declaration:

Definition:

C++11 – trailing return typeauto GetCount(int x, int y) -> int {

return 42;}

int (*)(int, int)

The signature of GetCount.

Default argument

Page 7: (3) cpp procedural programming

7

Features of Functions – Returning Values

● Functions can have a return type.

– When such a function is called, a value of type "return type" will be returned as a result of that function.

– This value can be stored (stuck into a variable) or otherwise consumed.

● Functions w/o return type are declared as returning void instead of a concrete type.

– Such functions don't have a result, but a persistent side effect in most cases.

● Functions, which only return values but have no side effects, are sometimes called pure functions.

● When a return statement in a function is executed (w/ or w/o returning a value) a function will be exited immediately!

// Store the returned value in a variable... (Mind that we have to write a pair of empty// parentheses, as GetDayOfMonth() accepts no parameters.):int day = GetDayOfMonth(); // …or use it in an expression:std::cout<<"The day is: "<<GetDayOfMonth()<<std::endl;// Finally the function can be called, ignoring the result: GetDayOfMonth();

// On calling ClearScreen(), the side effect happens, then ClearScreen() returns.ClearScreen(); // However, ClearScreen dos not return a value we could process!

// A function, which returns an int.int GetDayOfMonth() {

// pass}

// Clears the screen as side effect,// but doesn't return a value.void ClearScreen() {

// pass}

Page 8: (3) cpp procedural programming

8

Features of Functions – Parameters

● The return type, the parameter types and the order of parameters make up the signature of a function.

● Function definition and declaration can have an optional list of parameters (params).

– A parameter is a function's variable storing the value of the passed argument.

– A set of functions can have the same name, but differ in the signature's parameter list.

● This handy feature is what we call "function overloading".

– The last items of the parameter list can be prepared with default arguments or build a variable argument list.

● On calling a function a list of arguments will be passed to satisfy the params.

– If a function requires no parameters, an empty pair of parentheses is written.

– Order and type of the arguments must match to the parameters respectively.

● By this matching, the correct (overloaded) function will be found.

● A matching (overloaded) function is resolved at compile time!

– Parameters having a default argument, need not to be "satisfied".

– Arguments are passed by value by default, so parameters contain copies of the arguments.

● It is not possible to overload return types!● Btw. selecting function overloads at run time can

also be implemented in C++ with so called "multiple dispatch".

● What is the difference between arguments and parameters?● A parameter is nothing but a local variable that

contains the value of the respective argument. Or: an argument is the initial value of the respective parameter.

● The passed argument expressions are evaluated in an unpredictable order!

Page 9: (3) cpp procedural programming

9

Features of Functions – Calling Functions in a Nutshell

// No return type, no parameter list.void clearScreen() {

// pass}

// Call clearScreen() (mind the pair of empty parentheses), clearScreen() should// perform a side effect.clearScreen();

// No return type, awaits an int parameter.void checkAccount(int accountId) {

// pass}

// Call checkAccount(), pass 42 as argument.checkAccount(42);

// Returns int, awaits an int parameter. int getEntry(int entryID) {

// pass}

// Call getEntry(), pass 4 as argument, store the returned result in the variable theEntry.int theEntry = getEntry(4);

// Returns int, awaits two int parameters.int GetValue(int trackId, int index = 0) {

// pass}

// Call GetValue(), pass 7 (trackId) and then 7 (trackId) and 4 (index). Result ignored.GetValue(7); // The parameter index defaults to 0.GetValue(7, 4); // Both parameters are being satisfied.

Page 10: (3) cpp procedural programming

10

Functions are called – there is no Code Replacement

● A common misunderstanding: function call leads to "code replacement".

– This is not what's going on!

● The functions A() and B() do always exist, their code is not "merged" somehow.

● Functions are rather procedurally called in C/C++.

● (Code replacement can be achieved with macros in C/C++.)

int A() {return 2 + 3;

}

void B() {int result = A();std::cout<<result<<std::endl;

}

void B() {int result = 2 + 3; // No!std::cout<<result<<std::endl;

}NO!B() calls A()

● There is no code replacement going on, it would lead to code bloat, and thus bigger executables after compilation.

Page 11: (3) cpp procedural programming

11

Procedural Calling of Functions

● And again: functions can call other functions.

– When a function completes, execution returns to where the function was called from.

– "Top-level" functions call "lower-level" functions. So, there is a call hierarchy.

int main(int argc, char* argv[]) {double result = Square(3);

}

#include <cmath>

double Square(double arg) {return std::pow(arg, 2);

}

namespace std {double pow(double b, double exp) {

// calculate the powreturn value;

}}result = 9

(3)

(3, 2)

9

9

Page 12: (3) cpp procedural programming

12

Recursive Calling of Functions

● Some problems can be described as smaller instances of the same problem.

– In maths such descriptions are called recursive descriptions.

– For example the factorial function (1 x 2 x 3 x 4 … x n):

● Factorial can be expressed as a recursive function in C/C++.

– In maths, recursion means that a equation is defined in terms of itself.

– In programming, recursion means that a function calls itself.

● How to write a recursive function?

– A subproblem of the whole problem must be used as argument for recursive calls.

– And it is needed to consider the base case, when the recursion terminates!

– (The progression of the recursive calls must tend to the base case.)

– If we fail to consider one of these cases, we may end with an infinite recursion!

n!={1; n=0

n((n−1)!); n>0 n∈N

● Where to use the "factorial" function?● E.g. the factorial is used to calculate the count of

permutations of a set of elements.● Infinite recursions run as long as all the stack

memory of the executing thread is exhausted.

Page 13: (3) cpp procedural programming

13

Recursive Calling in Action

int main(int argc, char* argv[]) {int result = Factorial(3);

}

int Factorial(int n) {if (0 == n) {

return 1;} else {

return n * Factorial(n – 1);}

}

int Factorial(int n) {if (0 == n) {

return 1;} else {

return n * Factorial(n – 1);}

}

(3)(2)

62

int Factorial(int n) {if (0 == n) {

return 1;} else {

return n * Factorial(n – 1);}

}

(1)

1

int Factorial(int n) {if (0 == n) {

return 1;} else {

return n * Factorial(n – 1);}

}

(0)

1

0 == n

result = 6

● In the beginning, recursion is difficult to understand for most people. - They think about all the calls of a recursive function, in order to understand, if it is correct or not. They rather understand a function as a "machine" that processes inputs and returns outputs. → A better way to understand a function is that a function is a process. E.g. "process all documents and process all documents referred to in these documents".

Page 14: (3) cpp procedural programming

14

Various Implementations of the Factorial Algorithm

int FactorialRecursive(int n) {if (0 == n) {

return 1;} else {

return n * FactorialRecursive(n – 1);}

}int FactorialIterative(int n) {

int result = 1;for (int i = n; i > 0; --i) {

result *= i;}return result;

}int FactorialNiceRecursive(int n) {

return (0 == n)? 1: n * FactorialNiceRecursive(n - 1);

}

n!={1; n=0

n((n−1)!); n>0 n∈N

Page 15: (3) cpp procedural programming

15

Recursion and Recursive Functions in the Wild

● Useful to operate on recursive data. -> Data trees!

– E.g. a TreeView contains trees, that contain subtrees, that contain subtrees...

– Xml data is also a cascading tree of trees.

– Directory and file hierarchies.

– Network analyses, e.g. calculation of network efficiency and network load.

● Complex problems and puzzles can be solved easily with recursion.

– Maths: permutations of a set, numeric differentiation/integration

– Games: Towers of Hanoi, Sudoku, Chess puzzles etc.

● Definition of subproblems to be solved by multiple CPUs independently.

– The idea is to use CPU resources most efficiently -> Divide and conquer!

– Filters in graphics programming.

– Data analyses in networks and databases.

Page 16: (3) cpp procedural programming

16

Organizing Functions in Namespaces

● So far all user defined functions we saw, were defined as global functions.

● Global functions may clash with equally named/typed other functions.

– The functions of the standard library reside in the namespace std to prevent this.

● Also do namespaces group free functions semantically.

– It turns out, that all free functions should reside in namespaces!

– Don't define global functions (save main()), use namespaces instead!

● C++ namespaces can be understood as directories and functions as files.

– In a file system directories do contain files.

– Files with the same name can reside in different directories. -> No clash!

● Let's examine how to define and use namespaces with the function Factorial()...

● What's a free function?● And what is its opposite?

Page 17: (3) cpp procedural programming

17

// Function Factorial in the namespace Nico:namespace Nico {

int Factorial(int n) {return (0 == n)

? 1: n * Factorial(n - 1);

}}

Defining and using Namespaces in Code

// 1. Alternative: Qualify the function name// with the namespace's name:int main(int arc, char* argv[]) {

int result = Nico::Factorial(3);return EXIT_SUCCESS;

}

// 2. Alternative: Make all functions// in the namespace Nico global: with a// using directive:using namespace Nico;int main(int arc, char* argv[]) {

int result = Factorial(3);return EXIT_SUCCESS;

}

// 3. Alternative: Make only functions// named Nico::Factorial global: with// a using declaration:using Nico::Factorial;int main(int arc, char* argv[]) {

int result = Factorial(3);return EXIT_SUCCESS;

}

● Mind that namespaces allow us to have any other function named Factorial() residing in any other namespace than Nico; they will not clash with Nico::Factorial()!

Page 18: (3) cpp procedural programming

18

Separated Function Definitions

● Related functions should be implemented in separate code files. - Why that?

– Each developer can manage just his functions, not interfering with others'.

– On modification, just the separately modified code files must be compiled.

– Very important: The implemented code can be hidden from its callers.

● Separate and collect function definitions. - What's to do?

– Collect related function definitions in own cpp/c-files (summarized "c-files", these are the code files).

– Create h-files with function declarations for the functions in the c-files respectively.

– These "matching" h- and c-files should have the same name.

● The file names should not contain whitespaces or special characters (like umlauts).

– As C/C++ convention, #include the h-files into the belonging cpp/c-files.

● Calling the separated functions. - What's to do?

– In our top-level code file, we've to #include the h-files declaring the functions we need.

– In the code we can call the functions, because the declarations are visible.

● So far the calling side of functions are discussed. But what's about the function definitions? Where do they reside? => Now we'll inspect translation units.

Page 19: (3) cpp procedural programming

19

Documentation of Function Declarations

● The separation of function declaration and definition leads to information loss.

– In some sense this was the aim (callers should not see the definitions).

– But the mere function declaration is very opaque to us.

● How to improve the situation?

– Self description: Choose meaningful function and parameter names.

– Add documentation/usage comments to function declarations.

// numeric.hnamespace Nico {

/// Calculates the factorial./// @param arg – the positive value to calculate the factorial from./// @return – the factorial result.int Factorial(int arg);

}

Page 20: (3) cpp procedural programming

20

Creation of the Translation Unit by the Preprocessor

// numeric.hnamespace Nico {

/// Calculates the factorial./// @param arg – the positive value/// to calculate the factorial from./// @return – the factorial result.int Factorial(int arg);

}

// Main.cpp#include "numeric.h"int main(int arc, char* argv[]) {

int result = Nico::Factorial(3);return EXIT_SUCCESS;

}

// Main.cpp tunamespace Nico {

int Factorial(int arg);}

int main(int arc, char* argv[]) {int result = Nico::Factorial(3);return EXIT_SUCCESS;

}// numeric.cpp#include "numeric.h"

namespace Nico {int Factorial(int n) {

return (0 == n)? 1: n * Factorial(n - 1);

}}

Page 21: (3) cpp procedural programming

21

Separated Compilation and Linkage

● The separated c-files with function definitions need to be compiled also!

– In simple projects, we'll only have one code file (with the definition of main()).

– But in multi-file-projects we need to tell the compiler to compile all!

– Also the linker has to link all the resulting object-files (o-files) to an executable.

● How to negotiate with the compiler and linker about multiple files?

– We can, however, compile all c-files separately, e.g. on the console.

– We can write a make file that defines the build-tasks for compiler and linker.

– => In the end it is recommended to use an IDE to define this stuff in a project.

● Ok! What does a project within an IDE do for us?

– In the project we'll just collect all the h/c-files (and other files) we require.

– The IDE project will be automatically updated, when we add/remove h/c-files.

– Compiler and linker will be automatically prepared to deal with all the project's files.

● What other kinds of files could be managed within a IDE project?● E.g. resource files like icons.

Page 22: (3) cpp procedural programming

22

Getting our Feet wet with IDE Projects and Functions

● Example – Decompose a problem:

– Often the function call std::system("pause") is used to wait for the user on console.

– Possibly this function call should be used by other programs as well.

– That solution is Windows only! It should be expressed by platform neutral means.

– Let us extract this into our own function the "Bottom-Up" way! → Call it Wait().

– We should put this new function into its own namespace!

– Implement with std::system("pause") and test it.

– Then implement it in a platform neutral fashion and test it again.

– => Decomposition complete!

● What does to function call std::system("pause") do (std::system() is declared in <cstdlib>)?

● Why is this solution Windows only?

Page 23: (3) cpp procedural programming

23

Thank you!