C/C++
by oToToT
歷史沿革
你可能會用到
整合式開發環境(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