본문 바로가기
카테고리 없음

Some notes about C++

by SuldenLion 2023. 6. 7.
반응형

Youtube Brocode 참조

 

'\n' & endl

- '\n'     →    better performance

- endl   →    flush the output buffer

 

▷ string 

- Objects that represents a sequence of text

 

▷ const

- The const keyword specifies that a variable's value is constant tells the compiler to prevent anything from modifying it (read-only)

- Should use constant as often as possible only if I know that a variable is not going to be changed at all

- ex) const double PI = 3.141592;

 

> const parameter

- parameter that is effectively read-only

- code is more secure & conveys(전달) intent

- useful for references and pointers

 

▷ Namespace

- Provides a solution for preventing name conflicts in large projects.

- Each entity needs a unique name.

- A namespace allows for identically named entities as long as the namespaces are different.

#include <iostream>

namespace suldenlion {
    int x = 100;
}

void main() {
    int x = 10;
    
    std::cout << suldenlion::x;
}

- You can have different versions of the same variable as long as they're within a different namespace.

 

void main() {
    using namespace suldenlion;

    std::cout << x;
}

// using namespace 선언하면 x 앞에 scope resolution operator (::) 안써도 됨

 

▷ typedef 

- Reserved keyword used to create an additional name(alias) for another data type.

- New identifier for an existing type.

- Helps with readability and reduces typos(=오타).

 

#include <iostream>
#include <vector>
using namespace std;
#include <string>

typedef vector<pair<string, int>> pairList_t; // -> usually ends with underscore t for type
typedef string text_t;

void main() {
    pairList_t pairList;
    text_t name = "SuldenLion";
}

 

 

- Use when there is a clear benefit

- Replaced with 'using' (work better w/ templates)

#include <iostream>
#include <vector>
using namespace std;
#include <string>

//typedef vector<pair<string, int>> pairList_t; // -> usually ends with underscore t for type
//typedef string text_t;
using pairList_t = vector<pair<string, int>>;
using text_t = string; 
// (똑같이 동작한다 함) 왜 안되는겨

void main() {
    pairList_t pairList;
    text_t name = "SuldenLion";
}

- using keyword is more popular than typedef nowadays just because it's more suitable for templates 

 

▷ cout & cin

- cout : '<<' (insertion operator)

- cin : '>>' (extraction operator)

- getline(cin, string) : read line (include spaces)

- getline(cin >> ws, string) : add ws for any white spaces → This portion will eliminate any newline characters or any white spaces before any user input (쓰는 이유 : cin 쓰고 getline쓰면 '\n' 가 버퍼에 남아서 그러는 듯)

 

▷ Useful math related functions in C++

- std::max(x, y)

- std::min(x, y)

- pow(x, y)  #include <cmath> 해줘야됨

- sqrt(x)     ↗

- abs(x)

- round(x)

- ceil(x)

- floor(x)

 

▷ Ternary operator

- replacement to an if/else statement

condition ? expression1 : expression2;

 

Useful string methods in C++

- str.empty() : check str is empty or not

- str.clear()

- str.append("...");

- str.at(0) : Display character of specific index

- str.insert(0, "Lion")

- str.find("alcohol"); → This method will give the position of the "alcohol" (중복되면 중복된 위치 인덱스 모두 리턴하는가?)

- str.erase(0, 3) → Put begining index & ending index as parameter

 

▷ pseudo-random

- Not truly random (but close)

#include <iostream>

void main() 
{
    srand(time(NULL));
    
    int num = (rand() % 6) + 1;
    
    std::cout << num;
}

 

> Random number guessing game by using rand function

#include <iostream>
#include <ctime>

void main() 
{
    int num;
    int guess;
    int tries;

    srand(time(NULL));		 // srand(time(0))과 같은가?
    num = (rand() % 100) + 1;
    
    std::cout << "****** NUMBER GUESSING GAME ******\n";
    
    do {
        std::cout << "Enter a guess between (1-100): ";
        std::cin >> guess;
        tries++;
        
        if (guess > num) {
            std::cout << "Higher than answer\n";
        } else if (guess < num) {
            std::cout << "Lower than answer\n";
        } else {
            std::cout << "Correct! # of tries: " << tries << '\n';
        }
    } while (guess != num);
    
    std::cout << "**********************************\n";
    
    }
}

 

▷ C++ Banking program

#include <iostream>
using namespace std;
#include <iomanip> // There's a function here to set some precision for floating point numbers
// = Input Output Manipulator

void showBalance(double balance);
double deposit();
double withdraw(double balance);

void main() {
	double balance = 0;
	int choice = 0;
	
	do {
		cout << "******************\n";
		cout << "Enter your choice:\n";
		cout << "******************\n";
		cout << "1. Show balance\n";
		cout << "2. Deposit money\n";
		cout << "3. Withdraw money\n";
		cout << "4. Exit\n";
		cin >> choice;

		cin.clear(); // This will reset any error flags when the standard input fails
		fflush(stdin); // This is a function pass in standard input this will clear the input buffer -> flush 기능

		switch (choice) {
			case 1: {
				showBalance(balance);
				break;
			}
			case 2: {
				balance += deposit();
				showBalance(balance);
				break;
			}
			case 3: {
				balance -= withdraw(balance);
				showBalance(balance);
				break;
			}
			case 4: {
				cout << "Thanks for visiting!\n";
				break;
			}
			default : {
				cout << "Invalid choice\n";
			}
		}
	} while (choice != 4);

}

void showBalance(double balance) {
	cout << "Your balance is: " << setprecision(2) << fixed << balance << "₩\n"; // This will display our balance up to 2 decimal places after the decimal point
	// 강일 피셜 setprecision해두면 모든 실수형에 영향 줌. 해봤는데 double, float둘다 고정
	// 소수점 아래숫자 안보이지만 존재 -> setprecision(2)인 경우 0.99 있을때 0.005 두번 더하면 1됨
}

double deposit() {
	double amount = 0;
	
	cout << "Enter amount to be deposited: ";
	cin >> amount;

	if (amount > 0) return amount;

	cout << "That's not a valid amount\n";
	return 0;
}

double withdraw(double balance) {
	double amount = 0;

	cout << "Enter amount to be withdrawn: ";
	cin >> amount;

	if (amount > balance) {
		cout << "Insufficient funds\n";
		return 0;
	} else if (amount < 0) {
		cout << "That's not a valid amount\n";
		return 0;
	}

	return amount;
}

 

▷ C++ Rock-Scissors-Paper game

#include <iostream>
#include <ctime>
using namespace std;

char getUserChoice();
char getComputerChoice();
void showChoice(char choice);
void chooseWinner(char player, char computer);

void main() {
    char player;
    char computer;

    player = getUserChoice();
    cout << "Your choice: ";
    showChoice(player);

    computer = getComputerChoice();
    cout << "Computer's choice: ";
    showChoice(computer);

    chooseWinner(player, computer);
}

char getUserChoice() {
    char player;
    cout << "Rock-Scissors-Paper game!\n";

    do {
        cout << "Choose one of the following\n";
        cout << "*************************\n";
        cout << "'r' for Rock\n";
        cout << "'s' for Scissors\n";
        cout << "'p' for Paper\n";
        cin >> player;
    } while (player != 'r' && player != 's' && player != 'p');

    return player;
}

char getComputerChoice() {
    srand(time(0));

    int num = rand() % 3 + 1;

    switch (num) {
        case 1: return 'r';
        case 2: return 's';
        case 3: return 'p';
    } 
}
void showChoice(char choice) {
    switch (choice) {
        case 'r' : cout << "Rock\n";
            break;
        case 's' : cout << "Scissors\n";
            break;
        case 'p' : cout << "Paper\n";
            break;
    }
}

void chooseWinner(char player, char computer) {
    switch (player) {
        case 'r': 
            if (computer == 'r') {
                cout << "It's a tie!\n";
            } else if (computer == 's') {
                cout << "You win!\n";
            } else {
                cout << "You lose!\n";
            }
            break;
        case 's': 
            if (computer == 's') {
                cout << "It's a tie!\n";
            } else if (computer == 'p') {
                cout << "You win!\n";
            } else {
                cout << "You lose!\n";
            }
            break;
        case 'p': 
            if (computer == 'p') {
                cout << "It's a tie!\n";
            } else if (computer == 'r') {
                cout << "You win!\n";
            } else {
                cout << "You lose!\n";
            }
            break;
    }
}

 

 

> sizeof() : determines the size in bytes of a: variable, data type, class, objects, etc.

> fill() : Fills a range of elements with a specified value.

- fill(begin, end, value)

#include <iostream>
#include <string>
using namespace std;

void main() {
    string foods[50];

    fill(foods, foods + 50, "pizza");

    for (string food : foods) {
        cout << food << '\n';
    }
}

 

▷ C++ Quiz game

#include <iostream>
#include <string>
using namespace std;

void main() {
    string questions[] = {"1. What year was C++ created? ",
                            "2. Who invented C++? ",
                            "3. What is the predecessor of C++? ",
                            "4. Is the Earth flat?"};

    string options[][4] = {{"A. 1969", "B. 1975", "C. 1985", "D. 1989"},
                        {"A. Guido van Rossum", "B. Bjarne Stroustrup", "C. John Carmack", "D. Mark Zuckerburg"},
                        {"A. C", "B. C+", "C. C--", "D. B++"},
                        {"A. Yes", "B. No", "C. Sometimes", "D. What's Earth?"}};

    char answerKey[] = {'C', 'B', 'A', 'B'};
    int size = sizeof(questions)/sizeof(questions[0]);
    char guess;
    int score = 0;

    for (int i = 0; i < size; i++) {
        cout << "***********************\n";
        cout << questions[i] << '\n';
        cout << "***********************\n";

        for (int j = 0; j < sizeof(options[i])/sizeof(options[i][0]); j++) {
            cout << options[i][j] << '\n';
        }

        cin >> guess;
        guess = toupper(guess);

        if (guess == answerKey[i]) {
            cout << "CORRECT\n";
            score++;
        } else {
            cout << "WRONG!\n";
            cout << "Answer: " << answerKey[i] << '\n';
        }
    }

    cout << "***********************\n";
    cout << "        RESULTS        \n";
    cout << "***********************\n";
    cout << "Correct guesses: " << score << '\n';
    cout << "# of Questions: " << size << '\n';
    cout << "Score: " << (score/(double)size)*100 << "%\n";
}

 

> Memory address

- A location in memory where data is stored

- A memory address can accessed with '&' (address-of operator)

string name = "suldenlion";
cout << &name;

// output> 0xf595ffaa0  ->  hexadecimal address every time we run this program,
//                          that number is likely to change

 

> pass by value & pass by reference

#include <iostream>
#include <string>
using namespace std;

//void swap(string x, string y);
//     ↓
void swap(string &x, string &y);

void main() {
    string x = "SuldenLion";
    string y = "SuldenTiger";
    string tmp;

    swap(x, y); // -> This value weren't switched within my variables x and y even though 
                //	  we invoked this function. So why didn't it work well that's because
                //    normally when we pass a variable to a function we're passing by value
                //    when we invoke this function we're creating copies of the original values
                //    what we have now are two copies of the variable x and y. And all we're doing
                //	  is switching the two copies and not the original values so that's passed by value
                // -> If I need to change the original values of these variables I could instead pass
                //	  by reference, a reference as in a memory address, an address in your computer's
                //    memory where a value is located. 
}

/*void swap(string x, string y) {
	string tmp;
	tmp = x;
	x = y;
	y = tmp;
}*/

//     ↓

void swap(string &x, string &y) { // Prefix the address-of operator (ampersand)
    string tmp;
    tmp = x;
    x = y;
    y = tmp;
}

// We should use pass by reference as often as possible unless we have a reason to pass by value

 

Luhn Algorithm

① Double every second digit from right to left. If double number is 2 digits, split them

② Add all single digits from step ①

③ Add all odd numbered digits from right to left

④ Sum results from steps ② & ③

⑤ If step 4 is divisible by 10, # is valid

- 신용카드 번호, IMEI 번호, 주민번호 등이 유효한 값인지 간단히 검사하는 알고리즘

- mod10(모듈러스 10) 알고리즘이라고도 함

 

Luhn 알고리즘 설명

① 가장 오른쪽 숫자부터 시작해서 짝수번째에 해당하는 자릿수에 2를 곱함 (만약 2를 곱한 수가 9 이상일 경우 각각의 자릿수의 값을 더함)

② 가장 오른쪽 숫자부터 시작해서 홀수번째에 해당하는 숫자들은 그냥 그대로 둠

③ 모든 값을 더한 뒤 10으로 나눈 나머지가 0이면 유효한 값.

 

다음과 같은 카드가 있을 때 Luhn 알고리즘으로 유효성 체크를 해보겠다 ↓

 

 모든 값들을 더하고 10으로 나누었을 때 0 이면 유효한 카드번호이다. (60/10=0)

- 좀 더 복잡한 유효성 체크를 원하면 Verhoeff algorithm과 Damm algorithm이 있다고 함.

#include <iostream>
#include <string>
using namespace std;

int getDigit(const int number);
int sumOddDigits(const string cardNumber);
int sumEvenDigits(const string cardNumber);

void main() {
	string cardNumber;
	int result = 0;

	cout << "Enter a credit card #: ";
	cin >> cardNumber;

	result = sumOddDigits(cardNumber) + sumEvenDigits(cardNumber);

	if (result % 10 == 0) {
		cout << cardNumber << " is valid\n";
	} else {
		cout << cardNumber << " is not valid\n";
	}
}

int getDigit(const int number) {
	return number % 10 + (number / 10 % 10);
}

int sumOddDigits(const string cardNumber) {
	int sum = 0;
	
	for (int i = cardNumber.size() - 1; i >= 0; i-=2) {
		sum += cardNumber[i] - '0';
	}
	
	//cout << "odd - " << sum << endl;

	return sum;
}

int sumEvenDigits(const string cardNumber) {
	int sum = 0;
	
	for (int i = cardNumber.size() - 2; i >= 0; i-=2) {
		sum += getDigit((cardNumber[i] - '0') * 2);
	}
	
	//cout << "even - " << sum << endl;

	return sum;
}

 

 

> string find()와 string::npos

- find() 함수는 해당 문자열의 시작 위치를 반환. 문자열을 찾았다면 그 위치에서 문자열의 크기만큼 더해준 위치에서부터 다시 해당 문자열을 탐색함.

#include <string>
#include <vector>

using namespace std;

int solution(string str1, string str2) {
    int answer = str2.find(str1);
    
    // string::npos는 -1값을 가지는 상수로 find() 함수 수행시 찾는 문자열이 없을때 반환됨
    if (answer != string::npos) answer = 1;
    else answer = 0;
    
    return answer;
}

 

Pointers

- variables that stores a memory address of another variable

- sometimes it's easier to work with an address

> & = address-of operator

> * = dereference operator

#include <iostream>
#include <string>
using namespace std;

void main() {
    string name = "SuldenLion"; // to create pointer it should be of the same data type 
                                // as the variable it's pointing to
    string *pName = &name;

    cout << pName << endl;      // output> 0xb83... 
                                // pointer contains a memory address as its value 
                                // to access the value at this address you would use dereference operator

    cout << *pName << endl;     // output> SuldenLion 
                                // By using *, it's accessing the value of that address that's stored 
                                // within this pointer which contains name 

    int age = 21;
    int *pAge = &age;

    string freePizzas[5] = {"pizza1", "pizza2", "pizza3", "pizza4", "pizza5"};
    //string *pFreePizzas = &freePizzas; // (x) -> this array is already an address
    string *pFreePizzas = freePizzas; // don't need to use & operator

    cout << freePizzas << '\n';  // output> ox4a...
    cout << *freePizzas << '\n'; // output> pizza1
}

 

> Null pointer

- Null value = a special value that means something has no value. When a pointer is holding a null value, that pointer is not pointing at anything (null pointer)

- nullptr = keyword represents a null pointer literal

- nullptrs are helpful when determining if an address was successfully assigned to a pointer

int *pointer = nullptr;

 

> Dynamic memory

- Memory that is allocated after the program is already compiled & running

- Use the 'new' operator to allocate 

- memory in the heap rather than the stack

- Useful when we don't know how much memory we will need. Makes our programs more flexible, especially when accepting user input.

#include <iostream>
#include <string>
using namespace std;

void main() {
	int *pNum = NULL;

	pNum = new int;

	*pNum = 21;
	cout << "address: " << pNum << '\n';
	cout << "value: " << *pNum << '\n';

	delete pNum; // freeing up the memory at this address -> to prevent a memory leak 

	char *pGrades = NULL;
	int size;

	cout << "How many grades to enter in? ";
	cin >> size;

	pGrades = new char[size];

	for (int i = 0; i < size; i++) {
		cout << "Enter grade #" << i+1 << ": ";
		cin >> pGrades[i];
	}

	for (int i = 0; i < size; i++) {
		cout << pGrades[i] << " ";
	}

	delete[] pGrades;
}

 

Recursion

- a programming technique where a function invokes itself from within

- break a complex concept into a repeatable single step

 

> (iterative vs recursive)

- advantages : Less code and is cleaner. Useful for sorting and searching algorithms

- disadvantages : Uses more memory. Slower.

 

▷ Function template

- describes what a function looks like . Can be used to generate as many overloaded functions as needed, each using different data types

#include <iostream>
#include <string>
using namespace std;

/*int max(int x, int y) {
	return (x > y) ? x : y;
}

double max(double x, double y) {
	return (x > y) ? x : y;
}

char max(char x, char y) {
	return (x > y) ? x : y;
}*/

/*template <typename T>
T max(T x, T y) {
	return (x > y) ? x : y;
}*/

template <typename T, typename U>
auto max(T x, U y) {     // using the auto keyword the compiler will deduce what the return type should be
	return (x > y) ? x : y;
}

void main() {
	/*cout << max(1, 2) << '\n';
	cout << max(1.1, 2.2) << '\n';
	cout << max('1', '2') << '\n';*/

	cout << max(1, '2') << '\n';

	// overloaded functions that each do the same thing.
	// the only difference is that they accept and return different data types
	// we could write one function that will accept any data type well
	// that's what function templates are
}

 

▷ Struct

- A structure that group related variables under one name

- structs can contain many different data types 

- variables in a struct are known as "members"

- members can be access with . "Class member access operator"

#include <iostream>
#include <string>
using namespace std;

struct student {
	string name;
	double gpa;
	bool enrolled;
}; // -> be sure semicolon at the end of struct

void main() {
	student student1;
	student1.name = "SuldenLion";
	student1.gpa = 3.5;
	student1.enrolled = true;
}

 

> How to pass structs as arguments?

#include <iostream>
#include <string>
using namespace std;

struct student {
	string name;
};

void printStudent(student s);

void main() {
	student s;
	s.name = "SuldenLion";

	cout << &s << endl;

	printStudent(s);
}

void printStudent(student s) {
	cout << &s << endl;
}

↳ These addresses are different when we pass the struct to a function, the function will create copy of it. (passed by value)

↳ If we need to work with the original struct we can use the '&' operator

 

#include <iostream>
#include <string>
using namespace std;

struct student {
	string name;
};

void printStudent(student &s);

void main() {
	student s;
	s.name = "SuldenLion";

	cout << &s << endl;

	printStudent(s);
}

void printStudent(student &s) {
	cout << &s << endl;
}

↳ These addresses are the same.

 

enums

- a user-defined data type that consists of paired named-integer constants.

- GREAT if you have a set of potential options

 

▷ Object

- A collection of attributes and methods 

- They can have characteristics and could perform actions

- Can be used to mimic real world items

- Created from a class which acts as a "blue-print"

#include <iostream>
#include <string>
using namespace std;

class Human {
public:
	string name;
	string occupation;
	int age;

	void eat() {
		cout << name << " is eating" << endl;
	}

	void drink() {
		cout << name << " is drinking" << endl;
	}

	void sleep() {
		cout << name << " is sleeping" << endl;
	}
};

void main() {
	Human human1;

	human1.name = "SuldenLion";
	human1.occupation = "scientist";
	human1.age = 17;

	cout << human1.name << endl;
	cout << human1.occupation << endl;
	cout << human1.age << endl;

	human1.drink();
}

 

▷ Constructor

- Special method that is automatically called when an object is instantiated useful for assigning values to attributes as arguments

#include <iostream>
#include <string>
using namespace std;

class Student {
public:
	string name;
	int age;
	int gpa;

	Student(string name, int age, int gpa) {
		this->name = name;
		this->age = age;
		this->gpa = gpa;
	}
};

void main() {
	Student s("SuldenLion", 20, 3.5);
}

 

> Constructor overloading

- multiple constuctors with the same name but different parameters

- they allow for varing(=changing) arguments when instantiating an object

 

Abstraction

- hiding unnecessary data from outside a class

- getter : function that makes a private attribute READABLE

- setter : function that makes a private attibute WRITEABLE

#include <iostream>
#include <string>
using namespace std;

class Stove {
private:
	int temperature;
public:
	Stove() {
		setTemperature(0);
	}
	Stove(int temperature) {
		setTemperature(temperature);
	}
	int getTemperature() {
		return temperature;
	}
	void setTemperature(int temperature) {
		if (temperature < 0) {
			this->temperature = 0;
		} else if (temperature >= 10) {
			this->temperature = 10;
		} else {
			this->temperature = temperature;
		}
	}
};

void main() {
	Stove stove;

	stove.setTemperature(100);

	cout << stove.getTemperature();
}

 

▷ Inheritance

- A class can receive attributes and methods from another class

- Children classes inherit from a Parent class

- Helps to reuse similar code found within multiple classes

 

반응형

댓글