C and C++ Learning Notes

Deep Copy & Copy Constructor

Default Copy Constructor

The compiler also creates a copy constructor if we don’t write our own copy constructor. Unlike the default constructor, the body of the copy constructor created by the compiler is not empty, it copies all data members of the passed object to the object which is being created.

Custom Copy Constructor

Custom copy constructor can be really useful when there’s an array in a class and we want to deep copy it when passing value into a function.

Syntax:

1
2
3
Class_name(const Class_name& object){
...
}

To change =, the assignment operator, into deep copy, we need to overload the = operator as well.

Syntax:

1
2
3
operator=(const Class_name& object){
...
}

Since the content of the copy function and the overloading of the = operator is pretty much the same, we can write a private helper function to do the code reuse.

1
2
3
4
5
6
7
8
9
10
void ClassName::copyFrom(const ClassName &object){
...
}
ClassName& ClassName::operator=(const ClassName &object){
copyFrom(object);
return *this;
}
ClassName::ClassName(const ClassName &object){
copyFrom(object);
}

Core dumped and Segmentation Fault

Docs

Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.”

extern keyword

Docs

The extern keyword is used implicitly for functions. But to let the variable in one file be seen by other file, you should use extern for that file explicitly.

static keyword

Docs

Function Pointer

Syntax:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// define a function as usual
int avg(int arr[], size_t size) {
...
}
// use: return_type (* function_name)(arg1_type, arg2_type, ...)
int get_stats(int arr[], size_t size, int (*foo)(int[], size_t)) {
... foo(arr, size); // calling as usual
...
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
cout << get_stats(arr, 5, avg) << endl;
}

Constructor and destructor

1
2
3
4
5
6
7
8
9
10
11
12
13
class SomeClass {
private:
int num;

public:
SomeClass()
: num(1) {}
SomeClass(int num)
: num(num) {}
~SomeClass(){
// destructor
}
};

Constant member function

reference

CMake

1
2
3
4
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_options(-lm)

target_link_libraries(theNameOfYourExecutable m)

Dynamic allocation

Use new to new things.

Use delete xx to delete single pointer.

Use delete[] xx to delete pointer array.

Use nullptr instead of NULL.

iomanip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <fstream>
#include <iomanip>
#include <iostream>
using namespace std;
int main() {
double num;
cin >> num;
// num *= num;
ofstream out("double_square.txt");
out << setfill('*') << left << fixed;
for (int i = 1; i <= 10; i++) {
out << setw(11) << setprecision(i - 1) << fixed << num << endl;
}
return 0;
}

Input in C++ until EOL with istringstream

Use istringstream to turn a string into a stream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string inFileName;
cin >> inFileName;
ifstream inFile(inFileName);
string operation;
while (!inFile.eof()) {
string line;
getline(inFile, line);
istringstream inputLine(line);
inputLine >> operation;
cout << operation << endl;
}
return 0;
}

A+B problem written with class, const member functions, and operator overloading:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class Number {
private:
int a;

public:
Number(int a)
: a(a) {}
int get() const {
return a;
}
Number operator+(const Number& b) {
return Number(get() + b.get());
}
};
int main() {
Number a(10), b(20);
cout << (a + b).get();
return 0;
}

How to judge EOF in C++

Use .eof()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
string inFileName;
cin >> inFileName;
ifstream inFile(inFileName);
string operation;
while (!inFile.eof()) {
inFile >> operation;
cout << operation << endl;
}
return 0;
}

Const member functions

To specify to the compiler that a given member function is safe to call on const objects, you can declare the function with the const keyword. This specifies that the function is a “read-only” function that does not modify the object on which it is called.

1
2
3
4
const string& Person ::getName() const {
return name; // Doesn ’t modify anything ; trying to modify a
// data member from here would be a syntax error
}

Static Members and Variables

Static data members of a class are also known as “class variables,” because there is only one unique value for all the objects of that class. Their content is not different from one object of this class to another.

For example, it may be used for a variable within a class that can contain a counter with the number of objects of the class that are currently allocated, as in the following example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
class CDummy {
public:
static int n;
CDummy() { ++n; }
~CDummy() { --n; }
};
int CDummy::n = 0;
int main() {
CDummy a;
CDummy b[5];
CDummy* c = new CDummy;
cout << a.n << "\n"; // prints out 7
delete c;
cout << CDummy ::n << "\n"; // prints out 6
return 0;
}

Operator overloading

Reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
class Number {
private:
int a;

public:
Number(int a)
: a(a) {}
// here const is needed to declare that this method will not change member variable because the following overloading uses const
int get() const {
return a;
}
};
Number operator+(const Number& a, const Number& b) {
Number res(a.get() + b.get());
return res;
}
// notice, if you are defining this operator inside a class and if the operator needs 2 arguments, you only need to write 1.
// This is because the first argument is the instance of the class calling the operator function.
int main() {
return 0;
}

STL vector

Reference

Useful method

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
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v(10, 3); // 10 elements with value 3
v.push_back(1);
v.pop_back();
cout << v.empty();
cout << v.size();
cout << v[4];
// use iterator to visit the elements
vector<int>::iterator i = v.begin();
while (i != v.end()) {
cout << *i;
i++;
}
// or use auto
for (auto j = v.begin(); j != v.end(); j++) {
cout << *j << " ";
}
for (auto k : v) { // k is every element in v
cout << k << " ";
}
// if you want to modify the vector, use reference
for (auto& k : v) {
k -= 1;
cout << k << " ";
}
return 0;
}

Modifiers:

  • assign() – It assigns new value to the vector elements by replacing old ones
  • push_back() – It push the elements into a vector from the back
  • pop_back() – It is used to pop or remove elements from a vector from the back.
  • insert() – It inserts new elements before the element at the specified position
  • erase() – It is used to remove elements from a container from the specified position or range.
    v1.erase(v1.begin()+1,v1.begin()+3) for example.
  • swap() – It is used to swap the contents of one vector with another vector of same type. Sizes may differ.
  • clear() – It is used to remove all the elements of the vector container
  • emplace() – It extends the container by inserting new element at position
  • emplace_back() – It is used to insert a new element into the vector container, the new element is added to the end of the vector
  • count(v.begin(),v.end(),val) count how many element in v is equal to val.
  • find(v.begin(),v.end(),val) return iterator pointing to the first element equal to val
  • unique(v.begin(),v.end()) return an iterator pointing to the element after that remove all consecutive duplicates. But the size of the vector will not shrink, so it needs to be done like this:
1
2
it=unique(v.begin(),v.end());
v.resize(distance(v.begin(),it));

To gain a true unique vector, sort the vector first. sort(v.begin(),v.end(),cmp)

Virtual function

Docs

A virtual function is a member function which is declared within a base class and is re-defined (overridden) by a derived class. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class’s version of the function.

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
// CPP program to illustrate
// concept of Virtual Functions
#include <iostream>
using namespace std;
class base {
public:
virtual void print() {
cout << "print base class\n";
}
void show() {
cout << "show base class\n";
}
};
class derived : public base {
public:
void print() {
cout << "print derived class\n";
}
void show() {
cout << "show derived class\n";
}
};
int main() {
base* bptr;
derived d;
bptr = &d;
// Virtual function, binded at runtime
bptr->print();
// Non-virtual function, binded at compile time
bptr->show();
return 0;
}

Output

1
2
print derived class
show base class

Reference and pointer are two things

Check out this page

Here’s a piece of example code:

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
#include <iostream>
using namespace std;
void zero_small(int*, int*);
void zero_small(int&, int&);
int main() {
int a = 1, b = 0;
cout << &a << endl;
zero_small(a, b);
return 0;
}
void zero_small(int& a, int& b) {
cout << &a << endl;
cout << "First input: " << a << endl;
cout << "Second input: " << b << endl;
if (a < b) {
a = 0;
} else if (a > b) {
b = 0;
}
cout << "First number: " << a << endl;
cout << "Second number: " << b << endl;
}
void zero_small(int* a, int* b) {
cout << "First input: " << *a << endl;
cout << "Second input: " << *b << endl;
if (*a < *b) {
*a = 0;
} else if (*a > *b) {
*b = 0;
}
cout << "First number: " << *a << endl;
cout << "Second number: " << *b << endl;
}

The output is:

1
2
3
4
5
6
0x2fc65ffadc              // notice that these two memory locations are the same
0x2fc65ffadc
First input: 1
Second input: 0
First number: 1
Second number: 0

File I/O in C++ with fstream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <fstream>
#include <string>
int main() {
std::ifstream in("in.txt");
/**
* or
* std::ifstream in;
* in.open("in.txt");
*/
int num;
in >> num;
std::ofstream out("out.txt");
out << num;
std::string s;
std::getline(in, s);
return 0;
}

How to comment a custom function

Example code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @brief Count the number of chess of the given type of disk
*
* @param board pointer to the board
* @param disk disk type to be counted
* @return number of disks having the same type as the input disk
*/
int countBoard(Board board, Disk disk) {
int cnt = 0;
for (int i = 0; i < BOARD_SIZE; ++i) {
for (int j = 0; j < BOARD_SIZE; ++j) {
cnt += (board[i][j] == disk);
}
}
return cnt;
}

How to use qsort()

Docs

example code:

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
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int compare_ints(const void* a, const void* b)
{
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;

if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;

// return (arg1 > arg2) - (arg1 < arg2); // possible shortcut
// return arg1 - arg2; // erroneous shortcut (fails if INT_MIN is present)
}

int main(void)
{
int ints[] = { -2, 99, 0, -743, 2, INT_MIN, 4 };
int size = sizeof ints / sizeof *ints;

qsort(ints, size, sizeof(int), compare_ints);

for (int i = 0; i < size; i++) {
printf("%d ", ints[i]);
}

printf("\n");
}

How to use fgets() to read until EOF

1
2
while (fgets(s, sizeof(s) / sizeof(char), stdin) != NULL){
}

How to convert string to double

Use command strtod()

Docs

How to deal with complex number in C

Include <complex.h>
Docs

Hear is a demo code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
include <stdio.h>
#include <complex.h>
#include <tgmath.h>

int main(void)
{
double complex z1 = I * I; // imaginary unit squared
printf("I * I = %.1f%+.1fi\n", creal(z1), cimag(z1));

double complex z2 = pow(I, 2); // imaginary unit squared
printf("pow(I, 2) = %.1f%+.1fi\n", creal(z2), cimag(z2));

double PI = acos(-1);
double complex z3 = exp(I * PI); // Euler's formula
printf("exp(I*PI) = %.1f%+.1fi\n", creal(z3), cimag(z3));

double complex z4 = 1+2*I, z5 = 1-2*I; // conjugates
printf("(1+2i)*(1-2i) = %.1f%+.1fi\n", creal(z4*z5), cimag(z4*z5));
}

Dynamic memory allocation

Docs for malloc
Docs for realloc

When using dynamic memory allocation, remember to time the size of the memory by sizeof(type)!!!!! This is true for all command: malloc, calloc, realloc, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>   
#include <stdlib.h>

int main(void)
{
int *p1 = malloc(4*sizeof(int)); // allocates enough for an array of 4 int
int *p2 = malloc(sizeof(int[4])); // same, naming the type directly
int *p3 = malloc(4*sizeof *p3); // same, without repeating the type name

if(p1) {
for(int n=0; n<4; ++n) // populate the array
p1[n] = n*n;
for(int n=0; n<4; ++n) // print it back out
printf("p1[%d] == %d\n", n, p1[n]);
}

free(p1);
free(p2);
free(p3);
}

How to concatenate two strings?

1
strResult=concat(s1,s2);

How to init a struct array

1
struct patientType patients[200] = {{.socialID = 0, .age = 0, .dayCnt = 0, .temperature = {0}, .isIn = 0}};

use {{}}

How to assign a char array to another

1
char* s = argv[1];

where argv is a 2-D char array whose every row represents a char array.