C/C++

by oToToT

歷史沿革

等等,我們的課不是歷史課阿,那些知識對你學程式也不大會有幫助(可能等你寫久了會有一點點拉)

要看的去維基百科就可以看了拉,C / C++ 簡介

你可能會用到

整合式開發環境(IDE)

  • Code::Blocks
  • Dev-C++
  • Visual C++

文字編輯器

  • Sublime Text
  • Vim
  • Visual Studio Code
  • Notepad++
  • Atom

第一個C/C++程式

當然是Hello World囉

#include <cstdio>

int main(){
    printf("Hello world!\n");
    return 0;
}

稍微解釋一下

#include <cstdio>
/* C/C++中有許多的函式庫,要使用前要先記得打上#include <xxxxx> */

int main(){
    /* 這部分先略過不提,只要先知道所有你要執行的程式碼都請寫在main裡面 */
    printf("Hello world!\n");
    /* 利用cstdio裡內建的函數printf來將想要顯示的事物顯示出來 */
    return 0;
    /* 這部分先略過不提,只要先知道最後一行請打return 0就好 */
}

額外一提:怎麼跑程式

C/C++這語言在執行程式前,他需要先做「編譯」(Compile)的動作,「編」表示他要編寫出一份程式碼,「譯」表示他是要翻譯你的程式碼。編譯的好處在於他會檢查一些語法上的錯誤,或是任何完全不合理的行為,有些編譯器甚至還會幫你優化你的程式碼,讓他跑的更快。因此,在我們執行C/C++程式之前請先編譯你的程式碼,讓他產生出一份給電腦讀的程式碼。

額外一提:GCC

大部分的IDE內建的編譯器都是GCC,如果你要打競賽的話,大多也都是用GCC,所以這裡稍微講一下GCC的用法(?

假設你有裝GCC的話,可以在命令列中打上

g++ test.cpp

這樣的話他應該就會產生一個叫做a.out之類的執行檔,若要指定檔名可以輸入

g++ test.cpp -o test.exe

此外GCC還內建一些簡單的Warning,可以在輸入

g++ test.cpp -o test.exe -Wall

Ch1.1 變數

如何宣告一個變數

(修飾詞) 資料型態 變數名稱

int main(){
    int a, aa;
    const int xd;
    float b;
    char c;
    return 0;
}

各式資料型態

  • 整數類:int, long, short ...
  • 浮點數類:float, double ...
  • 字母類:char, string ...

數值類的限制

Text

型別名稱 占用記憶體 範圍
int 4 bytes -2147483648 ~ 2147483647
char 1 byte -128 ~ 127
short 2 bytes -32768 ~ 32767
long  4 bytes -2147483648 ~ 2147483647
long long 8 bytes –9223372036854775808 ~ 9223372036854775807
float 4 bytes 3.4E +/- 38 (7 位數)
double 8 bytes 1.7E +/- 308 (15 位數)
long double 16 bytes 1.18E +/- 4932 (31 位數)
bool 1 bytes 0 ~ 1

初始化與賦值

int main(){
    int a=5;
    int b;
    b=87;
    int c(7122);
    int x=10, y, z(8);
    return 0;
}

輸入輸出資料

#include <cstdio>

int main(){
    int a;
    scanf("%d", &a);
    int b, c;
    scanf("%d%d", &b, &c);
    int x, y;
    scanf("%d\n%d", &x, &y);
    printf("%d %d\n", x, y);
    return 0;
}

格式化關鍵字

型別名稱 關鍵字
int %d, %i / %u
char %c / %hhu
short %h / %hu
long  %ld / %lu
long long %lld / %llu
float %f
double %lf
long double %Lf, %llf
bool NO / dirty: %d

Ch1.2 運算

數值運算

  • 加法 a+b

  • 減法 a-b

  • 乘法 a*b

  • 除法 a/b

  • 餘數(模) a%b

位元運算

  • 往高位位移 a<<b

  • 往低位位移 a>>b

  • 位元反轉 ~a

  • 異或 a^b

  • 或 a|b

  • 且 a&b

布林運算

  • 小於 a<b

  • 大於 a>b

  • 等於 a==b

  • 不等於 a!=b

  • 大於等於 a>=b

  • 小於等於 a<=b

  • 否 !a / not a

  • 或 a || b / a or b

  • 和 a && b / a and b

運算的封閉性

#include <cstdio>

int main(){
    int a = 1000000, b = 1000000;
    if(a*b == 1000000000000LL) puts("Well");
    if(a*b == -727379968) puts("sad.");
    a = 3, b = 2;
    if(a/b == 1.6) puts("Yes");
    if(a/b == 1) puts("No");
    return 0;
}

自動轉型

#include <cstdio>

int main(){
    int a = 1000000;
    long long b = 1000000;
    if(a*b == 1000000000000LL) puts("Well");
    if(a*b == -727379968) puts("sad.");
    float a = 3; int b=2;
    if(a/b == 1.5) puts("Yes");
    if(a/b == 1) puts("No");
    return 0;
}

強迫轉型

#include <cstdio>

int main(){
    int a = 1000000, b = 1000000;
    if((long long)a*b == 1000000000000) puts("Well");
    if(a*b == -727379968) puts("sad.");
    int a = 3, b=2;
    if((float)a/b == 1.5) puts("Yes");
    if(a/b == 1) puts("No");
    return 0;
}

浮點數誤差

#include <cstdio>

int main(){
    float a = 0.1, b = 0.2;
    if(a+b == 0.3) puts("yes");
    else puts("no");
    return 0;
}

Ch1.3 條件

if/else

#include <cstdio>

int main(){
    int x; scanf("%d", &x);
    if(x==1) puts("x is 1");
    if(x!=1) puts("x is not 1");

    if(x==2) puts("x is 2");
    else puts("x is not 2");

    if(x==87){
        x=0;
        printf("x now is %d\n", x);
    }else{
        puts("thank you");
    }

    if(x==6){
        printf("%d\n", x);
    }else{
        if(x==7){
            printf("%d\n", 10-x);
        }else{
            printf("%d\n", x*10);
        }
    }

    if(x==6) printf("%d\n", x);
    else if(x==7) printf("%d\n", 10-x);
    else printf("%d\n", x*10);
    return 0;
}

Switch Case

#include <cstdio>

int main(){
    int x; scanf("%d", &x);
    switch(x){
        case 1:
            puts("1");
            puts("www");
            break;
        case 2:
            puts("2");
            break;
        case 3:
        case 4:
            puts("3 or 4");
            break;
        default:
            puts("ijk");
    }
    return 0;
}

3元運算子

#include <cstdio>

int main(){
    int x; scanf("%d", &x);
    puts(x==1?"1":"no");
    return 0;
}

Ch1.4 習題

Ch2.1 迴圈

迴圈?好吃嗎?

想像某天有人叫你在螢幕上顯示1~100,難道你會(想)寫

#include <cstdio>

int main(){
    printf("1 2 3 4 5 6 7 8 9 10.............");
    return 0;
}

while迴圈

#include <cstdio>

int main(){
    int i = 1; // 紀錄一下現在是數字幾
    while(i <= 100){ // 確定怎樣的情況下會執行
        printf("%d ", i);
        i = i + 1;
    }
    return 0;
}

先做再說 - do while

#include <cstdio>

int main(){
    int i = 1;
    do{
        printf("%d ", i);
        i = i + 1;
    }while(i <= 100);
    return 0;
}

插個話 i++ v.s. ++i

#include <cstdio>

int main(){
    int a = 1;
    printf("%d\n", a);
    a++;
    printf("%d\n", a);
    int b = 1;
    printf("%d\n", b);
    ++b;
    printf("%d\n", b);
    return 0;
}

插個話 i++ v.s. ++i

#include <cstdio>

int main(){
    int a = 1;
    int c = a++;
    printf("%d\n", c);
    int b = 1;
    int d = ++b;
    printf("%d\n", d);
    return 0;
}

變形一下 - for

#include <cstdio>

int main(){
    for(int i = 1; i <= 100; i++){
        printf("%d ", i);
    }
    return 0;
}

巢狀迴圈

#include <cstdio>

int main(){
    for(int i=1;i<=9;i=i+1){
        for(int j=1;j<=9;j=j+1){
            printf("%d * %d = %d\n", i, j, i*j);
        }
    }
    return 0;
}

break - 不是下課

#include <cstdio>

int main(){
    int n; scanf("%d", &n);
    bool isPrime = true;
    for(int i=2;i<=n;i++){
        if(n % i == 0){
            isPrime = false;
            break;
        }
    }
    return 0;
}

continue - 繼續阿

#include <cstdio>

int main(){
    int n; scanf("%d", &n);
    for(int i=1;i<=n;i++){
        if(i % 2 == 0) continue;
        printf("%d ", i);
    }
    return 0;
}

Ch2.2 陣列

陣列?那是什麼?

有時候你會需要記錄一堆類似性質的東西,可是難道你要寫出這樣的程式碼?

#include <cstdio>

int main(){
    int a1, a2, a3, a4, a5; 
    scanf("%d%d%d%d%d",&a1,&a2,&a3,&a4,&a4);
    // do something
    return 0;
}

不妨一起宣告

有時候你會需要記錄一堆類似性質的東西,可是難道你要寫出這樣的程式碼?

#include <cstdio>

int main(){
    int a[5];
    for(int i=0;i<5;i++) scanf("%d", &a[i]);
    // do something
    return 0;
}

從零開始的異世界生活陣列

#include <cstdio>

int main(){
    int a[3];
    a[2] = a[0] + a[1];
    return 0;
}

!!索引值從零開始!!

對於一個陣列a[n], 不存在a[n]或a[n+1]

大小為定值

#include <cstdio>

int main(){
    int n; scanf("%d",&n);
    int a[n];
    // do something
    return 0;
}

對於一個陣列a[n], n不能是動態給定的

初始化陣列

int numbers[5] = {0, 1, 2, 3, 4};
int numbers[5] = {0, 1}; // 自動補零
int numbers[] = {0, 1, 2, 3, 4, 5, 6, 7}; //自動計算長度
int numbers[100] = {0}; // 全部補零,因為會自動補零:D

// ----------------------------------------------- //

int numbers[5]; 
numbers = {0, 1, 2, 3, 4}; // 錯誤示範

字元陣列 (字串)

#include <cstdio>

int main(){
    char str[5] = "haha";
    printf("%s\n", str);
    printf(str);
    return 0;
}

題外話,特殊字元\0

#include <cstdio>

int main(){
    char str[5] = "haha";
    if(str[4] == '\0') printf("Hi");
    else printf("lol.");
    return 0;
}

遍歷字串

#include <cstdio>

int main(){
    char str[1000];
    scanf("%s", str);
    for(int i=0;str[i]!='\0';i++){
        printf("%c", str[i]);
    }
    return 0;
}

多維陣列

#include <cstdio>

int main(){
    int NineNine[10][10];
    for(int i=1;i<10;i++){
        for(int j=1;j<10;j++){
            NineNine[i][j] = i*j;
        }    
    }
    return 0;
}

多維陣列初始化

#include <cstdio>

int main(){
    int matrix1[3][3]={1, 2, 3, 4, 5, 6, 7, 8, 9};
    int matrix2[3][3]={{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    return 0;
}

Ch2.3 函數

數學上定義的函數

若\( f: X \to Y \)

則 \( \forall x \in X , \exists y \in Y s.t. f(x)=y \land \nexists y^\prime \neq y s.t. f(x)=y^\prime \)

C/C++的函數

#include <cstdio>
#include <cmath>

int main(){
    int x = -1;
    abs(x);
    int y = 25;
    sqrt(y);
    int xdd = pow(2, 10);
    return 0;
}

內建的函數百百種

C/C++內建的函數有許許多多種,分別擺在不同的標頭檔內,若要使用請先#include對的標頭檔

請務必確認該函數的參數規定即回傳值的意義

題外話:字串相關的函數

在<cstring>中有許多跟字串相關的函數,這裡稍微講幾個常用的。

  • strlen(str):計算字串str的長度
  • strcpy(str1, str2):將str1的內容設成跟str2一樣
  • strcat(str1, str2):將str2接在str1的後面
  • strcmp(str1, str2):比較str1跟str2(一樣的話是回傳0)

參數規範很重要

#include <algorithm>

int main(){
    int x = 10;
    long long y = 100;
    long long ret = std::max(x, y);
    return 0;
}

回傳值意義也很重要

#include <cstdio>
#include <cstdlib>

int main(){
    for(int i=0;i<100;i++){
        printf("%d ", rand());
    }
    return 0;
}

大多數人的選擇

#include <cstdio>
#include <cstdlib>
#include <ctime>

int main(){
    srand(time(NULL));
    for(int i=0;i<100;i++){
        printf("%d ", rand());
    }
    return 0;
}

自己的函數自己寫

#include <cstdio>

int abs(int);

int main(){
    printf("%d", abs(-20));
    return 0;
}

int abs(int x){
    if(x < 0) return -x;
    else return x;
}

自己的函數自己寫

#include <cstdio>

int abs(int x){
    if(x < 0) return -x;
    else return x;
}

int main(){
    printf("%d", abs(-20));
    return 0;
}

射後不理(?的函數

#include <cstdio>

void Hi(char s[]){
    printf("Hi, %s", s);
}

int main(){
    char str[100];
    printf("%s", str);
    Hi(str);
    return 0;
}

我想要又不想要

#include <cstdio>

void display(char,int=1);

int main(){
    char c; scanf("%c", &c);
    display(c, 10);
    display(c);
    return 0;
}

void display(char c, int time){
    for(int i=0;i<time;i++) printf("%c", c);
    printf("\n");
}

我想要又不想要

#include <cstdio>

void display(char c, int time=1){
    for(int i=0;i<time;i++) printf("%c", c);
    printf("\n");
}

int main(){
    char c; scanf("%c", &c);
    display(c, 10);
    display(c);
    return 0;
}

遞迴函數

#include <cstdio>

int fib(int x){
    if(x==0) return 0;
    if(x==1) return 1;
    return fib(x-1) + fib(x-2);
}

int main(){
    printf("%d", fib(10));
    return 0;
}

Scope

#include <cstdio>

void func(){
    int r = 5;
}

int main() {
    func();
    printf("%d\n", r);
    { int www = 9487; }
    printf("%d\n", www);
    return 0;
}

Scope

#include <cstdio>

int main() {
    int a = 1;
    if(true){
        int a = 2;
        printf("%d", a);
    }
    return 0;
}

Ch2.4 習題

來不及找QQ

大家可以試著做做印星星或是一些自己想做的東東, sorry

Ch3.1 自定義型別

我的資料有好多屬性

char name[3][20] = {"Kotori", "Maki", "Honoka"};
int age[3] = {15, 14, 15};
int height = {159, 161, 157};

自己的型別自己定拉

struct Lovelive{
    char name[10];
    int age, height;
};
struct Point{
    int x, y;
};
struct Line{
    // ax+by+c = 0
    double a;
    double b;
    double c;
};
struct SciFi{
    //a * 10^b
    double a;
    int b;
};

阿,可是值呢?

struct Point{
    int x, y;
};

int main(){
    Point a;
    a.x = 1;
    a.y = 2;
    Point b;
    b = {3, 4};
    return 0;
}

我想要多一點的功能

#include <cstdio>
#include <cmath>

struct Point{
    int x, y;
    double dis(){
        // distance of (0, 0) and (x, y)
        return sqrt(x*x+y*y);
    }
};

int main(){
    Point a = {1, 2};
    printf("%lf", a.dis());
    return 0;
}

還可以這樣耶

#include <cstdio>
#include <cmath>

struct Point{
    int x, y;
    double dis(Point A){
        // distance of A and (x, y)
        return sqrt((x-A.x)*(x-A.x)+(y-A.y)*(y-A.y));
    }
};

int main(){
    Point a = {1, 2}, b = {3, 4};
    printf("%lf", a.dis(b));
    return 0;
}

甚至我還可以做運算!

#include <cstdio>
#include <cmath>

struct Point{
    int x, y;
    Point operator+(Point a){
        Point ret;
        ret.x = x+a.x;
        ret.y = y+a.y;
        return ret;
    }
};

int main(){
    Point a = {1, 2}, b = {3, 4};
    Point c = a+b;
    printf("(%d, %d)", c.x, c.y);
    return 0;
}

建構子-初始化

#include <cstdio>
#include <cmath>

struct Point{
    int x, y;
    Point(){
        x = 0;
        y = 0
    }
    Point(int a, int b){
        x = a;
        y = b;    
    }
};

int main(){
    Point a = {1, 2}, b = {3, 4};
    Point c = a+b;
    printf("(%d, %d)", c.x, c.y);
    return 0;
}

private-public

#include <cstdio>
#include <cmath>

struct Point{
    private:
        int x, y;
    public:
        void set_point(int a, int b){
            x=a;
            y=b;        
        }
        double dis(){
            return sqrt(x*x+y*y);
        }
};

int main(){
    Point a = {1, 2};
    printf("(%d, %d)", c.x, c.y);
    return 0;
}

class

#include <cstdio>
#include <cmath>

class Point{
    int x, y;
};

int main(){
    Point a = {1, 2};
    printf("(%d, %d)", c.x, c.y);
    return 0;
}

Ch3.2 命名空間

namespace - 名字被用了怎麼辦

#include <cstdio>
#include <cmath>

int x1, y1;

int main(){
    scanf("%d%d", &x1, &y1);
    printf("|(%d, %d)|=%lf\n", x1, y1, sqrt(x1*x1+y1*y1));
    return 0;
}

namespace

#include <cstdio>
#include <cmath>

namespace ICanDoIt{
    int x1, y1;
    double dis(){
        return sqrt(x1*x1+y1*y1);
    }
};

int main(){
    scanf("%d%d", &ICanDoIt::x1, &ICanDoIt::y1);
    printf("%lf", ICanDoIt::dis());
    return 0;
}

每次都要打一遍好麻煩

#include <cstdio>
#include <cmath>

namespace ICanDoIt{
    int x1, y1;
};

int main(){
    using ICanDoIt::x1;
    using ICanDoIt::y1;
    scanf("%d%d", &x1, &y1);
    // something
    return 0;
}

using還是好麻煩

#include <cstdio>
#include <cmath>

namespace ICanDoIt{
    int x1, y1;
};

int main(){
    using namespace ICanDoIt;
    scanf("%d%d", &x1, &y1);
    // something
    return 0;
}

using namespace std

#include <iostream>
using namespace std;

int main(){
    int x; cin>>x;
    return 0;
}

Ch3.3 指標

變數放在哪呢?

大家上學校的資訊課應該都知道,其實我們的變數其實是存到電腦的記憶體中,所以每個變數想當然的都會佔一定的記憶體大小,而且也一定在某個地方記錄了這個東東的位置。

所以其實我們在宣告變數的時候其實就是跟作業系統要一塊記憶體,然後把資料擺進去

講重點啦,指標指標

指標其實是一種特別的資料型態,他會存放某個記憶體位置,所以有了位置你就可以透過某種特別的方式進去裡面獲得資料,或改變資料。

學資芽打個比喻:如果把記憶體想成一個旅館的話,那指標就會是門牌號碼,你可以知道裡面可能有人住,但其實裡面住誰你還是要進去才知道。

所以指標到底長怎樣

#include <cstdio>

int main(){
    int a = 131071;
    int *ptr = &a;
    printf("%p", ptr);
    return 0;
}

各種指標

#include <cstdio>

int main(){
    int *a;
    double *b;
    long long *c, d;
    return 0;
}

我想進去他房間(?

#include <cstdio>

int main(){
    int a = 127;
    int *ptr = &a;
    printf("%d\n", *ptr);
    *ptr = 50;
    printf("%d\n", a);
    return 0;
}

指標的指標

#include <cstdio>

int main(){
    int a = 127, b=100;
    int *ptr = &a;
    int **ptrptr = &ptr;
    *ptrptr = &b;
    *ptr = 2;
    printf("%d", *ptr);
    return 0;
}

陣列其實是某種指標

#include <cstdio>

int main(){
    int a[] = {1, 2, 3}
    printf("%d\n", a[1]);
    printf("%d\n", *(a+1));
    return 0;
}

Reference - 參照

#include <cstdio>

int main(){
    int a = 127;
    int &b = a;
    printf("%d, %d\n", a, b);
    b = 100;
    printf("%d, %d\n", a, b);
    return 0;
}

Ch3.3 指標應用

我想要交換東西

#include <cstdio>

void swap(int x, int y){
    int tmp = x;
    x = y;
    y = tmp;
}

int main(){
    int a=10, b=20;
    printf("%d %d\n", a, b);
    swap(a, b);
    printf("%d %d\n", a, b);
    return 0;
}

Call by Address

#include <cstdio>

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

int main(){
    int a=10, b=20;
    printf("%d %d\n", a, b);
    swap(&a, &b);
    printf("%d %d\n", a, b);
    return 0;
}

Call by Reference

#include <cstdio>

void swap(int &x, int &y){
    int tmp = x;
    x = y;
    y = tmp;
}

int main(){
    int a=10, b=20;
    printf("%d %d\n", a, b);
    swap(a, b);
    printf("%d %d\n", a, b);
    return 0;
}

傳遞陣列

#include <cstdio>

void myfunc(int arr[], int n){
    // do something
}

int main(){
    int arr[10];
    myfunc(arr, 10);
    return 0;
}

傳遞多維陣列

#include <cstdio>

void myfunc(int arr[][9], int n, int m){
    // do something
}

int main(){
    int arr[9][9];
    myfunc(arr, 9, 9);
    return 0;
}

動態配置記憶體

#include <cstdio>

int main(){
    int n; scanf("%d", &n);
    int *ptr = new int;
    int *arr = new int[n];
    *ptr = 10;
    for(int i=0;i<n;i++) arr[i]=i;
    delete ptr;
    delete[] arr;
    return 0;
}

動態配置二維陣列

#include <cstdio>

int main(){
    int n; scanf("%d", &n);
    int **mtx = new int*[n];
    for(int i=0;i<n;i++) arr[i]=new int[n];
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            arr[i][j]=i*j;
        }
    }
    for(int i=0;i<n;i++) delete[] arr[i];
    delete[] arr;
    return 0;
}

學習資源

C/C++

By Tommy Chiang

C/C++

An Easy Introduction of C/C++

  • 1,896