First publication date : 2020/03/26
You will discover the differences between C and C++ languages with these first exercises. No OOP for this !
From C to C++
"Hello world"
#include <iostream>
int main(int argc, char ** argv) {
for(int i=0; i< 120; ++i)
std::cout << "Hi guys ! " << std::endl;
return 0;
}
- Compile this small example with g++ (not
gcc
) - Add the compiler flags
-Wall -Wextra
- Get rid of warnings with anonymous parameters
<<
is called the insertion operator. You can read it as "put to".
Standard (keyboard) input
- Compile and execute the following program
- Display the answers
#include <iostream>
#include <string>
int main(int, char **) {
std::string first; // special type for characters strings
int age;
std::cout << "What is your first name ?" << std::endl;
std::cin >> first;
std::cout << "How old are you ?" << std::endl;
std::cin >> age ;
std::cout << "Hi "<< first << std::endl;
return 0;
}
>>
is called the extraction operator. You can read it as "get from".
std::string
is a type that represents the characters string in C++. You will NEVER AGAIN need to handle char *
(except in particular situations like a lecture for example).
Handling standard "objects" with the prefix std::
can be tedious.
One instruction can help
using namespace std;
ou using std::cout;
. Usually developers love the last one !
Arrays and constants
You can compile the following code in C or C++ (if you put aside the calls to std::cout
).
If you want to keep the display feature, you can use the printf
C function because any C++ program can call the C libraries. Only header files change : for example, stdlib.h
becomes cstdlib
.
#include <iostream>
using std::cout;
using std::endl;
/* The const keyword can be used to define the size of n static array */
/* no #define anymore */
const int SIZE = 10;
int main(int, char **) {
int tab[SIZE];
for (int i=0; i < SIZE; ++i) {
tab[i] = i %2;
cout << tab[i] << " ";
}
cout << endl;
return SIZE;
}
Function overloading
Put this code in a .c
file and compile with gcc
. Note the errors.
#include <stdio.h>
void display(int a) {
printf("%d", a);
}
void display(double a) {
printf("%lf", a);
}
int main(int, char **) {
display(1);
display(2.0);
return 0;
}
If the file is a .cpp
one and is compiled with gcc
OR if the .c
file is compiled with g++
, you won't have the error messages!
String
A specific note on strings is available.
Run the following code and look what is going on with the different versions of s
:
#include <iostream>
int main() {
char s[10];
// std::string s;
// char * s;
std::cin >> s;
std::cout << "#" << s << "#" << std::endl;
for (int i = 0; i< 10; ++i)
std::cout << "@" << s[i] << "@" << (int)s[i] << "@" << std::endl;
return 0;
}
References
First use
#include <iostream>
void function1(int a) {
a = 3;
}
void function2(int* p) {
*p = 5;
}
void function3(int& b) {
b = 7;
}
int main(int, char **) {
int a = 1;
std::cout << a << std::endl;
function1(a);
std::cout << a << std::endl;
function2(&a);
std::cout << a << std::endl;
function3(a);
std::cout << a << std::endl;
return 0;
}
But what happened ?
- When returning from
function1()
, nothing because the parameter is a copy as well. - the variable
a
is changed because we provide its address to the function2 (and it is properly dereferenced) - what we expect with "reference". The paramter has to be seen as an alias of the original variable (no copy).
More...
- Compile and execute the following program. Do you have what we expect ?
- What does happen if we gave the same name to the functions
function1()
andfunction2()
?
#include <iostream>
void function1(int a) {
std::cout << &a << std::endl;
}
void function2(int& a) {
std::cout << &a << std::endl;
}
int main(int, char **) {
int age = 2021-1983;
std::cout << age << std::endl;
std::cout << &age << std::endl;
function1(age);
std::cout << &age << std::endl;
function2(age);
std::cout << &age << std::endl;
return 0;
}
Variables swap
Try the following code:
int a = 3;
int b = a;
int& c = a;
std::cout << a << " " << b << " " << c << std::endl;
b = 4;
std::cout << a << " " << b << " " << c << std::endl;
c = 5;
std::cout << a << " " << b << " " << c << std::endl;
a = 6;
std::cout << a << " " << b << " " << c << std::endl;
Write a function that allows swapping parameters of int
type
- with pointers
- with references
Compare the ease to write and understand the different versions.
Introduction to valgrind
valgrind is a very handful tool to detect faulty programs during execution : you will notice context errors and memory allocation errors
Let's see this piece of code :
#include <iostream>
int main(int , char ** ) {
int i;
while (i<10) {}
std::cout << i << std::endl;
++i;
}
std::cout << "end of program" << std::endl;
return 0;
}
You can find the error by yourself but we will try it the valgrind way. Let's compile (do not forget the -g option):
$ g++ -Wall -Wextra -g valtest.cpp
$ ./a.out
The fun is that on some machines, it can work, on others it can crash. Let's try a first analysis:
$ valgrind ./a.out
and a more complete one:
$ valgrind --track-origins ./a.out
It is now pretty clear, isn't it ?
Simple dynamic memory allocation
Execute valgrind
on these two examples and correct them ! Here is the first:
int main(int, char**) {
int * p = new int;
*p = 3;
cout << *p << endl;
return 0;
}
Now, the second one:
int main(int, char**) {
const int SIZE = 500;
int * p = new int[SIZE];
for(auto i = 0; i< SIZE; ++i ) p[i] = i;
for(auto i = 0; i< SIZE; ++i ) cout << p[i] << endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10