C++

工具介紹

C++ 基本格式

#include <iostream>
using namespace std;
int main(){
    cout << "Hello Jinkela!\n";
    return 0;
}

函數庫

#include <iostream>
using namespace std;
int main(){
    cout << "Hello Jinkela!\n";
    return 0;
}

命名空間

#include <iostream>
using namespace std;
int main(){
    cout << "Hello Jinkela!\n";
    return 0;
}

cout

  • C++ 常用輸出工具
  • 把資訊印到螢幕上
  • #include <iostream>

程式碼

螢幕

a = 7122
b = 7122712271227122
c = Jinkela
d = 0.7122
7122Jinkela7122
#include <iostream>
using namespace std;
int main(){
    int a = 7122;
    long long b = 7122712271227122;
    char c[100] = "Jinkela";
    double d = 0.7122;
    
    cout << "a = " << a << '\n';
    cout << "b = " << b << endl;
    cout << "c = " << c << '\n';
    cout << "d = " << d << '\n';
    cout << a << c << 7122 << '\n';
    return 0;
}

endl

  • cout 專用的換行
  • 比賽來說建議用 '\n' 取代

cin

  • C++ 最常使用的輸入工具
  • 把你用鍵盤打的東西存到變數中
  • 以空白,換行當作分割
  • #include <iostream>

做個小實驗

#include <iostream>
using namespace std;
int main(){
    int a;
    long long b;
    char c[100];
    double d;
    
    cin >> a >> b >> c >> d;
    
    cout << "a = " << a << '\n';
    cout << "b = " << b << endl;
    cout << "c = " << c << '\n';
    cout << "d = " << d << '\n';
    cout << a << c << 7122 << '\n';
    return 0;
}

常見錯誤

#include <iostream>
using namespace std;
int main(){
    int a, b;
    cin << a, b; // 這樣編譯會過!!
    cout << a << ' ' << b << '\n';
    return 0;
}

輸入輸出加速

  • C++ 輸入輸出比C還要慢
  • 有一些手段可以加速
  • 但有一些限制
#include <iostream>
using namespace std;

int main(){
    // 在main開頭加上這兩行,debug時建議拿掉
    ios_base::sync_with_stdio(false); // 加了這行scanf/printf會壞掉
    cin.tie(0); // 加了這行就不要用 endl
    
    return 0;
}

C++ 字串

string

string

  • C++ 專用字串
  • 比C的char陣列好用
  • #include <string>

string 基本操作

#include <iostream>
#include <string>
using namespace std;
int main(){
    string a = "abc7122";
    cout << a.size() << ' ' << a << '\n';
    for(size_t i = 0; i < a.size(); ++i){
        a[i] = 'j';
    }
    cout << a << '\n';
    char c[100] = "Jinkela";
    a = c;
    cout << a << '\n';
    return 0;
}

string 加法

#include <iostream>
#include <string>
using namespace std;
int main(){
    string a = "aa";
    string b = "bb";
    a += b;
    cout << a << '\n';
    a += a + b;
    cout << a << '\n';
    a.pop_back();
    cout << a << '\n';
    return 0;
}

string 輸入

#include <iostream>
#include <string>
using namespace std;
int main(){
    string a, b;
    cin >> a >> b;
    cout << a + b << '\n';
    return 0;
}

string 比較: 字典序

#include <iostream>
#include <string>
using namespace std;
int cmp(string a, string b){
    size_t len = a.size() < b.size() ? a.size() : b.size();
    for (size_t i = 0; i < len; ++i){
        if(a[i] == b[i]) continue;
        return a[i] < b[i] ? -1 : 1;
    }
    if (a.size() == b.size()) return 0;
    return a.size() < b.size() ? -1 : 1;
}
int main(){
    string a, b;
    while(cin >> a >> b){
        cout << cmp(a, b);
        if (a < b) cout << " <\n"; // -1
        if (a == b) cout << " ==\n"; // 0
        if (a > b) cout << " >\n"; // 1
    }
    return 0;
}

string 轉成 c字元陣列

#include <cstdio>
// stdio.h
#include <string>
using namespace std;
int main(){
    string s = "aaa7122";
    printf("%s\n", s.c_str());
    return 0;
}

整行輸入

getling

getline

  • #include <iostream>
  • getline(cin, 變數(必須是string))
#include <iostream>
#include <string>
using namespace std;
int main(){
    string s;
    getline(cin, s);
    cout << s << '\n';
    return 0;
}

輸出輸入重導向

a.out的code

螢幕

小實驗

#include <iostream>
#include <string>
using namespace std;
int main(){
    cout << "Please input: ";
    string s;
    getline(cin, s);
    cout << "Your input: ";
    cout << s << '\n';
    return 0;
}
Please input: aaa ssss
Your input: aaa ssss

input.txt

螢幕

檔案輸入

Please input: 
Your input: aaa ssss
aaa ssss
  • ./a.out < input.txt

螢幕

output.txt

檔案輸出

Please input: 
Your input: GGGGGGG GGG
GGGGGGG GGG
  • ./a.out > output.txt

input.txt

output.txt

檔案輸入輸出

Please input: 
Your input: aaa ssss
aaa ssss
  • ./a.out < input.txt > output.txt

連續輸入

通常題目會這樣的描述

  • 輸入有多筆測資
  • 請輸入到EOF為止
  • (中英都要能看懂)

EOF (end of file)

  • 讀到檔案結束時會觸發EOF事件
  • cin , getline在遇到EOF時會回傳false
  • 用鍵盤輸入製造EOF
    • windows: Ctrl + Z
    • Linux: Ctrl + D

輸入範例

輸入有多筆。

每比第一行有一個數字\(n\),接下來有\(n\)行,每行有兩個浮點數x, y

適合的code

#include <iostream>
using namespace std;
int main(){
    int n;
    while(cin >> n){
        for(int i = 0; i < n; ++i){
            double x, y;
            cin >> x >> y;
        }
    }
    return 0;
}

從字串輸入

sscanf

stringstream

sscanf

  • #include <cstdio>
  • sscanf(字元陣列, 後面和 scanf 一樣)
  • 格式化輸入
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int main(){
    string s;
    getline(cin, s); // input: (123,456)
    int x, y;
    sscanf(s.c_str(), "(%d,%d)", &x, &y);
    cout << x << ' ' << y << '\n'; // output: 123 456
    return 0;
}

stringstream

  • #include <sstream>
  • 把字串作為輸入
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(){
    string str;
    getline(cin, str);
    stringstream ss(str);
    int a;
    while(ss >> a){
        cout << a << '\n';
    }
    return 0;
}

getchar()
scanf("%c")

初學者不建議使用(參閱例題)

double or float?

比賽時千萬不要用float

小實驗

#include <iostream>
using namespace std;
template<typename T>
void test(){
    T a = 1.0 / 81;
    T b = 0;
    for(int i = 0; i < 729; ++ i)
        b += a;
    cout << b << '\n'; // (729/81) = 9
}
int main(){
    test<float>(); // prints 9.00002
    test<double>(); // prints 9
    return 0;
}

double小數點輸出

  • 輸出到小數點後第k位(四捨五入)
  • #include <iomanip>
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
    int k = 3; // 輸出到小數點後第3位
    cout << fixed << setprecision(k);
    cout << 0.7122 << '\n';
    double pi = 3.14159265358979;
    cout << pi << ' ' << pi*pi << '\n';
    return 0;
}

C++ 特殊技巧

auto

  • auto變數定義時會自動判斷自己的型別
#include <iostream>
using namespace std;
string f(){
    return "Jinkela";
}
int main(){
    auto a = 7122; // int
    auto b = 2147483647122;// long long
    auto c = "7122"; // const char*
    auto d = f(); // string
    cout << a << ' ' << b << ' ' << c << '\n';
    cout << d << '\n';
    return 0;
}

錯誤用法

  • auto不是這樣用的
#include <iostream>
using namespace std;
int main(){
    auto a = 7122; // int
    a = 7123;
    a -= 1;
    a = "aaaaaa"; // error
    return 0;
}

Range-based for

  • for(型態 變數 : 範圍)
#include <iostream>
using namespace std;
int main(){
    for(int n : {1,2,3,4,5}){
        cout << n << ' ';
    }
    cout << '\n';
    
    int a[10] = {1,2,3,4,5};
    for(int n : a){
        cout << n << ' ';
    }
    cout << '\n';
    return 0;
}

reference(c++ 98)

  • C要做到同樣功能的話需要指標
#include <iostream>
using namespace std;
int main(){
    int a = 5;
    int &b = a;
    b += 1;
    cout << a << '\n';
    int c[10] = {1,2,3};
    for(auto &i : c){
    	i += 7122;
    }
    for(auto i : c){
    	cout << i << ' ';
    }
    cout << '\n';
    return 0;
}

常見錯誤

行尾空白

直接輸出在螢幕上看不出來

#include <iostream>
using namespace std;
int main(){
    int a[] = {1,2,3,4,5};
    for(int x : a){
        cout << x << ' ';
    }
    cout << '\n';
    return 0;
}

建議處理方式

#include <iostream>
using namespace std;
int main(){
    int a[] = {1,2,3,4,5};
    bool use = false;
    for(int x : a){
        if(use) cout << ' ';
        use = true;
        cout << x;
    }
    cout << '\n';
    return 0;
}

建議處理方式2

#include <iostream>
using namespace std;
int main(){
    int a[] = {1,2,3,4,5};
    for(int x : a){
        static bool use = false;
        if(use) cout << ' ';
        use = true;
        cout << x;
    }
    cout << '\n';
    return 0;
}

炫技處理方式

#include <iostream>
using namespace std;
int main(){
    int a[] = {1,2,3,4,5};
    for(int i = 0; i < 5; ++i){
        cout << a[i] << " \n"[i==4];
    }
    return 0;
}

萬能標頭黨

<bits/stdc++.h>

萬能標頭黨

  • 一口氣把所有常用的功能include
  • 解題時很好用(背起來),但開發大型專案時不要用
#include<bits/stdc++.h>
using namespace std;
int main(){
    int a;
    cin >> a;
    cout << a * a << '\n';
    scanf("%d", &a);
    printf("%d\n", max(a, 1));
    return 0;
}

例題

地圖翻轉問題

  • 給你一張由字元組成的地圖,請你將他翻轉
  • 輸入第一行有兩個數字\(n, m, (n,m\le 10^3)\)
    接下來有\(n\)行,每行有\(m\)個以空白隔開的字元,表示地圖
  • 請你將地圖翻轉後輸出

範例輸入

範例輸出

4 5
% A B C D
H K J L L
* 5 6 * 7
l s d / ?
% H * l
A K 5 s
B J 6 d
C L * /
D L 7 ?

answer (C)

#include <stdio.h>
char s[1005][1005];
int main(){
    int n,m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < m; ++j){
            char buff[2];
            scanf("%s", buff); //這裡用getchar或 %c 都容易壞掉
            s[i][j] = buff[0];
        }
    }
    for(int j = 0; j < m; ++j){
        for(int i = 0; i < n; ++i){
            if(i != 0) putchar(' ');
            printf("%c",s[i][j]);
        }
        puts("");
    }
    return 0;
}

answer (C++)

#include <bits/stdc++.h>
using namespace std;
char s[1005][1005];
int main(){
    int n,m;
    cin >> n >> m;
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < m; ++j){
            cin >> s[i][j];
        }
    }
    for(int j = 0; j < m; ++j){
        for(int i = 0; i < n; ++i){
            cout << s[i][j] << " \n"[i==n-1];
        }
    }
    return 0;
}

地圖翻轉問題2

  • 給你一張由字元組成的地圖,請你將他翻轉
  • 輸入第一行有兩個數字\(n, m, (n,m\le 10^3)\)
    接下來有\(n\)行,每行有\(m\)個字元,表示地圖
  • 請你將地圖翻轉後輸出

範例輸入

範例輸出

4 5
%ABCD
HKJLL
*56*7
lsd/?
%H*l
AK5s
BJ6d
CL*/
DL7?

answer (C)

#include <stdio.h>
char s[1005][1005];
int main(){
    int n,m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i){
        scanf("%s", s[i]);
    }
    for(int j = 0; j < m; ++j){
        for(int i = 0; i < n; ++i){
            printf("%c",s[i][j]);
        }
        puts("");
    }
    return 0;
}

answer (C++)

#include <bits/stdc++.h>
using namespace std;
char s[1005][1005];
int main(){
    int n,m;
    cin >> n >> m;
    for(int i = 0; i < n; ++i){
        cin >> s[i];
    }
    for(int j = 0; j < m; ++j){
        for(int i = 0; i < n; ++i){
            cout << s[i][j];
        }
        cout << '\n';
    }
    return 0;
}

進階字串反轉

  • 第一行有一個數字\(n, n\le 10^5\)
  • 接下來有\(n\)行,每行有一些以空白分隔的字串
  • 一行最多有\(10^5\)個字元
  • 對於每一行
    請你將這些字串反轉後去掉空白然後輸出

範例輸入

範例輸出

4
asdf dfgh adfgdfa fhgdf sfs dfsd
a_a b_b_ ccdd
abcd 1234 a1b2c3d4
jinkela Jinkela
fdsahgfdafdgfdafdghfsfsdsfd
abcda_a_b_bddcc
dcba43214d3c2b1a
aleknijalekniJ

answer(C++)

#include <bits/stdc++.h>
using namespace std;
int main(){
    string buff;
    getline(cin, buff);
    stringstream ss(buff);
    int n;
    ss >> n; // 直接用cin 會出問題
    while(n--){
        getline(cin, buff);
        stringstream ss(buff);
        string tmp;
        while(ss >> tmp){
            for(int i=tmp.size()-1; i>=0; --i)
                cout << tmp[i];
        }
        cout << '\n';
    }
    return 0;
}

C++競賽技巧

By jacky860226

C++競賽技巧

  • 592