C++與C的區別一

1. C++風格數組初始化:ios

#include <iostream> #include <array>

using namespace std; void main() { //CPP一維數組初始化
    array<int, 10>MyInt{ 1,2,3,4,5,6,7,8,9,10 }; for (auto i : MyInt) { cout << i << " " << (void *)&i << endl; } //CPP二維數組初始化
    array<int, 10>MyInt1{ 11,2,3,4,5,6,7,8,9,10 }; array<int, 10>MyInt2{ 21,2,3,4,5,6,7,8,9,10 }; array<int, 10>MyInt3{ 31,2,3,4,5,6,7,8,9,10 }; array<array<int, 10>, 3>myInt{ MyInt1,MyInt2,MyInt3 }; for (auto j : myInt) { for (auto i : j) { cout << i << " "; } cout << endl; } cin.get(); }

 2. CPP別名:面試

#include <iostream>

using namespace std; //通常狀況,原則上都用using取代typedef //typedef處理不了模板,處理不了命名空間,統一用using
typedef double DB;        //C風格
using DBCPP = double;    //CPP風格別名 //數組別名
typedef int a[10]; using IntArray = int[10]; //函數指針
typedef int(*p)(int a, int b);        //函數指針類型,p
using pFun = int(*)(int a, int b);    //CPP函數指針別名 //函數指針數組
typedef int(*pa[10])(int a, int b); using ppFun = int(*[10])(int a, int b); void main() { cout << sizeof(DB) << endl;       //8
    cout << sizeof(DBCPP) << endl;    //8
 IntArray int1; cout << sizeof(int1) << endl;     //40
 cin.get(); }

3. auto 使用:數組

#include <iostream>

using namespace std; //C++14自動推理返回值類型 //C++11須要指定返回值類型
auto add(int a, int b)->int        //此處int可換爲decltype(a+b)
{ return a + b; } //數控科技面試題:請問f是什麼?
auto (*f)()->int(*)(); //int(* (*fx)() )() //返回值是函數指針 //請推理下面pf是什麼類型?
auto pf1()->auto(*)()->int(*)() { return nullptr;    //返回空指針
} auto pf2(void)->auto(*)(int x)->int(*)(int a,int b) { return nullptr;    //返回空指針
} //int(* (*)(int x) )(int a,int b) //int(* (* pf2(void) )(int x) )(int a,int b) //int(*(* (void) )(int))(int,int)
 auto go(int a, int b)->auto(*)()->int (*)(int, int(*)(int, int)); //int (* (*)() )(int, int(*)(int, int)) //int (* (* go(int a, int b) )() )(int, int(*)(int, int)) //int (* (* (int, int))(void))(int, int (*)(int,int))

void main() { cout << typeid(f).name() << endl; cout << typeid(pf1).name() << endl; cout << typeid(pf2).name() << endl; cout << typeid(go).name() << endl; cin.get(); }

4. 函數模板的別名:安全

#include <iostream> #include <array>

using namespace std; //C++14自動推理返回值類型 //C++11須要指定返回值類型
template<class T1,class T2> auto add(T1 t1, T2 t2)->decltype(t1 + t2)        //此處int可換爲decltype(a+b)
{ return t1 + t2; } //函數模板的別名
template<class T> using t = T; template<class T> using tp = T*; template<class T>
void show(T tx) { t<int> t1(tx);        //一旦使用別名必須指定類型 <int>
    tp<int> tp1(&tx);    //初始化指針
    cout << t1 << " " << tp1 << endl; } template<class T> using ten = array<T, 10>; void main() { cout << add(1, 2) << endl;            //3
    cout << add(1.1, 2.2) << endl;        //3.3

    int a = 10; show(a); using IntArray = array<int, 10>;    //至關於爲模板起了別名,明確地指明瞭類型爲array<int, 10>
    array<int, 10> MyInt;                //此時array<int, 10>表明一個類型
 IntArray MyInt2; //template<class T> using t = array<T, 10>; //error C2951: 模板 聲明只能在全局、命名空間或類範圍內使用
    ten<int> t1{ 1,2,3,4,5,6,7,8,9,10 };//模板別名不明確類型
    for (auto i : t1) { cout << i << " "; } cin.get(); }

5. 收縮轉換:函數

#include <iostream>

using namespace std; void main() { char ch1(787878); char ch2{ 787878 };    //賦初始值最好用大括號,保證數據類型安全轉換
 cout << (int)ch1 << endl;    //-90 編譯經過,產生溢出
    cout << (int)ch2 << endl;    //編譯不經過,error C2397: 從「int」轉換到「char」須要收縮轉換
 cin.get(); }

6. 二進制:優化

#include <iostream>

using namespace std; void main() { int a = 0b1001; int b = 0B1101; cout << a << endl;    //9
    cout << b << endl;    //13
 cin.get(); }

7. 常量表達式constexpr :spa

#include <iostream>

using namespace std; int get1() { return 5; } constexpr int get2()    //constexpr返回值或其餘表達式爲常量
{ return 5; } void main() { //int a[5+get1()]; //error C2131: 表達式的計算結果不是常數
    int a[5 + get2()];    //編譯成功
 cin.get(); }

 8. lambda 表達式:指針

#include <iostream>
using namespace std; void main() { [] {cout << "hello world!" << endl; }();        //解決函數懷孕現象
 auto fun = [] {cout << "hello" << endl; };        //函數指針
    fun();//調用
 [] {cout << "hello C" << endl; }();                //匿名lambda表達式
 [](char *str) {cout << str << endl; }("你好!");//帶參數(匿名)
 auto fun1 = [](double a, double b) {return a + b; }; cout << fun1(10, 20.1) << endl;        //30.1
 auto fun2 = [](double a, double b)->int {return a + b; };    //指定返回值類型,->在()與{}之間
    cout << fun2(10, 20.1) << endl;        //30

    int num = 100; auto func = [](int num) {num = 5, cout << num << endl; };//遵循副本機制
    func(num);                        //5
    cout << "main=" << num << endl;    //main=100
 cin.get(); }
#include <iostream> #include <array> #include <algorithm>
using namespace std; void main() { int num1 = 100; int num2 = 99; //[]() {cout << num1 << " " << num2 << endl; }();//error C3493: 沒法隱式捕獲「num1」,由於還沒有指定默認捕獲模式
    [=]() {cout << num1 << " " << num2 << endl; }();    //100 99 //[=]() {num1=10,num2=20,cout << num1 << " " << num2 << endl; }();//error C3491: 「num1」: 沒法在非可變 lambda 中修改經過複製捕獲
    [&]() {num1 = 10, num2 = 20, cout << num1 << " " << num2 << endl; }();//=只能讀不可寫;&讀寫外部變量
    cout << "main=" << num1 << " " << num2 << endl;        //main=10 20

    int num3 = 100; int num4 = 99; [=]()mutable {num3 = 10, num4 = 20, cout << num3 << " " << num4 << endl; }();    //10 20 mutable起到副本做用
    cout << "main=" << num3 << " " << num4 << endl;                                    //100 99

    int a = 10, b = 9, c = 8; //a可讀可寫,bc只可讀
    [&a, b, c]() {a = 20, cout << a << " " << b << " " << c << endl; }();    //20 9 8 //mutable副本,能讀能寫,讀的本來,寫的副本
    [a, b, c]()mutable {a = 1, b = 2, c = 3, cout << a << " " << b << " " << c << endl; }();    //1 2 3 
 array<int, 10>MyInt{ 1,2,3,4,5,6,7,8,9,10 }; //lambda表達式嵌入使用
    for_each(MyInt.begin(), MyInt.end(), [](int num) {cout << num << " "; });                //顯示
    cout << endl; for_each(MyInt.begin(), MyInt.end(), [](int &num) {num += 1, cout << num << " "; });    //修改
    cout << endl; for_each(MyInt.begin(), MyInt.end(), [](int num) {cout << num << " "; });                //顯示
 cin.get(); }

9. 函數包裝器:code

#include <iostream> #include <functional>    //函數包裝器頭文件

using namespace std; using std::function;    //函數包裝器

void go() { cout << "go" << endl; } int ADD(int a, int b) { return a + b; } void main() { function<void(void)> fun1 = go;                                    //包裝函數
 fun1(); function<void(void)> fun2 = []() {cout << "go lambda" << endl; };//包裝lambda表達式
 fun2(); function<int(int, int)> fun3 = ADD; cout << fun3(10, 19) << endl; function<int(int, int)> fun4 = [](int a, int b)->int {return a + b; }; cout << fun4(10, 19) << endl; cin.get(); }

10. 模板元blog

#include <iostream>
using namespace std; int get50(int n) { if (n == 1) return 1; else if (n == 2) return 2; else
        return get50(n - 1) + get50(n - 2); } //遞歸調用:函數反覆調用,等待返回,浪費時間較多 //模板元實現遞歸加速 //執行速度快,編譯的時候慢,代碼會增長 //把運行的時間節約在編譯的時候 //常使用在遞歸加速,遊戲優化,此處的模板元僅僅適用於C++11
template<int N>
struct data { //遞歸表達式
    enum { res = data<N - 1>::res + data<N - 2>::res }; }; template<>
struct data<1> { enum { res = 1 }; }; template<>
struct data<2> { enum { res = 2 }; }; void main() { cout << data<40>::res << endl;    //模板元,代碼加速(將運行時間放在編譯中執行)
    cout << get50(40) << endl; cin.get(); }

11. C++中的const :

#include <iostream>
using namespace std; void run1(const int *p);        //可改變地址,不可改內容
void run2(int const *p);        // void run3(int * const p);        //不可改地址,可改內容
void run4(const int * const p);    //地址內容均不能改
void run5(int const * const p);    // 
void main() { //C語言中: //const int num = 10; //*(int *)(&num) = 4; //printf("%d\n", num); //4 //const int n = 10; //int a[n]; //C++編譯器自動優化,將n直接替換爲10 //int a = 10; //const int n = a; //此時C++編譯器不敢亂優化,不敢把n直接替換爲a //int data[n]; //error C2057: 應輸入常量表達式 //const int a = 10; //const int n = a; //int data[n]; //const int num = 10; //*(int *)(&num) = 3; //cout << (void *)&num << endl; //優化,強行替換爲10,寄存器 //cout << *(&num) << endl; //10 //cout << num << endl; //10 //int a = 10; //const int num = a; //*(int *)(&num) = 3; //cout << (void *)&num << endl; //直接讀內存,此時爲變量,不敢優化 //cout << *(&num) << endl; //3 //cout << num << endl; //3

    const int num[5] = { 1,2,3,4,5 }; const int *p = num; *(int *)p = 100;        //const數組沒有優化,能夠間接改變
    for (auto i : num) cout << i << " ";    //100 2 3 4 5
    cout << endl; cin.get(); }

12. 智能指針:

#include <iostream> #include <memory> #include <Windows.h>    
using namespace std; void cmem() { while (1) { double *p = new double[1024 * 1024 * 10]; Sleep(3000); delete p;        //釋放
        Sleep(3000); } } void autoptr() { while (1) { double *p(new double[1024 * 1024 * 10]); auto_ptr<double>autop(p);    //建立智能指針,接管這片內存,會自動回收
 Sleep(3000); } } void autoptrnew() { while (1) { Sleep(6000); unique_ptr<double>p(new double[1024 * 1024 * 10]); Sleep(6000); } } void main() { //cmem();
 autoptr(); autoptrnew(); cin.get(); }

13. 多元數組 tuple :

#include <iostream> #include <tuple>
using namespace std; //多元數組,存取不一樣的數據類型
void main() { char ch = 'X'; short sh = 12; int num = 1234567; double db = 123; char *p = "calc"; tuple<char, short, int, double, char *>MyTuple(ch, sh, num, db, p); auto autov1 = get<0>(MyTuple);    //多元數組不能用for(auto i:MyTuple)的方式遍歷
    cout << autov1 << endl; auto autov2 = get<1>(MyTuple); cout << autov2 << endl; auto autov3 = get<2>(MyTuple); cout << autov3 << endl; auto autov4 = get<3>(MyTuple); cout << autov4 << endl; auto autov5 = get<4>(MyTuple); cout << autov5 << endl; cin.get(); }

14. 左值引用與右值引用:

#include <iostream>
using namespace std; //C++能用引用的狀況,就別用指針
void change(int & rnum) { rnum = 111; } void main0501() { //int num(10); //num是左值,有內存實體,能夠賦值 int num=10; //int & rnum(num); //引用&就是變量的別名 //
    //rnum = 1; //rnum等價於num的別名 //change(num); //cout << num << endl; //111 //int num = 1; //int data = 0; //cout << (void *)&data << endl; //data = num + 1; //data = num + 2; //data = num + 3; //cout << data << endl; //右值引用
    int num = 1; int && rnum(num + 4);    //右值引用,快速備份寄存器的值。編譯器會自動回收
    printf("%p\n", &rnum); //如果左值引用,須要兩步:
    int data = num + 4; int &rdata(data); int a[5]{ 1,2,3,4,5 }; int *p(a); cout << *p << endl;        //1

    int * & rp(p);            //左值引用改變指針 & 放在類型與變量名之間
    rp += 1; cout << *p << endl;        //2

    int * && rrp(p + 2);    //右值引用改變指針 && //int * && rrp(&a[1]);
    cout << *rrp << endl;    //4
 cin.get(); } void showit(int && rrnum)    //右值引用
{ cout << rrnum << endl; } void main() { int a[5]{ 1,2,3,4,5 }; showit(a[3] + 2); //移動語義:將左值轉化爲右值(左值必定能夠變爲右值,右值不必定可變爲左值)
    showit(move(a[3])); cin.get(); }

15. 引用的本質:

#include <iostream>
using namespace std; void main0601() { int num = 10; int data = 20; int & rnum(num);    //引用一旦初始化,就不會再引用其餘變量
    rnum = data; cout << num << endl;    //20
    cout << data << endl;    //20
 cin.get(); } void main() { double db; //double & rdb; //error C2530: 「rdb」: 必須初始化引用
    double & rdb(db); cout << sizeof(rdb) << endl;        //8

    struct MyStruct        //引用的本質是指針實現的,爲了簡化程序
 { double & rdb; }; cout << sizeof(MyStruct) << endl;    //4
 cin.get(); }

 16. 引用指針以及做爲函數參數和函數返回值:

#include <iostream>
using namespace std; //改變指針,須要二級指針 //C++中可用引用
void main0701() { int a(4);            //初始化爲4
    int *p(new int(5));    //開闢int大小空間,值爲5
    cout << a << endl;    //4
    cout << *p << endl;    //5 //int & ra(a); //引用變量 //int * & rp(p); //引用指針 //ra = 3; //*rp = 12; //cout << a << endl; //3 //cout << *p << endl; //12

    int && rra(move(a));    //右值引用,有內存實體就直接引用,沒有內存實體則新開闢內存
    int * && rrp(move(p)); rra = 1; cout << rra << endl; cout << a << endl; //int 整數類型 //int & 引用整數,本質是指針 //int && 引用整數,本質是指針,能處理左值(move) 和右值
 cin.get(); } int num1 = 10; int num2 = 20; void change(int * &rp)    //C++中能用引用就別用指針
{ rp = &num2; } void main0702() { int *p = &num1; change(p); cout << *p << endl;    //20
 cin.get(); } void main0703() { int *p(nullptr); int **pp(&p); int ** &rpp(pp);        //VS2015 C++14 //int **pp(&p); //int(** (&rpp))(pp); //VS2013 C++11
 cin.get(); } void main0704() { int ***ppp(nullptr); int *** & rppp(ppp); cin.get(); } int data1 = 10; int data2 = 20; int *p = &data1; void changeit(int ** &rpp) { *rpp = &data2; } void main0705() { int **pp = &p;    //二級指針
    cout << **pp << endl;    //10
 changeit(pp); cout << **pp << endl;    //20
 cin.get(); } //返回一個引用a
int getdata() { int num = 10; return num;        //函數返回值有副本機制
} void main0706() { cout << getdata() << endl;    //10
 cin.get(); } //函數返回值有副本機制,返回變量 //棧區,自動回收、釋放,返回爲指針不能指向棧區,返回爲引用不能應用棧區
int & getdata1() { int num = 10; return num;        //函數返回值有副本機制
} void main0707() { int & rnum = getdata1();    //此時引用的是原來的內存,調用後已經釋放
    cout << "hello" << endl; cout << rnum << endl;        //此處結果並非10

    int rnum2 = getdata1();        //拷貝到新的內存rnum2中
    cout << rnum2 << endl;        //10
 cin.get(); } int & getdata2() { int *p(new int(5));    //堆區 
    return *p; } void main0708() { int & rnum = getdata2();    //此時引用的是堆區
    cout << "hello" << endl; cout << rnum << endl;        //5
 cin.get(); } char * & getcode() { char *p = "hellohellohello";    //常量字符串-->代碼區(與程序供存亡)
    return p;                        //p在棧上,但指向內容在代碼區
} void main() { char * &rp = getcode();            //指針,引用p,但這個p在棧上,消亡了
    char * newp = rp;    //保存rp存儲代碼區地址
    cout << "hello china" << endl; cout << newp << endl;    //hellohellohello
    cout << rp << endl;        //亂碼
 cin.get(); }

17. 引用數組:

#include <iostream>
using namespace std; void main0801() { int a[5]{ 1,2,3,4,5 };                            //一維數組
    int *pa[5]{ a,a + 1,a + 2,a + 3,a + 4 };        //指針數組

    int b[2][3]{ 1,2,3,4,5,6 };        //二維數組 //二維數組,每個元素是一個指針
    int *pb[2][3]{ &b[0][0],&b[0][0] + 1,&b[0][0] + 2,&b[0][0] + 3,&b[0][0] + 4,&b[0][0] + 5 }; int *p1(new int[5]{ 1,2,3,4,5 });                //堆上的一維數組
    int(*p2)[4] = new int[3][4]{ {1,2,3,4},{5,6,7,8},{9,10,11,12} };    //堆上的二維數組
 cin.get(); } void main0802() { int a[5]{ 1,2,3,4,5 }; int(&ra)[5](a);            //引用一維數組
    for (auto i : ra) cout << i << " "; cout << endl; int *pa[5]{ a,a + 1,a + 2,a + 3,a + 4 }; int *(&rpa)[5](pa);        //引用指針數組
    for (auto i : rpa) cout << *i << " "; cout << endl; cin.get(); } void main0803() { int *p1(new int[5]{ 1,2,3,4,5 }); int **pp(new int *[5]{ p1,p1 + 1,p1 + 2,p1 + 3,p1 + 4 });    //堆上指針數組
    int * &rp(p1); int ** &rpp(pp); cin.get(); } void main0804() { int b[2][3]{ 1,2,3,4,5,6 };        //二維數組 //二維數組,每個元素是一個指針
    int *pb[2][3]{ &b[0][0],&b[0][0] + 1,&b[0][0] + 2,&b[0][0] + 3,&b[0][0] + 4,&b[0][0] + 5 }; int(&rb)[2][3](b);        //引用二維數組
    int *(&rpb)[2][3](pb);    //引用二維指針數組
 cin.get(); } void main() { //int(*p2)[4] = (new int[3][4]{ { 1,2,3,4 },{ 5,6,7,8 },{ 9,10,11,12 } }); //堆上的二維數組 //指向數組的指針,用{}初始化
    int(*p2)[4]{ new int[3][4]{ { 1,2,3,4 },{ 5,6,7,8 },{ 9,10,11,12 } } }; int(*&rp)[4](p2);    //引用行指針
    for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) cout << rp[i][j]<<"   "; cout << endl; } int * (*pp)[4]{ new int *[3][4] };    //堆上開闢二維指針數組
    int * (*&rpp)[4](pp);                //引用二維指針數組
 cin.get(); }

 18. const 與引用:

#include <iostream>
using namespace std; void main0901() { int num = 100; int const & rnum(num);    //const限定引用權限,只能讀不能寫 //const int & rnum(num); //與上面同樣 //rnum=3; //不能寫
    cout << rnum << endl; cin.get(); } //void main0902() //{ // int num = 100; // int & const rnum(num); //const放在&右邊沒有影響 // rnum=3; // cout << rnum << endl; //
// cin.get(); //}

void main0903() { int a[5]{ 1,2,3,4,5 }; const int(&ra)[5](a);    //只能讀不能寫
    for (auto i : ra) cout << i << " "; cout << endl; cin.get(); } void main0904() { //int *p(new int(5)); //堆上指針初始化 //int *(&rp)(p); //*rp = 3; //cout << *p << endl;

    const int *p(new int(5));    //指針,指向常量
    const int (*(&rp))(p);        //引用一個指向常量的指針 //*rp = 3;
    cout << *p << endl; cin.get(); } void main0905() { int * const p(new int(4));    //地址不能變,值能夠變
    int * const (&rp)(p);        //引用一個常量指針
    *p = 1; cin.get(); } void main0906() { const int * const p(new int(4));    //地址不能變,值也不能變
    const int * const (&rp)(p);            //引用一個指向常量的常量指針 //*p = 1;
 cin.get(); } void main() { int *p(new int(4)); //const int *(&rp)(p); //error C2440: 「初始化」: 沒法從「int *」轉換爲「const int *&」
    const int *(&rp)((const int *&)p);    //強制轉換
 cin.get(); }

 19. 引用與函數指針:

#include <iostream> #include <cstdlib>
using namespace std; //函數指針引用做爲參數,能夠改變函數指針 //函數指針引用做爲返回值,能夠實現調用getitp(p)("hello world");
int gocmd(const char *cmd) { system(cmd); return 1; } int showcmd(const char *cmd) { cout << cmd << endl; return 1; } void change(int(* & p)(const char *cmd))    //函數指針的引用作參數
{ p = showcmd; } //getp()返回一個函數指針
int(*    getp()    )(const char *cmd) { int(*( p))(const char *cmd)(gocmd); return p; } //getitp()返回一個函數指針的引用,而且參數是一個函數指針的引用
int(* &   getitp(   int(*& p)(const char *cmd)    )     )(const char *cmd) { p = showcmd; return p; } void main() { int(*p)(const char *cmd)(gocmd);    //定義函數指針並初始化 //p("calc");

    ////change(p);
    //p = getp(); //經過返回值來賦值 //p("echo hello world");
 getitp(p)("hello world");    //首先getitp(p)返回一個函數指針的引用,而後繼續執行後面語句
 cin.get(); }

20. 引用與指針的差異:

#include <iostream>
using namespace std; struct MyStruct { int *p1;        //4
    int & p2;        //4
    double & p3;    //4
};        //引用本質就是指針 //int & getint1() //{ // int a = 5; // return a; //返回局部變量或臨時變量的地址 //}

int & getint2(int & rint)    //參數、返回都是地址,此時引用的是外部傳入的參數
{ rint = 1; return rint; } void main() { //cout << sizeof(MyStruct) << endl;

    int a = 10; int *p(new int(5)); //getint2(a); //getint2(*p);

    int & ra(a);    //引用,棧上,4個字節
 cin.get(); }
相關文章
相關標籤/搜索