-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_3_ProgramStructure.cpp
More file actions
1210 lines (1108 loc) · 57.6 KB
/
Copy path_3_ProgramStructure.cpp
File metadata and controls
1210 lines (1108 loc) · 57.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ===========================================================================
/// <summary>
/// _3_ProgramStructures.cpp
/// CplusPlus
/// created by Mehrdad Soleimanimajd on 09.05.2018
/// </summary>
/// <created>ʆϒʅ, 09.05.2018</created>
/// <changed>ʆϒʅ, 02.07.2023</changed>
// ===========================================================================
#include "CplusPlus.h"
#ifdef _WIN32
#include "Console.h"
#elif defined __APPLE__
#include "Terminal.h"
#endif
#define Tab '\t'
#define Nline '\n'
const char tab {'\t'};
const char nline {'\n'};
void _07_01_ControlStructures ()
{
try
{
ColourCouter (" -------------------------------------------------", F_bRED);
ColourCouter ("--------------------------------------------------\n\n", F_bRED);
//! ####################################################################
//! ~~~~~ control structures (statements and flow control):
// apart from linear sequence of statements a program can contain repeated segments of code, decision taking and bifurcations.
// generic (sub)statements required by most of the flow control statements in C++ as a part of their syntax are:
// either simple statements ended with semicolon (;)
// or a compound one which every single statement ends with its own semicolon (;) enclosed as a block in curly braces ({}). { statement1; statement2; ... }
// the entire block composed of sub-statements is considered a single statement.
ColourCouter ("~~~~~ Control structures (Statements and flow control):\n", F_bPURPLE);
ColourCouter ("A program can contain linear sequence of statements, repeated segments of code, decision taking and bifurcations.\n\n", F_YELLOW);
} catch (const std::exception&)
{
}
}
void _07_02_SelectionStatements ()
{
try
{
//! ####################################################################
//! ~~~~~ selection statements (if and else):
// execution of a statement or block if the condition is fulfilled.
//! keywords: if else
// Note syntax: if (condition) statement
ColourCouter ("~~~~~ Selection statements (if and else):\n", F_bPURPLE);
ColourCouter ("Can be used to introduce conditioned execution of statements.\n\n", F_YELLOW);
int x {99};
std::cout << "Current value of x is:" << tab << x << nline;
if ((x % 3) == 0)
std::cout << "Three is a devisor of x" << nline; // a statement
// a block statement without usual indentation and line breaks:
if (true) { std::cout << "x is "; std::cout << x << nline << nline; }
// Note syntax: if (condition) statement1 else statement2
// the introduced statement2 by 'else' keyword will be executed, when the condition is not fulfilled.
bool flag {false};
std::cout << "Current value of x is:" << tab << x << nline;
if (flag == true)
std::cout << "x divided by 3 is:" << tab << x / 3 << nline;
else // introduction of an alternative statement
std::cout << "x divided by 9 is:" << tab << x / 9 << nline << nline;
// concatenated several if + else structure
// for example it can be introduced to fulfil the intention of checking a range of values
x = 10;
std::cout << "Current value of x is:" << tab << x << nline;
if ((x % 3) == 0)
std::cout << "Three is a devisor of x" << nline << nline;
else
if ((x % 5) == 0) // alternative statement is concatenated with another if-else structure
std::cout << "Five is a devisor of x" << nline << nline;
else
std::cout << "The value of x is: " << x << nline << nline;
} catch (const std::exception&)
{
}
}
void _07_03_IterationStatements ()
{
try
{
//! ####################################################################
//! ~~~~~ iteration statements (loops):
// repetition of statements a certain times or till a condition is fulfilled.
//! keywords: while do for
ColourCouter ("~~~~~ Iteration statements (Loops):\n", F_bPURPLE);
ColourCouter ("To repeat statements a certain times or until a condition is fulfilled.\n\n", F_YELLOW);
//! ####################################################################
//! ----- the while loop:
// repeat the statement while the expression is true.
// alteration of the value must somehow happen in the statement to avoid looping forever in while loops
// Note syntax: while (expression) statement
// the complexity of the loop in the example below is trivial for computer,
// so it will be performed instantly without any practical delay
ColourCouter ("----- The while loop:\n", F_bPURPLE);
ColourCouter ("While the expression is true, this loop continue to iterate.\n\n", F_YELLOW);
std::cout << "Between numbers one to twenty, three is the divisors of (while loop):" << tab << "{ ";
int n {1};
while (n <= 20)
{
if ((n % 3) == 0)
{
std::cout << n << ' ';
std::this_thread::sleep_for (std::chrono::milliseconds (100)); // add delays for some dramatic effect! :)
}
++n; // alter the value checked in condition.
}
std::cout << "}" << nline << nline;
//! ####################################################################
//! ----- the do-while loop:
// the same behaviour like while loop but the condition will be checked after the execution of the statement.
// either if the condition is fulfilled or not, at least one execution of the statement is guaranteed.
// the use of do-while loop is preferred over the while loop,
// especially when the to be checked condition is determined within the statement itself.
// Note syntax: do statement while (condition);
ColourCouter ("----- The do-while loop:\n", F_bPURPLE);
ColourCouter ("Same behaviour like while loop, but with guarantee of one time statement execution.\n\n", F_YELLOW);
std::cout << "Between numbers one to ten, two is the divisors of (do-while loop):" << tab << "{ ";
int o {1};
do
{
if ((o % 2) == 0)
{
std::cout << o << ' ';
std::this_thread::sleep_for (std::chrono::milliseconds (100));
}
++o;
} while (o <= 10);
std::cout << "}" << nline << nline;
//! ####################################################################
//! ----- the for loop:
// iteration of the statement a certain number of times while its condition is true
// the initialization expression executes before the loop begins and the increase expression after each iteration,
// therefore this loop is most useful, when it comes to counter variables.
// Note syntax: for (initialization; condition; increase) statement;
ColourCouter ("----- The for loop:\n", F_bPURPLE);
ColourCouter ("To introduce loops that iterate a certain number of times.\n\n", F_YELLOW);
std::cout << "Between numbers one to ten, three is the divisors of (for loop):" << tab << "{ ";
for (int i {1}; i < 10; i++)
{
if ((i % 3) == 0)
{
std::cout << i << ' ';
std::this_thread::sleep_for (std::chrono::milliseconds (100));
}
}
std::cout << "}" << nline << nline;
//! - in addition:
// more on for loops plus some other features:
// the tree fields in the for loop are optional but the semicolons between them in all cases are obligatory.
//! for example: for (; n<10; ;) -equivalent to a while loop
//! another example: for (; n<10; ++n;) -maybe the variable is initialized before
// a loop with true as condition (no condition) is equivalent to an infinite loop
// each field will be executed in a particular time in the life cycle of a loop.
// these fields are expressions so they can use the comma operator, therefore a for loop can handle two counter variables at the same time.
// Note expressions are not statements so they can't be replaced by a block.
ColourCouter ("Features of for loops: multiple expressions as fields:\n", F_GREEN);
std::cout << nline << tab;
for (int i = 30, n = 0; n != i; n++, i -= 2)
{
std::cout << "^-^" << tab; // times of execution is 10
}
std::cout << nline << nline;
//! - in addition:
// example of nested for loops:
// Added to pattern: take note of repeated line and division in patterns
// * *
// * *
// * * 9 times
// *
// * *
// * *
ColourCouter ("Demonstration of a pattern using nested for loops:\n", F_GREEN);
bool flag {false};
for (int i = 1; i <= 5; i++)
{
if (i == 4 && flag == false) { i = 3; flag = true; } // repeat a line
for (int j = 1; j < 54; j++)
{
if ((i == (j % 6)) || (((i - 1) + (j % 6)) == 5)) // 6 to divide the patterns (try 5 too)
{
ColourCouter ("*", F_bPURPLE);
std::this_thread::sleep_for (std::chrono::milliseconds (20));
} else
std::cout << ' ';
}
std::cout << nline;
}
std::cout << nline;
//! ####################################################################
//! ----- range-based for loops: iteration over all the elements in a range
// Note syntax: for (declaration : range) statement;
// declaration declares a variable of a type which is able to take values of an element in the range.
// ranges are sequences of elements including arrays, containers and any other type supporting the functions begin and end.
// none of these types is mentioned yet, therefore stings will be used which are sequences of character.
// this kind of loop is automatic and doesn't require the explicit declaration of counter variable.
ColourCouter ("----- Rang-based for loops:\n", F_bPURPLE);
ColourCouter ("Iteration over all the elements in a range.\n\n", F_YELLOW);
std::string for_range {"SequenceOfCharacters"};
std::string temp {""};
std::cout << "The stored string in the variable is:" << tab << for_range << nline;
for (char c : for_range)
{
// each element in the range is passed through a selection statement using the variable c
if (c == 'e')
temp += c;
}
std::cout << "Reusing all 'e' characters in the sequence:" << tab << temp + "ROR! ^.^" << nline << nline;
// using type deduction (auto):
// to automatically deduct the type of elements in a range
ColourCouter ("Type deduction in range-based for loops:\n", F_GREEN);
std::string the_range {"*****"};
int count {1};
for (auto c : the_range)
{
for (int i = 0; i < count; i++)
{
std::cout << c;
std::this_thread::sleep_for (std::chrono::milliseconds (100));
}
std::cout << nline;
count++;
}
std::cout << nline;
} catch (const std::exception&)
{
}
}
void _07_04_JumpStatements ()
{
try
{
//! ####################################################################
//! ~~~~~ jump statements:
// they can be used to alter the flow of a program by jumping to specific locations
ColourCouter ("~~~~~ Jump statements:\n", F_bPURPLE);
ColourCouter ("The flow of a program can be altered by jumping to specific locations.\n\n", F_YELLOW);
//! ####################################################################
//! ----- the break statement:
// to leave a loop, even if its end condition isn't fulfilled.
// purposes: to end an infinite loop, to leave a loop before its natural end
ColourCouter ("----- The break statement:\n", F_bPURPLE);
ColourCouter ("To leave a loop before its natural end.\n\n", F_YELLOW);
std::cout << "Breaking the loop at word 'break':" << nline;
std::string another_range {"-loop-while-do-for-break-iterate-"};
std::cout << "The string is:" << tab << another_range << nline << nline;
std::string word {""};
int count {0};
for (auto c : another_range)
{
if (c == '-')
{
if (word == "break")
{
std::cout << tab << count << " neutral words are counted before 'break'." << nline << nline;
break;
}
if (word != "")
{
count++;
word = "";
}
} else
word += c;
}
//! ####################################################################
//! ----- the continue statement:
// to skip the current iteration and jumping to the next one.
ColourCouter ("----- The continue statement:\n", F_bPURPLE);
ColourCouter ("To introduce skipping the iterations of a loop.\n\n", F_YELLOW);
std::cout << "Continuing the loop at word 'break':" << nline;
std::string a_range {"-loop-while-do-for-break-iterate-"};
std::cout << "The string is:" << tab << a_range << nline << nline;
std::string a_word {""};
int counter {0};
for (auto c : a_range)
{
if (c == '-')
{
if (a_word == "break")
continue;
if (a_word != "")
{
counter++;
a_word = "";
}
} else
a_word += c;
}
std::cout << tab << "There are " << counter << " neutral words in string." << nline << nline;
//! ####################################################################
//! ----- the goto statement: provides absolute jump to another point in the program
// this jump is an unconditional jump, ignores the nesting levels and doesn't cause any automatic stack unwinding,
// therefore it is to be used with care, preferably within the same block and especially in the presence of local variables.
// defined labels which are valid identifier followed by colon (:), are destinations point and will be used as argument for goto statement.
// goto is deemed a low-level feature with no particular use in modern higher-level C++ programming paradigms.
ColourCouter ("----- The goto statement:\n", F_bPURPLE);
ColourCouter ("To introduce absolute and unconditional jump to another point in the program.\n\n", F_YELLOW);
std::cout << "Repeated smilies using goto statement:" << nline << tab;
int n {10};
a_loop_with_goto:
std::cout << "^,^" << tab;
--n;
std::this_thread::sleep_for (std::chrono::milliseconds (100));
if (n > 0) goto a_loop_with_goto;
std::cout << nline << nline;
} catch (const std::exception&)
{
}
}
void _07_05_AnotherSelectionStatement ()
{
try
{
//! ####################################################################
//! ~~~~~ another selection statement (switch):
// to compare the evaluated expression against labels that are constant expressions.
// it is like concatenations of 'if' and 'else if' statements but limited to constant expressions.
// it is not possible to use variables or ranges as labels since they aren't valid C++ constant expressions, therefore it is better to use 'if' for ranges and values that aren't constant.
// after evaluating the expression and finding the equivalent constant, its break statement causes the end of the switch.
// if the evaluation value isn't match to any of the constants, the default case and its group of statement when it is existed, will be executed since it is optional, .
// Note syntax: (type 'switch' and press tab key twice)
// switch (expression)
// {
// case constant1:
// group_of_statement1;
// break;
// .
// .
// default:
// group_of_default_statement;
// break;
// }
ColourCouter ("~~~~~ Another selection statement (switch):\n", F_bPURPLE);
ColourCouter ("Expressing a binary value (switch):\n\n", F_YELLOW);
std::string x {"1010110110"};
std::cout << "The binary number is:" << tab << x << nline << tab;
for (char c : x)
{
switch (c)
{
case 48: // ASCII code of zero
std::cout << "-Zero-";
break;
case 49: // ASCII code of one
std::cout << "-One-";
break;
default:
std::cout << "-Not zero or one-";
break;
}
}
std::cout << nline << nline;
//! - in addition:
// the syntax of switch is inherited from the early versions of C language. switch uses labels in place of blocks.
// the break statement for each case is needed, otherwise switch executes all the statements after the equivalent case till the end or reaching a break no matter what case they belong to.
// this makes enclosing a group statement in braces unnecessary,
// and can be useful for execution of same group of statement for more than one case.
ColourCouter ("Execution of same group of statement for more than one case.\n", F_GREEN);
int number {0};
unsigned short count {0};
std::string str_in;
std::cout << "Enter a number between 1 and 20:" << nline << tab << " -";
std::getline (std::cin, str_in);
std::stringstream (str_in) >> number;
for (int i = 1; i <= number; i++)
{
if (number % i == 0)
{
count++;
}
}
switch (count)
{
case 1:
case 2:
std::cout << number << " is a prime number." << nline << nline;
break;
case 3:
default:
std::cout << number << " is not a prime number and has " << count << " divisors." << nline << nline;
break;
}
} catch (const std::exception&)
{
}
}
int modulo (int a, int b)
{
int r; r = a % b; return r;
}
float division (int a, int b)
{
float r; r = static_cast<float> (a / b); return r;
}
void _08_01_Functions ()
{
try
{
ColourCouter (" -------------------------------------------------", F_bRED);
ColourCouter ("--------------------------------------------------\n\n", F_bRED);
//! ####################################################################
//! ~~~~~ functions:
// a group of code that is given a name to structure a program in segment of code to perform individual tasks,
// which can be called from some points of the program.
// Note most common syntax: type name (parameter1, ...) {statements}
// the parenthesis which differentiate functions from other kind of declarations or statements are always required no matter declaring or calling a function.
// parameters which allow passing arguments to the function act like local variables within the functions.
// the expression that calls a function, will be evaluated as the returned value by the function.
// all the functions that have defined return type in their definitions must return a value with a proper return statement that includes a return value, even if this value is never going to be used.
// a function can be called multiple times and its parameter aren't limited to literals.
ColourCouter ("~~~~~ Functions:\n", F_bPURPLE);
ColourCouter ("To introduce structures that can be used to perform individual tasks in segment of code.\n\n", F_YELLOW);
int r;
float result;
ColourCouter ("Two function to perform modulo and division operations:\n", F_GREEN);
std::cout << "Passed literal values as parameters:" << tab << "7 and 2" << nline;
r = modulo (7, 2); // passing literals
std::cout << "The result of modulo function:" << "\t\t" << r << nline;
std::cout << "Result (no additional variable):" << tab << modulo (7, 2) << nline << nline; // direct function calling in insertion stream
int x {4}; int y {3};
std::cout << "Passed variables as parameters:" << "\t\t" << "x = " << x << tab << "y = " << y << nline;
result = division (x, y); // passing variables
std::cout << "The result of subtraction function:" << tab << result << nline << nline;
ColourCouter ("Division function called as an operand of addition operation:\n", F_GREEN);
std::cout << "Passed variables as parameters:" << "\t\t" << "x = " << x << tab << "y = " << y << nline;
result = 6 + division (x, y); // the function call is operand of addition operation.
result = division (x, y) + 6; // same as above: commutative property of addition operation
std::cout << "The result of both expressions is:" << tab << result << nline << nline;
} catch (const std::exception&)
{
}
}
void interaction (void)
{
std::cout << "Hi, please tell me your name!\n\t-";
std::string str_in {""};
std::getline (std::cin, str_in);
std::cout << "\nHowdy " << str_in << ", I'm a Function. ^_^ \n\n";
}
void _08_02_VoidFunctions ()
{
try
{
//! ####################################################################
//! ----- functions with no type (the use of void):
// if the function doesn't need to return a value it shall be defined as a void function.
// the void type is an spacial type to represent the absence of value.
// void keyword can also be used in function's parameter list to explicitly specify that the function takes no actual parameters
// void keyword in parameter's list: in C++ optional, in C language required
ColourCouter ("----- Functions with no type (The use of void):\n", F_bPURPLE);
ColourCouter ("Void functions are those that don't have any returned value.\n\n", F_YELLOW);
std::cout << "Some interactions integrated in a void function with no parameters:" << nline << nline;
interaction ();
} catch (const std::exception&)
{
}
}
void _08_03_MainFunctionReturnValue ()
{
try
{
//! ####################################################################
//! ----- the return value of main function:
// the type of return value of main is int.
// if the execution of main ends normally without encountering the return statement,
// the compiler assumes that the function has ended with an implicit return statement.
// this only applies to the main function for historical reasons.
//! return statement: return 0;
// the returned zero value either implicitly or explicitly will be interpreted by the environment that the program ended successfully.
// returning other values are possible and some environment give access to them to the caller in some way,
// although this behaviour is not required nor necessarily portable between platforms.
// Note in some way guaranteed interpretable values on all platforms are:
// ----------------------------------------------------------------------
// 0 the program was successful
// ----------------------------------------------------------------------
// EXIT_SUCCESS the program was successful (the header is <cstdlib>)
// ----------------------------------------------------------------------
// EXIT_FAILURE the program failed (the header is <cstdlib>)
// ----------------------------------------------------------------------
// Note some authors consider the explicitly written return statement a good practice,
// thus the implicit return statement for main function is a tricky exception.
ColourCouter ("----- The return value of main function:\n", F_bPURPLE);
ColourCouter ("The return value of the main function which is of type int has his own peculiarity.\n\n", F_YELLOW);
ColourCouter ("Read the comments in the source code...\n\n", F_GREEN);
} catch (const std::exception&)
{
}
}
// ampersand signs '&' indicate, that the arguments are passed as reference
void square (int& d, int& e, int& f)
{
d *= d, e *= e, f *= f;
}
void _08_04_PassedArgumentsTypes ()
{
try
{
//! ####################################################################
//! ----- arguments passed by value and by reference:
//? by value:
// the values of arguments will be passed to function on the moment of the call, that is:
// the values will be copied into the variables represented by function parameters.
// the values of passed arguments will be used to initial the function parameters,
// thus the modification of them in function doesn't have any effect on the variables outside of it.
ColourCouter ("----- Arguments passed by value and by reference:\n", F_bPURPLE);
ColourCouter ("The Arguments can be passed to a function by value and by reference.\n\n", F_YELLOW);
int x {3}; int y {4};
int result {0};
ColourCouter ("Passing arguments by value:\n", F_GREEN);
std::cout << "The passed arguments are:" << tab << "x = " << x << tab << "y = " << y << nline;
result = modulo (x, y);
std::cout << "Result of modulo function:" << tab << result << nline << nline;
//? by reference:
// to gain access to variables defined outside of functions,
// and actually modifying their values passed to a function, arguments need to be passed by reference.
// to gain access to arguments, the function defines its parameters as reference.
// in C++ language, references are indicated by the ampersand sign '&' following the parameter type.
// what is passed is the variable itself,
// so somehow the association happens between the passed arguments and the parameters of the function to the extent,
// that the modification of arguments on their corresponding local variables within function is then possible,
// and in the end its reflection is on the variables passed as arguments.
ColourCouter ("Passing arguments by reference:\n", F_GREEN);
int a {2}; int b {3}; int c {4};
std::cout << "The passed arguments are:" << tab << "a = " << a << tab << "b = " << b << tab << "c = " << c << nline;
square (a, b, c);
std::cout << "Result (exponent two):" << "\t\t" << "a = " << a << tab << "b = " << b << tab << "c = " << c << nline << nline;
} catch (const std::exception&)
{
}
}
int search_ref (std::string& a, char& b)
{
int count {0};
if (b < 97)
b += 32;
for (auto c : a)
if (c == b)
count++;
return count;
}
// constant arguments passed as reference
int search_ref_const (const std::string& a, const char& b)
{
int count {0};
char temp {b}; // unmodifiable argument
if (b < 97)
temp += 32;
for (auto c : a)
if (c == temp)
count++;
return count;
}
void _08_05_Efficiency ()
{
try
{
//! ####################################################################
//! ----- efficiency consideration and constant reference:
// passing arguments by value causes the arguments to be copied which it may be relatively inexpensive for fundamental types like int,
// but in compound type it may result in certain overhead and copying large quantities of data just for function call.
// to avoid this unneeded copy, calling functions by reference is suggested and with it,
// the function operates directly on aliases of passed arguments and at utter most,
// it might mean the transfer of certain pointer to the function.
ColourCouter ("----- Efficiency consideration and constant reference:\n", F_bPURPLE);
ColourCouter ("Passing arguments by reference to avoid certain overhead.\n\n", F_YELLOW);
std::string line {"A line containing some word to be passed as argument by reference and searched within."};
char character;
int count;
std::cout << "Enter the character you are searching (A-Z):" << nline << "\t-";
std::cin >> character;
count = search_ref (line, character);
std::cout << nline << "\t" << count << " characters could be counted." << nline << nline;
//! - in addition:
// functions with reference parameters are generally perceived as functions that modify the arguments passed.
// by qualifying the parameters as constant, it can be guaranteed that the function doesn't modify the arguments
ColourCouter ("The use of constant parameters in passing arguments by reference:\n", F_GREEN);
std::cout << "Above entered character will be used:" << nline;
count = search_ref_const (line, character);
std::cout << nline << "\t" << count << " characters could be counted." << nline << nline;
} catch (const std::exception&)
{
}
}
inline int search_inline (const std::string& a, const char& b)
{
int count {0};
char temp {b};
if (b < 97)
temp += 32;
for (auto c : a)
if (c == temp)
count++;
return count;
}
void _08_06_InlineFunctions ()
{
try
{
//! ####################################################################
//! ----- inline functions:
// since calling a function has a certain overhead (stacking arguments, jumps etc...) it isn't efficient for short functions.
// by using inline specifier in the function declaration the compiler will be suggested that inline expansion is preferred over the usual function call mechanism.
// behaviour of a function won't be changed but the function body will be inserted at each point of the function call, so the regular invocation will be avoided.
ColourCouter ("----- Inline functions:\n", F_bPURPLE);
ColourCouter ("To introduce the inline expansion of a function body and replace the regular invocation with it.\n\n", F_YELLOW);
ColourCouter ("Search function with inline specifier declaration:\n", F_GREEN);
std::string line {"A line containing some word to be passed as argument by reference and searched within."};
char character;
int count;
std::cout << "Enter the character you are searching (A-Z):" << nline << "\t-";
std::cin >> character;
count = search_inline (line, character);
std::cout << nline << "\t" << count << " characters could be counted." << nline << nline;
// note that in C++ the optimization task is delegated to the compiler.
// most compiler already optimize code to generate inline functions whenever there is an opportunity, even not explicitly marked with inline specifier.
// Therefore using it in the declaration of a function is merely a suggestion and the compiler is free to not inline it and optimize otherwise, as long as the resulting behaviour is the one specified by the code.
} catch (const std::exception&)
{
}
}
// a default value in function's declaration (optional parameters)
long exponent (long a, int b = 2)
{
for (int i = 1; i <= b; i++)
a *= a;
return a;
}
void _08_07_ParametersDefaultValues ()
{
try
{
//! ####################################################################
//! ----- default values in parameters:
// optional parameters in C++ functions that doesn't require any arguments in the call shall have default values in the definition,
// which will be used when a function is needed to be called with fewer arguments.
ColourCouter ("----- Default values in Parameters:\n", F_bPURPLE);
ColourCouter ("To declare functions with optional parameters.\n\n", F_YELLOW);
std::cout << "Two call to exponent function with two parameters of which the last one is optional:" << nline;
long result;
result = exponent (12);
std::cout << "-- exponent (12):" << tab << result << nline;
result = exponent (10, 4); // optional parameter is used in the call, therefore the default value will be ignored
std::cout << "-- exponent (10, 4):" << tab << result << nline << nline;
} catch (const std::exception&)
{
}
}
void negative (int x); // function prototype
void positive (int x); // the same
void _08_08_FunctionsDeclaration ()
{
try
{
//! ####################################################################
//! ----- declaring functions:
// in C++ language, like identifiers, functions can not be used before declaration.
// in any case, at least the prototype of a function needs to be declared before any call to the function,
// which gives enough details about the types involved (return and parameters) in the function definition (function body).
// prototype syntax is like the one of a function's declaration without any body code which ends with semicolon.
// name of parameters are optional in the declaration, this means they can be mentioned or not,
// and when mentioned, not matching to the declaration of the function itself is also possible.
//? so two possible syntaxes are:
// Note int proto_function (int first, int second);
// Note int proto_function (int, int);
// name inclusion always improves the legibility of the declaration anyhow.
// the purposes of declaring functions before their actual definition:
// the order of functions becomes recognizable.
// possibility to call another function from within the already called function. (example below)
ColourCouter ("----- Declaring functions:\n", F_bPURPLE);
ColourCouter ("To introduce the declaration of a function and place its definition elsewhere.\n\n", F_YELLOW);
ColourCouter ("Working with the functions negative and positive:\n", F_GREEN);
int number;
std::cout << "Please enter an integer number:\t\t";
std::cin >> number;
negative (number);
} catch (const std::exception&)
{
}
}
void negative (int x)
{
if (x < 0) std::cout << "The entered number is negative.\n\n";
else positive (x);
}
void positive (int x)
{
if (x > 0) std::cout << "The entered number is positive.\n\n";
else negative (x);
}
long exponent (int a, int b)
{
if (b > 1)
return (a * exponent (a, b - 1));
else
return a;
}
void _08_09_Recursivity ()
{
try
{
//! ####################################################################
//! ----- recursivity:
// the property with which functions can call themselves.
// usual for some task like sorting elements or factorial (n!)
ColourCouter ("----- Recursivity:\n", F_bPURPLE);
ColourCouter ("The call that a function can make to itself.\n\n", F_YELLOW);
std::cout << "A recursive function to calculate exponent:" << nline;
int number {0}, power {0};
std::cout << "Please enter the number:\t\t";
std::cin >> number;
std::cout << "Please enter the exponent:\t\t";
std::cin >> power;
std::cout << "\t\t\t\t-- " << number << " ^ " << power << " = " << exponent (number, power) << nline << nline;
} catch (const std::exception&)
{
}
}
void _09_01_OverloadsAndTemplates ()
{
try
{
ColourCouter (" -------------------------------------------------", F_bRED);
ColourCouter ("--------------------------------------------------\n\n", F_bRED);
//! ####################################################################
//! ~~~~~ overloads and templates:
ColourCouter ("~~~~~ Overloads and templates:\n", F_bPURPLE);
ColourCouter ("-- Overloads are two or more functions with the same name.\n", F_YELLOW);
ColourCouter ("-- Defining a function with generic type is known as function template.\n\n", F_YELLOW);
} catch (const std::exception&)
{
}
}
int operation (int a, int b)
{
return (a % b);
}
// different declaration and definition
double operation (double a, double b)
{
if (a > b)
return a;
else
return b;
}
void _09_02_OverloadedFunctions ()
{
try
{
//! ####################################################################
//! ----- overloaded functions:
// in C++, two or more different functions can have the same name if their parameters are different (number, type).
// it isn't enough to have different return type to overload a function, hence at least one parameter must be different.
// by examining the type of the passed arguments the compiler distinguish which overload of a function shall be called.
// the example below is not generally a good idea to demonstrate overloads of a function, since similar behaviour of overloads is expected,
// on the other hand it shows the possibility that the overloads can be fully different.
// the functions in this example have entirely different behaviours, declarations and definitions and the only similarity is their name.
ColourCouter ("----- Overloaded functions:\n", F_bPURPLE);
ColourCouter ("C++ ability to define multiple instances of a function.\n\n", F_YELLOW);
ColourCouter ("Operations modulo and maximum performed by overloads of the function operation:\n", F_GREEN);
int number_1 {5}, number_2 {4};
double number_3 {2.4}, number_4 {3.7};
std::cout << "Passed numbers are:" << "\t\t" << number_1 << tab << number_2 << nline;
std::cout << "Result of overload modulo is:" << tab << operation (number_1, number_2) << nline;
std::cout << "Passed numbers are:" << "\t\t" << number_3 << tab << number_4 << nline;
std::cout << "Result of overload maximum is:" << tab << operation (number_3, number_4) << nline << nline;
} catch (const std::exception&)
{
}
}
int multiply (int m, int n)
{
return (m * n);
}
// different declaration with same definition
double multiply (double m, double n)
{
return (m * n);
}
// a generic sum function. the appropriate version of function will be instantiated and called by compiler each time.
template <class tType>
tType multiply_generic (tType m, tType n)
{
tType r;
r = (m * n);
return r;
}
// multiple template parameters
template <class tParamOne, class tParamTwo>
// the use of regular non-template type
bool minimum_check (tParamOne a, tParamTwo b)
{
return (a < b);
}
void _09_03_FunctionTemplates ()
{
try
{
//! ####################################################################
//! ----- function templates:
// a function (multiply for example) could be overloaded for many types and all of them having the same body or definition.
ColourCouter ("----- Function templates:\n", F_bPURPLE);
ColourCouter ("The ability of C++ to define generic functions known as function templates.\n\n", F_YELLOW);
ColourCouter ("A function could be overloaded for different types while all of them having the same definition:\n", F_GREEN);
std::cout << "Multiply 2 by 2 (overload for int type):" << tab << multiply (2, 2) << nline;
std::cout << "Multiply 0.3 by 0.3 (overload for double type):" << tab << multiply (0.3, 0.3) << nline << nline;
// for above case, C++ has the ability to define generic functions known as function templates.
// Note syntax: template <template-parameters> function-declaration
// it is like regular function, preceded with template keyword and a series of template parameters enclosed in angle-brackets <> and separated with comma
// the template parameters can be generic template types by specifying either the class or typename keyword (both are 100% synonym in template declaration) followed by an identifier.
// this identifier can then be used in the function definition like regular types. (see generic function multiply_generic)
// no matter how a generic type would be used (parameter, return or variable), it will be determined on the moment the template is instantiated.
// a template can be instantiated by applying it to create a function using particular types or values for its template parameters.
// the instantiation will be done when a template function called.
// call statement syntax is like function but the template arguments, enclosed in angle-brackets must be specified.
// Note syntax: name <tamplate-arguments> (function-arguments)
ColourCouter ("Multiple instances of a function (the use of generic function or function template):\n", F_GREEN);
int result1;
result1 = multiply_generic<int> (2, 2); // using int type to make an instance
std::cout << "Result of first instance (int type):" << "\t\t" << result1 << nline;
double result2;
result2 = multiply_generic<double> (0.3, 0.3); // making another instance with double type
std::cout << "Result of another instance (double type):" << tab << result2 << nline << nline;
//! - in addition:
// type deduction in generic types
// since the generic type SomeType is also used as parameters of the function, the compiler is able to deduce the data type automatically.
// therefore there is no need to explicitly specify the type within angle-brackets when calling the function.
// for this, the type shall be unambiguous so the compiler could perform the deduction.
// if the function is called with arguments of different types, the compiler may not be able to deduct the type of the generic type.
// take the following call for instance:
ColourCouter ("Instantiating another instance while using deduction of type:\n", F_GREEN);
std::cout << "Result of another instance (deduction):" << "\t\t" << multiply_generic (0.3, 0.3) << nline << nline;
//! - in addition:
// templates are a powerful and versatile feature.
// while they can have multiple template parameters, it is still possible for the function to use regular non-templated types.
// since numerical literals are always of a specific type, unless otherwise specified with a suffix.
// this means integer literals always produce values of type int and floating-point literals always produce values of type double.
// so there is no ambiguity possible in the example below.
ColourCouter ("Multiple template parameters plus using non-templated types:\n", F_GREEN);
if (minimum_check (10, 10.1)) // automatic template parameter deduction
std::cout << "The number 10 is smaller than 10.1" << nline << nline;
else
std::cout << "The number 10 is greater than 10.1" << nline << nline;
} catch (const std::exception&)
{
}
}
template <class tParam, int N>
tParam fixed_exponent (tParam val)
{
for (int i = 0; i < N; i++)
val *= val;
return val;
}
void _09_04_ParticularTypeTemplateArguments ()
{
try
{
//! ####################################################################
//! ----- particular type template arguments:
// the template parameter can also include expression of a particular type additionally to types introduced with class and typename.
// when a particular type is used, the parameter looks like regular function parameter and can actually be used just like one.
// the major difference:
// since template parameter's values are compile-time-determined, so different instantiations could be generated,
// the values of arguments of particular types are never passed during runtime.
// this means that every call to such a template generates a different version of the function template,
// therefore the values of argument of particular types need to be constant expressions and the template can not be instantiated with variables.
ColourCouter ("----- Particular type template arguments:\n", F_bPURPLE);
ColourCouter ("To introduce expressions of particular types as template parameter.\n\n", F_YELLOW);
ColourCouter ("A function template with parameter of particular type int:\n", F_GREEN);
int result;
result = fixed_exponent<int, 2> (2);
std::cout << "First instance (always square):" << "\t\t\t" << result << nline;
result = fixed_exponent<int, 3> (2);
std::cout << "Second instance (always exponent three):" << tab << result << nline << nline;
} catch (const std::exception&)
{
}
}
void _10_01_NameVisibility ()
{
try
{
ColourCouter (" -------------------------------------------------", F_bRED);
ColourCouter ("--------------------------------------------------\n\n", F_bRED);
//! ####################################################################
//! ~~~~~ name visibility:
// in C++ name entities such as variables, functions and compound types need to be declared before being used.
// the point where this declaration happens hat influence on its visibility.
ColourCouter ("~~~~~ Name Visibility\n", F_bPURPLE);
ColourCouter ("The visibility of name entities such as variables, functions and compound types can be different after declaration.\n", F_YELLOW);
ColourCouter ("The point where an entity is declared, influences its visibility.\n\n", F_YELLOW);
} catch (const std::exception&)
{
}
}
int global_variable {0}; // global scope from this point of code (not in other .cpp files)
int first_function ()
{
int local_variable {0}; // local scope within this block
local_variable = 10;
return local_variable;
}
int second_function ()
{
global_variable = 20;
int local_variable {0}; // no redefinition (another local variable)
local_variable = 30;
return local_variable;
}
void _10_02_Scopes ()
{
try