CPP

This is the notes for C++ learning.

QT Starter Recipe

In C++ we have two ways to create a new class object:

1
2
Student s;
Student *s2 = new Student("Alan");

In QT, we have a class called Qwideget, it also has a function called show, use this function can show a window.

1
2
Qwidget *w = new Qwidget();
w->show();

We can add a picture in this window:

1
2
TDWidget *w = new TDWidget("./image.png")
w->show()

Now, add a button:

1
2
QPushButton *btn = new QPushButton("Button", w);
btn->move(330, 450);

Now add a picture into the button:

1
2
TDPushButton *btn = new TDPushButton("./image2.png", w);
btn->move(330, 450);

Now we want to generate multiple buttons in the window:

1
2
3
4
5
6
for(int i=0; i<11; i++){
for(int j=0; j<6; j++){
TDMenuButton * btn = new TDMenuButton("./images.png");
btn->move(100+i*65, 100+j*85);
}
}

Hash Map

Ordered Map (Map)

The elements in the ordered map or we say the map, are sorted. In many cases we use the tree structure for this particular issue, such as binary trees.

1
# include <map>

Here we defined a hash map, the key is the audio_ID, and the value is the trans:

1
std::map<std::string, audioRecord> audioMap;

each time we need to add more one element, we use:

Here, the “audio_file_name” here are the keys.

1
2
3
4
5
audioMap[audio_file_name_1] = audioRecord {"audio_file_name_1", sr, bit_depth, dur};
audioMap[audio_file_name_2] = audioRecord {"audio_file_name_2", sr, bit_depth, dur};
audioMap[audio_file_name_3] = audioRecord {"audio_file_name_3", sr, bit_depth, dur};
...
audioMap[audio_file_name_n] = audioRecord {"audio_file_name_n", sr, bit_depth, dur};

Retreive the data for audio_file_name_3:

1
2
audioRecord& audio_file_name_3 = audioMap["audio_file_name_3"]
audio_file_name_3.sr;

So we can easily grap the value results of the “audio_file_name_3” sr.

Unordered Map

An unordered map is a hash table, it used the hash function to hash the key, and we can easily retreive the bucket we want. This is usually unordered and faster than the map.

1
# include <unordered_map>
1
std::unordered_map<std::string, audioRecord> audioMap;

Read a wav file and render it

Environmental Install

Intall SDL

https://gist.github.com/aaangeletakis/3187339a99f7786c25075d4d9c80fad5

Git clone the Tutorial Code

https://github.com/BennyQBD/AudioTutorial

Understand audio

https://www.ee.iitb.ac.in/course/~daplab/resources/

Introduction

Environment of C++

In windows there is the Visual C++

Linux: GCC : (the gcc in most cases are compiled for c, and g++ is for C++)

1
g++

/ Clang (Clang++)…

The IDE includes: Visual Studio / CodeLite / Code::blocks / Eclipse…

The usual tools included:

1
2
3
4
5
– /usr/bin/time
– valgrind
– cpp reference
– Compiler explorer
– C++ insights

The logic of the C++ is compling:

We can follow this simple solutionsource code >> processing >> excecutable programs, the problem is that it can takes a long time. And if there is little editing of the source code, and we have to re-compile it again.

The solution is to divide the source codes into multiple source codes like:

1
2
3
souce_file_1 (source file + headers) >> compile >> object files >> link >> 
excecutable programs
souce_file_2 (source file + headers) >> compile >> object files >> link >>

Now we can compile the C++ program more quickly, and easy to maintain. So the core steps can be compile and link. But here also comes with a question!!!

What if we used the same variable but in different C++ files, which may cause the collision, so we need to declare the definition of the variable. So the header files is to define the variables, it defines all the variables, if another c++ files need it, just borrow and declare it, which would be much more convinient. The initial way of using the header files can be declare the variables, but laterly it also includes some definitions.

But the golden rule still be if you declare one variable, you only can declare that variable once. If different c++ files want to refer to that variable, we just include it from the header files.

image-20220922212927648

Here is a “Hello world” example:

1st. C Preprocessor

1
2
3
4
5
6
7
8
#include <iostream>

int main()
{

std::cout << "Hello World";

}

Now we can do that preprocessing:

1
gcc -E ./main.cpp -o ./main.i

image-20220922220320102

The main.i file will include all the header files into our program and preprocess it.

2st. C Compile

The next step could be the C compiling. It will generate the compiled code.

1
g++ main.i -S -o main.s 

Now we can get the compiled code: main.s

image-20220922220153890

The main in here represents the main function we declared from the previous hello world program.

The call in here is to print the “hello world” message.

The use of the assembler is to use the compiled code into the machine code, that machine can read.

We will refer to the system link or other objects and put it together to get the runable program.

Direct Way

We can direct compile those steps in C++ just by one line of code:

1
g++ ./main.cpp -o ./main

Header Files

Preprocessing

Here is the step to convert the original file into the translated component.

ifdef

Ifdef is to solve the reference too deep problem, we can declare these codes in the header file:

1
2
3
4
#ifndef HEADER_NAME
#define HEADER_NAME

#endif

Or we can try pragma_once which can replace the same way like #ifndef:

1
#pragma once

We suggested to use the #pragma to avoid the collision between different header files.

Header Include

We need to include the header file:

#include “ .h”

If we are using “ “, the system will search the header file from the current directory. In most cases, we will use this way since its we wrote those header files.

#include <>

If we use <>, the system will search from the environment variable, or installed C++ packages, there is no “.h” ending.

System I/O lib

The input stream can be: cin, the output stream can be cout, cerr for error printing, clog for printing the log…

Compile

We will convert the interpreted units into the compiled languages:

Here is a good example:

https://godbolt.org/z/zh9aqx

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int res = 0;
for (int i = 0; i < 1000; ++i)
{
res += i;
}
return res;
}

// the res should be 1+...+999

Now here is the gcc compiling procedures: Here is the -O0 is to compile the codes without any other optimizations.

image-20220922223635463

But if we set like -O 3, which we will get the third level optimization:

image-20220922223756278

Hello World

Return 0

Every function it will define the return value except the return value like void or in main function.

So in here we will define a main function:

1
2
3
4
5
6
7
8
9
#include <iostream>

int cheer(const char* pInfo){
std::out << pInfo << std::endl;
}

int main(){
cheer("This is a good day");
}

So there maybe a warning like no return value, we need to add the return value:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int cheer(const char* pInfo){
std::out << pInfo << std::endl;
// return null value
return;
}

int main(){
cheer("This is a good day");
}

Also there is also no need to really declare a formal parameter totally if we do not want use that variable but still want to keep it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

int cheer(const char* pInfo, int){
std::out << pInfo << std::endl;
// return null value
return;
}

int main(){
cheer("This is a good day", 0);
return 0;
// number 0 is just the habit
// we can check by the echo $?
// if without declaring, the system will directly call it 0
}
function is the final running program,its like a general function. The return value of it is ```int```, and we usually use ```0``` to represent the return value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16



There are two forms of ```main``` function in C++:

```cpp
// This is the first type
int main(){
return 0;
}


// Here is the second type, it equals to main()
int main(int argc, char* argv[]){
return 0;
}

Namespace

If we need to avoid there are multiple functions with the same name, we can use the namespace to avoid the comflictions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

namespace NameSpace1
{
void fun()
{

}
}

namespace NameSpace2
{
void fun(){

}
}

int main(){
NameSpace2::fun();


}

Or we can do using namespace:

1
2
3
4
5
int main(){
// Now it will defaulty search the fun funtion from the NameSpace1
using namespace NameSpace1;
fun();
}

printf

In C++, we can use the std::cout or printf:

1
std::cout << "Hello World" << std::endl;

It can equals to :

1
2
#include <cstdio> // but it is not that quite standard and strict, so we import <cstdio> lib to refer the printf
printf("Hello World\n");

if

The essence of if is division like trees.

Here is the if in C++:

1
2
3
4
5
6
if (x == y){

}
else{

}

while

The essence of the while is recursion or loop.

Here is an example is guessing number:

1
2
3
4
5
6
7
8
9
int main(){
int x = 42;
int y = 0;
while (x != y){
std::cout << "Please input a number: \n";
// Cin here will be the user input
std::cin >> y;
}
}

image-20220924142713210

The logic here is that, if the user input is not equal to the x there, so the program will request you to input a number, else it will stop.

Struct

We can define the struct of multiple variables we want to call, especially for those variables who have inner connections.

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
#include <iostream>
#include <cstdio>

struct Point{
int x;
int y;
// the inside of the struct also can include functions
void IncX(){
x = x + 1;
}
}

void fun(Point p){
p.x;
p.y;
p.x = p.x + 1;
return x;
}

// So in this way, we can make the variables more friendly to call
int main(){
Point p;
// so we can call a struct name is "p"
p.x = 3;
p.y = 5;
p.IncX();
std::cout << p.x << " " << p.y << "\n";
}

Type and variables

C++ is a very strong language focused on the type of variables typically.

There are two steps to set a variable in C++:

Initialize

The first step to define a value can be:

1
2
int x = 10;
int y = 5;

Now the variable x can be created into a storage address, and pass the value into it.

Pass the value
1
x = y

The computer now will firstly find the address of the x, and change the value from that address [rbp-4] (-4 = 0xFFFFFFFFFFFFFFFC) into 10 (10 = 0xA). And the same idea is that y is correspond to [rbp-8 ] (-8 = 0xFFFFFFFFFFFFFFF8) whose the value is 5 = 0x5.

image-20220924160919422

Now the idea can be let y equals to x. The logic here is we firstly get the address of y which is [rbp-8] and pass the value under that address into eax, and pass the eax value into the address which is [rbp-4].

There is one notice is that, the C++ will sometimes convert the value for you if you misuse it, like in here the 10.5 is a double float number, but the C++ will let you to store that value only include the integer part which is the automatic setting of the C++.

image-20220924162242225

Pointer

Here we can firstly define a pointer, and the pointer address will point to a value.

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(){
int x = 42;
int y = 56;

int* p = &x;
// &x is to get the address from the variable,
// we can change the value of the pointer p the same as the address of y
p = &y;

// now we can get the value from refering the pointer p, the idea of int* p and *p is totally different
std::cout << *p << std::endl;
// the *p will be the value of x
}

image-20220924215057558

& is for getting the address. Pointer will also create a space in your computer, it will also can become an object. Pointer it is a procedure to point! Pointer can save the address.

We can also set the default pointer into null, like:

1
int *p = nullptr; // this is just a pre-set value, which means the address of it have not be clearly decided.

We can use pointer to save a lot of computing space, especially when we want to pass a relatively “big” value into the function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Str{
....
}

void fun(Str* param){
// we are setting the function params into the pointer, so we can just give that pointer an address, so we can easily manipulate it.

}


int main(){
Str x;
// now we pass the x's address to p
Str* p = &x;
fun(p);
}

Useful Linux Cmds

nm

We can use:

1
nm ./main.cpp.o | c++filt -t

It will print all the referred values or params when the program is compiled.


CPP
http://xiaos.site/2022/07/12/CPP/
Author
Xiao Zhang
Posted on
July 12, 2022
Licensed under