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
댓글