CPP_Details_Medium0.1

版权声明:本文虽为 贴墙上的咖啡 原创,未经允许仍可转载. https://blog.csdn.net/enochhugh/article/details/83552176

1.手动编译:
单文件:

$ g++ test.cpp -o myname
$ ./ myname

多文件:

$ g++ test1.cpp test2.cpp -o myname
$ ./ myname

指定C++11标准:

g++ -g -Wall -std=c++11 main.cpp

2.声明typedef

typedef int dog;//支持安全检查,作用域块内
//增加dog为int的别名
#define dog int* //不支持检查,无作用域
#define WIDTH 5//#undef WIDTH可取消
#define MIN(a,b) (a<b ? a : b)//可定义参数宏define
#define MKSTR( x ) #x//可定义为字符串"x"
#define concat(a, b) a ## b//可定义为a*b

3.枚举enum

enum clolr {red,green,blue} c;
c = blue;
enum color { red, green=5, blue };//blue为6,red仍为0

4.同名时,使用::引用全局版变量,
::count//否则引用局部变量

5.宽字符常量
L’x’ 可存储于wchar_t类型的变量中

6.转义空格\t
可以输出空格

7.explicit,
防止构造函数的隐式转换发生;

Test t=12;//试图隐式转换,失败
Test t(12);//直接初始化,成功

8.static存储类
应用局部固定作用域内的值;
应用全局则将变量限制于该声明文件中。

9.thread_local 存储类
仅应用于数据声明和定义;不能用于函数声明或定义

10.^是异或,~是补码计算,<<是左移,>>右移

A   = 0011 1100
B   = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A  = 1100 0011
A>>2= 0000 1111
A<<2= 1111 0000
A<<= 2//等同于 A=A<<2; 

11.while (x --> 0);
其实等价于while( (x–) > 0 );

12.for范围循环

int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array){sth.}

13.Lambda 函数

[capture](参数) mutable->返回值{body}//公式
auto add_x = [x](int a) mutable { x *= 2; return a + x; };//示例
[](int x, int y){ return x < y ; }//标准示例
[]{ ++global_x; }//无参数示例
[]{};//最简单的示例

auto Myname = [] { cout << "sth" << endl; };
Myname();//实用示例

注意:
Lambda 函数总是一个 const 函数,mutable 可以取消其常量性。
在使用该修饰符时,参数列表不可省略(即使参数为空)

[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

14.对于[=]或[&]的形式,Lambda 表达式可以直接使用 this 指针。
但对于[]的形式,如果要使用 this 指针,必须显式传入:

[this]() { this->someFunc(); }();

15.C++随机数
如要产生 [m,n] 范围内的随机数num,可用:int num=rand()%(n-m+1)+m;
(即 rand()%[区间内数的个数]+[区间起点值])

#include <time.h>
srand((unsigned) time(NULL)); /*播时间秒数种子*/
 for(i = 0; i < 10; i++)
    {
        number[i] = rand() % 100; /*产生100以内的随机整数*/
        printf("%d ", number[i]);
    }

16.二维数组

int a[3][4] = {  
 {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
};
等价于int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
输出循环:
 int a[i][j] = {};               
   for ( int i = 0; i < 5; i++ )
      for ( int j = 0; j < 2; j++ )
      {
         cout << "a[" << i << "][" << j << "]: ";
         cout << a[i][j]<< endl;
      }

17.数组指针

*(Arryname + x)等价于Arryname[x]

注意:
C++ 中,将 char * 或 char[] 传递给 cout 进行输出,
结果会是整个字符串,如果想要获得字符串的地址(第一个字符的内存地址),
可使用以下方法:
强制转化为其他指针(非 char*);
可以是 void *,int *,float *, double * 等;

  • 使用 &s[0] 不能输出 s[0](首字符)的地址:
    因为 &s[0] 将返回 char*,对于 char*(char 指针),
    cout 会将其作为字符串来处理,向下查找字符并输出直到字符结束 *

18.常量字符串必须加const,以\0结尾

const char a4[7] = "something";//最后一位是'\0'
//直接初始化char数组是特殊的,这种初始化数组末尾字符以一个null结尾

19. vector动态向量容器

 vector<int> vec;
//可使用诸如vec.size(),vec.push_back(i)
2:
vector <int *> a 
3:
vector <int **> a 
使用数组对其赋值:
第一种:vector<int> v( a, a+sizeof(a)/sizeof(a[0]) );
第二种:
int a[]={1,2,3,4,5,6,7,8,9};
typedef vector<int> vec_int;
vec_int vecArray(a,a+9);

20.setw(int n)用来控制输出间隔,(n-1个空格)

cout<<setfill('*')<<setw(5)<<'a'<<endl;
输出:****a

21.动态分配数组

int MAX=10;
int *array=new int[MAX]{1,2,3};
delete[] array;

22.获取数组长度遍历数组:

char* x[5] = { (char*)"1", (char*)"2", (char*)"3", (char*)"4", "5" };
for (int i = 0; i < sizeof(x) / sizeof(char*); i++)
cout << x[i] << "\n";

23.字符串长度

cout<<strlen("123")<<endl;   //返回 3
cout<<sizeof("123")<<endl;   //返回 4
string s = "123";
cout<<s.size()<<endl;        //返回 3
char str[20]="0123456789";
int a=strlen(str); // a=10;
int b=sizeof(str); // 而 b=20;

24.在 C++ 里参数传递数组永远都是传递指向数组首元素的指针,
编译器不知道数组的大小;如果想在函数内知道数组的大小, 这样做:
进入函数后用memcpy拷贝出来,长度由另一个形参传进去:

fun(unsiged char *p1, int len)
{
    unsigned char* buf = new unsigned char[len+1]
    memcpy(buf, p1, len);
}

25.检查空指针一般可直接使用if(ptr)语句;
MacOS中空指针为8字节,ptr++理论上移动8字节;
使用指针控制多用while循环,而i++控制多用for循环;
比如:while ( ptr <= &var[MAX - 1] );
还需要注意数组名虽然是指针,不能自增减–、++
比如:var++不可行,但是*(var+2)可行

26.指针数组

int *ptr[MAX];//指针数组
int *(ptr[3]);//指针数组
用法:ptr[i] = &var[i];int (*ptr)[3];//是数组指针!!

27.常量引用不允许绑定非对象,但是使用const除外:

const int &r1 = MAX;//可行
等价于:
const int temp = dval;  
const int &ri = temp; 

28.常量指针(const位于*左侧):

int const* p;
或者
const int* p;//优先使用
//指针p可变,所对应常量内容*p不可修改

指针常量(const位于*右侧)int * const p;//
//指针p不可变,所对应的内容*p可修改

指向常量的常指针:(总之他们都适用就近原则)
const int * const p;
//均不可变

29.new出来的指针delete后,一定要置nullptr,
否则成为野指针非常危险;不能返回函数内部new分配的内存的引用,
目的是防止内存泄露。

30.获取系统当前时间

#include <ctime>
time_t now = time(0);
char* dt = ctime(&now);
cout << "本地日期和时间:" << dt << endl;
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);
cout << "UTC 日期和时间:"<< dt << endl;

31.cerr<<非缓冲,立即会被输出,用于处理错误消息;
clog<<缓冲,溢出或刷新才输出,用于处理日志消息。

32.结构体指针

struct Books *struct_pointer;
struct_pointer = &Book1;
struct_pointer->title;//对象用.指针用->
示例:
printBook( &Book1 );//传地址
void printBook( struct Books *book ){}

33.typedef和结构体简化

typedef struct Books{sth.}Books;
之后,即可直接Books Book1, Book2;

34.typedef和指针

typedef long int * sex99;
sex99 x,y,z;//三个都将成为指针

35.类和结构体的区别:
(1)class 默认的成员访问权限是private,
而 struct 中则是 public 的。
(2)从 class 继承默认是 private 继承,
而从 struct 继承默认是 public 继承。
C的结构体不可有函数,C++的结构体可以有函数。

36.关于继承
1.private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
2.protected 成员可以被public继承的派生类访问

37.C++ 初始化类成员时,是按照声明的顺序初始化的,
而不是按照出现在初始化列表中的顺序;
初始化列表的顺序要跟你在类声明的顺序要一致。

38.必须定义拷贝构造函数的情况:
有的类有一个数据成员是指针,
或者是有成员表示在构造函数中分配的其他资源,
这两种情况下都必须定义拷贝构造函数。
显然,以下情况都会调用拷贝构造函数:
(1)一个对象以值传递的方式传入函数体
(2)一个对象以值传递的方式从函数返回
(3)一个对象需要通过另外一个对象进行初始化。

39.友元函数和静态成员函数都没有this指针;
初始化是赋一个初始值,而定义是分配内存。

40.struct说明
C++ 中的 struct 对 C 中的 struct 进行了扩充,
它已经不再只是一个包含不同数据类型的数据结构。
struct 能包含成员函数吗? 能!
struct 能继承吗? 能!!
struct 能实现多态吗? 能!!!
那它和 class 还能有什么区别?
最本质的一个区别就是默认的访问控制,体现在两个方面:
默认的继承访问权限和数据访问控制:
struct是public的,class是private的。

41.不可重载的运算符:

.:成员访问运算符
.*, ->*:成员指针访问运算符
:::域运算符
sizeof:长度运算符
?::条件运算符
#: 预处理符号

42.基类中定义纯虚函数:

virtual void funtional() = 0;

在有动态分配堆上内存的时候,析构函数必须是虚函数,但没有必要是纯虚的;
友元不是成员函数,只有成员函数才可以是虚的,因此友元不能是虚拟函数。
析构函数应当是虚函数,将调用相应对象类型的析构函数。
构造函数不能是虚函数;析构函数应当是虚函数除非类不用做基类;

43.当基类中没有定义虚函数时,其长度=数据成员长度;
派生类长度=自身数据成员长度+基类继承的数据成员长度;

当基类中定义虚函数后,其长度=数据成员长度+虚函数表的地址长度;
派生类长度=自身数据成员长度+基类继承的数据成员长度+虚函数表的地址长度。

包含一个虚函数和几个虚函数的类的长度增量为0。
含有虚函数的类只是增加了一个指针用于存储虚函数表的首地址。
派生类与基类同名的虚函数在VTABLE中有相同的索引号(或序号)。

多态的必须要求:
a.要有继承
b.要有虚函数重写
c.父类指针(引用)指向子类对象

44.读写文件

ofstream outfile;//写模式打开文件
outfile.open("file.dat", ios::out | ios::trunc );//截断式写入
outfile << data << endl;

fstream  afile;
afile.open("file.dat", ios::out | ios::in );//读写
//第一个参数是位置和名称,第二个为具体模式参数

ifstream infile; //以度模式打开
infile.open("afile.dat");  
infile >> data;//读取数据
infile.close();//关闭文件

45.文件位置指针

// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg( n );
 
// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg( n, ios::cur );
 
// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg( n, ios::end );
 
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );

46.复制文件test.txt到test1.txt

void file_copy(void)
{
    char data[100];
    ifstream infile;
    ofstream outfile;
    infile.open("test.txt");
    outfile.open("test_1.txt");//分别打开两个文件
    cout << "copy from test.txt to test_1.txt" << endl;
    while (!infile.eof())//判断到达文件尾条件
    {
        infile >> data;//读入数组
        cout << data << endl;
        outfile << data << endl;//将数组写入文件
    }
    infile.close();//分别关闭文件对象
    outfile.close();
}

47.git中文文件乱码问题

$ git config --global core.quotepath false

48.关于 cin.ignore()
完整版本是 cin.ignore(int n, char a),
从输入流 (cin) 中提取字符,提取的字符被忽略 (ignore),不被使用。
每抛弃一个字符,它都要计数和比较字符:如果计数值达到 n 或者被抛弃的字符是 a,
则 cin.ignore()函数执行终止;否则,它继续等待。
它的一个常用功能就是用来清除以回车结束的输入缓冲区的内容,
消除上一次输入对下一次输入的影响。比如可以这么用:
cin.ignore(1024,’\n’),
通常把第一个参数设置得足够大,这样实际上总是只有第二个参数 \n 起作用,
所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。

49.字符串的处理

getline(cin,str);//更安全简单
cin.getline(char*, int a);

50.异常处理:

#include <iostream>
using namespace std;
 
double division(int a, int b)
{
   if( b == 0 )
   {
      throw "Division by zero condition!";
   }
   return (a/b);
}
 
int main ()
{
   int x = 50;
   int y = 0;
   double z = 0;
 
   try {
     z = division(x, y);
     cout << z << endl;
   }catch (const char* msg) //捕获异常
   {
     cerr << msg << endl;//错误信息输出
   }
 
   return 0;
}

51.错误捕获示例:

#include <iostream>
#include <exception>
using namespace std;
 
struct MyException : public exception
{
  const char * what () const throw ()
  //what()是异常类提供的一个公共方法,已被所有子异常类重载,将返回异常产生的原因
  //const throw() 不是函数,叫异常规格说明,表示what函数可抛出异常的类型,
  //类型说明放到 () 里,这里面没有类型,就是声明这函数不抛出异常,
  //通常函数不写后面的就表示函数可以抛出任何类型的异常
  {
    return "C++ Exception";
  }
};
 
int main()
{
  try
  {
    throw MyException();
  }
  catch(MyException& e)
  {
    std::cout << "MyException caught" << std::endl;
    std::cout << e.what() << std::endl;
  }
  catch(std::exception& e)
  {
    //其他的错误
  }
}

52.C++11初始化列表

valarry<double> V2(10,8)
//含有八个double,每个设置为10
valarry<int> V3={20,32,23,54};
//C++11初始化列表

53.C++成员初始化列表:
只有构造函数可以使用初始化列表语法;
引用数据成员与const数据成员必须使用这种语法,才能在创建时初始化;
其中变量的初始化的顺序,以声明中的顺序为准,再次强调。

54.通过把类成员函数声明为const 以表明它们不修改类对象。
任何不会修改数据成员的函数都应该声明为const类型。
如果在编写const成员函数时,不慎修改了数据成员,
或者调用了其它非const成员函数,编译器将指出错误,
这样做的好处是提高程序了的健壮性。

55.捕获任何异常使用省略号:

try
{
   // 保护代码
}catch(...)//所有异常
{
  // 能处理任何异常的代码
}

56.二维数组内存分配:

int **array;
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int [n]  ;
}
//释放
for( int i=0; i<m; i++ )
{
    delete [] arrar[i];
}
delete [] array;
例如:P[4][8]动态数组:
#include <iostream>
using namespace std;
 
int main()
{
    int **p;   
    int i,j;   //p[4][8] 
    //开始分配4行8列的二维数据   
    p = new int *[4];
    for(i=0;i<4;i++){
        p[i]=new int [8];
    }
 
    for(i=0; i<4; i++){
        for(j=0; j<8; j++){
            p[i][j] = j*i;
        }
    }   
    //打印数据   
    for(i=0; i<4; i++){
        for(j=0; j<8; j++)     
        {   
            if(j==0) cout<<endl;//每一行换行   
            cout<<p[i][j]<<"\t";   
        }
    }   
    //开始释放申请的堆   
    for(i=0; i<4; i++){
        delete [] p[i];   
    }
    delete [] p;   
    return 0;
}
P[4][8]输出结果:
0 0 0 0 0 0 0 0 
0 1 2 3 4 5 6 7 
0 2 4 6 8 10  12  14  
0 3 6 9 12  15  18  21

57.三维数组模型:

int ***array;
// 假定数组第一维为 m, 第二维为 n, 第三维为h
// 动态分配空间
array = new int **[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int *[n];
    for( int j=0; j<n; j++ )
    {
        array[i][j] = new int [h];
    }
}
//释放
for( int i=0; i<m; i++ )
{
    for( int j=0; j<n; j++ )
    {
        delete array[i][j];
    }
    delete array[i];
}
delete [] array;
三维数组实例:
#include <iostream>
using namespace std;

int main()
{
    int i,j,k;   // p[2][3][4]

    int ***p;
    p = new int **[2];
    for(i=0; i<2; i++)
    {
        p[i]=new int *[3];
        for(j=0; j<3; j++)
            p[i][j]=new int[4];
    }

    //输出 p[i][j][k] 三维数据
    for(i=0; i<2; i++)
    {
        for(j=0; j<3; j++)
        {
            for(k=0;k<4;k++)
            {
                p[i][j][k]=i+j+k;
                cout<<p[i][j][k]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }

    // 释放内存
    for(i=0; i<2; i++)
    {
        for(j=0; j<3; j++)
        {
            delete [] p[i][j];
        }
    }
    for(i=0; i<2; i++)
    {
        delete [] p[i];
    }
    delete [] p;//单独删除最外层指针
    return 0;
}
综上,P[2][3][4]输出结果为:
0 1 2 3 
1 2 3 4 
2 3 4 5 

1 2 3 4 
2 3 4 5 
3 4 5 6 

58.动态内存实现链表数组:

#include <iostream>
#include <cstdio>

using namespace std;

struct node()
{//链表的节点
      int data;//数据
      int num;//节点编号
      struct node *next;//指向下一个节点
};

int main()
{
    struct node *head/*头节点*/, *p, *q;
    head=NULL;
    p=NULL;
    q=new node;
    q->next=NULL;
    q->num=1;
    int a=-1;
    cout<<"请输入第1个数字:";
    cin>>a;
    q->data=a;
    head=q;
    while (a!=0)
    {
         p=q;
         q=new node;
         q->next=NULL;
         p->next=q;
         q->num=p->num+1;
         cout<<"请输入第"<<q->num<<"个数字:";
         cin>>a;
         q->data=a;
    }

    //前面都是输入,这以下都是输出

    q=head;
    p=NULL;
    while (q->data!=0)
    {
         printf("%d %d\n",q->num,q->data);
         q=q->next;
    }
    
    //释放内存

    q=head;
    p=q;
    while(q->next!=NULL)
    {
        p=q->next;
        delete []q;
        q = p;  
    }
    return 0;
}

59.typenamey用法的特别之处:
typedef typename T::LengthType LengthType;
告诉 c++ 编译器,typename 后面的字符串为一个类型名称,
而不是成员函数或者成员变量,这个时候如果前面没有 typename,
编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称
(静态数据成员或者静态函数),所以编译不能够通过。

60.行号、文件名、日期和世界的宏调用:

__LINE__//当前行号
__FILE__//文件名和目录
__DATE__//month/day/year日期
__TIME__//hour:minute:second时间

61.注册信号SIGINT和信号处理程序

语法:int raise (signal sig);//sig是要发送的信号的编号,
//包括SIGINT、SIGABRT、SIGFPE、SIGILL、SIGSEGV、SIGTERM、SIGHUP
示例:
void signalHandler( int signum ){exit(signum);}
signal(SIGINT, signalHandler);
if( i == 3 ){raise( SIGINT);}//i=3则产生信号

62.C++多线程——Linux模块

创建POSIX线程:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
//thread是指向线程标示符指针
//attr是不透明属性对象,可被用来设置线程属性。可指定线程属性对象,也可使用默认值NULL
//start_routine是线程运行函数起始地址,一旦创建就会执行
//arg是运行函数参数,它必须通过把“引用作为指针”强制转换为“void类型”的方式进行传递。如果没有传递参数,则使用 NULL。
注意:创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。

终止线程:

#include <pthread.h>
pthread_exit (status)//显式地退出,通常为线程工作结束后被调用

示例1:

#include <iostream>
// 必须的头文件
#include <pthread.h>
 
using namespace std;
 
#define NUM_THREADS 5
 
// 线程的运行函数
void* say_hello(void* args)
{
    cout << "Hello Runoob!" << endl;
    return 0;
}
 
int main()
{
    // 定义线程的 id 变量,多个变量使用数组
    pthread_t tids[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; ++i)
    {
        //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
        int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
        if (ret != 0)//此处返回0是正常,不为0则创建失败
        {
           cout << "pthread_create error: error_code=" << ret << endl;
        }
    }
    //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
    pthread_exit(NULL);
}

示例2:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 3

struct thread_data
{
    int thread_id;
    char *message;
};

void *PrintHello(void *threadarg)
{
    struct thread_data *my_data;

    my_data = (struct thread_data *) threadarg;

    cout << "Thread ID : " << my_data->thread_id;
    cout << " Message : " << my_data->message << endl;

    pthread_exit(nullptr);
}

int main()
{
    pthread_t threads[NUM_THREADS];
    struct thread_data td[NUM_THREADS];
    int rc, i;

    for (i = 0; i < NUM_THREADS; i++)
    {
        cout << "main() : creating thread, " << i << endl;
        td[i].thread_id = i;
        td[i].message = (char *) "This is message";
        rc = pthread_create(&threads[i], nullptr, PrintHello, (void *) &td[i]);
        if (rc)
        {
            cout << "Error:unable to create thread," << rc << endl;
            exit(-1);
        }
    }
    pthread_exit(nullptr);
}


连接和分离线程:
pthread_join() 子程序阻碍调用程序,直到指定的 threadid 线程终止为止。
当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或
可分离的(detached)。只有创建时定义为可连接的线程才可以被连接;
如果线程创建时被定义为可分离的,则它永远也不能被连接。
语法:

pthread_join (threadid, status) 
pthread_detach (threadid) 
示例:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
 
using namespace std;
 
#define NUM_THREADS     5
 
void *wait(void *t)
{
   int i;
   long tid;
 
   tid = (long)t;
 
   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}
 
int main ()
{
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;
 
   // 初始化并设置线程为可连接的(joinable)
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
   for( i=0; i < NUM_THREADS; i++ ){
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, wait, (void *)&i );
      if (rc){
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
 
   // 删除属性,并等待其他线程
   pthread_attr_destroy(&attr);
   for( i=0; i < NUM_THREADS; i++ ){
      rc = pthread_join(threads[i], &status);
      if (rc){
         cout << "Error:unable to join," << rc << endl;
         exit(-1);
      }
      cout << "Main: completed thread id :" << i ;
      cout << "  exiting with status :" << status << endl;
   }
 
   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

63.C++11大括号初始化器

int *arr=new int[4]{1,2,3,4};//new也可用
Stump s1{12,21.1};//类对象初始化
vector <int> name{10};//参数
double total= sum({2.5,3.1,4});//可作为参数

64.Lambda表达式

[=,&]->返回值{a};
//按值访问作用域内的所有动态变量,按引用访问所有动态变量

65.关于操作符重载的编译器代换:

T1=T2+T3将被编译器解读为:
T1=T2.operator+(T3);//成员函数重载
T1=oprator+(T2,T3)//使用友元实现才承载
同理,ostream & operator<<(ostream &,const Time &);
将cout<<trip;解读为:operator(cout,trip)

66.智能指针绑定删除器
unique_ptr在编译时绑定删除器,避免间接调用删除器的运行时开销;
shared_ptr在运行时绑定删除器,使用户重载删除器更方便

67.大小端,所见所得是大端,反向是小端;

大端多:C52、JAVA和网络,
默认小端多:intelX86、Windows10、C++编译器、Mac

0x12345678,为方便说明,这里采用16进制表示。
这个数在不同字节顺序存储的CPU中储存顺序如下:
0x12345678 16进制,两个数就是一字节
高有效字节——>低有效字节: 12 34 56 78
低地址位 高低址位

大端: 12  34  56  78
小端: 78  56  34  12

判断代码:

#include
 <iostream> 
 
using namespace std;
 
typedef unsignedint UINT;
typedef unsignedchar UCHAR;
 
int main()
{
    UINT i=0x12345678;
    cout<<hex<<i<<endl;
    UCHAR *p
 = (UCHAR*)&i;         //将i的地址传给数组指针p,实际上p指向的地址是i在内存中存储的第一个字节,大端就是0x12,小端就是0x78
    if((*p==0x78)&(*(p+1)==0x56))       
        cout<<"小端"<<endl;
    else if((*p==0x12)&(*(p+1)==0x34))
        cout<<"大端"<<endl;
    else
        cout<<"未定义骚操作";
    return 0;
}

转换代码:

#include
 <iostream>
 
using namespace std;
 
typedef unsignedint UINT;
typedef unsignedchar UCHAR;
 
int main()
{
    UINT i=0x12345678;
    cout<<hex<<i<<endl;
    UCHAR *p
 = (UCHAR*)&i;
    UINT num,num1,num2,num3,num4;
    num1=(UINT)(*p)<<24;
    num2=((UINT)*(p+1))<<16;
    num3=((UINT)*(p+2))<<8;
    num4=((UINT)*(p+3));
    num=num1+num2+num3+num4;
 
    cout<<"num1:"<<hex<<num1<<endl;    //看num1的16进制表示,下同
    cout<<"num2:"<<hex<<num2<<endl;
    cout<<"num3:"<<hex<<num3<<endl;
    cout<<"num4:"<<hex<<num4<<endl;
    cout<<"num:"<<hex<<num<<endl;
 
    unsignedchar *q
 = (unsigned char*)&num;
    if((*q==0x78)&(*(q+1)==0x56))         
        cout<<"小端"<<endl;
    else if((*q==0x12)&(*(q+1)==0x34))
        cout<<"大端"<<endl;
    else
        cout<<"未定义骚操作";
    return 0;
}

专业级做法:

bool is_big_endian()
{
  unsigned short test = 0x1234;
  if(*( (unsigned char*) &test ) == 0x12)
    return true;
  else
    return false;
}
int big_endian_string_to_int(const string& str)
{
  if (str.length() <=0)
  {
    return -1;
  }
  int a=0;
  int i=0;
 
  a+= str[i];
  while (++i < str.length())
  {
    a=a<<8;
    a += str[i];
  }
  a += str[i];
  
  return a;
}
int web_string_to_int(const char* array,const unsigned len)
{
  int a = 0;
  string str(array,array+len);
 
  if (is_big_endian()) //大端机
  {
    return big_endian_string_to_int(str);
  }
  else // 小端机转换为整数
  {
    reverse(str.begin(),str.end());
    return big_endian_string_to_int(str);
  }
  return a;
}


int main(int, char *[])
{
  
  char a[4]={0x12,0x34,0x56};
  cout<<::hex<<web_string_to_int(a,3)<<endl;
  
 
  return 0;
};

68.二维数组申请内存

int **a=new int *[10];
  for(i=0;i<10;i++)
    a[i]=new int[10];

69.判断程序由C/C++编译或引用

//该语句的目的是告诉编译器f()是C连接的,
//函数f是采用C语言方式链接的,应该在库中找名字_f而不是找_f_int_char
//这样C++就不会转换函数名。
extern "C"{
 float f(int a,char b);
 //其他函数
 }
//或者写成
extern "c"
{	
	#include "Myheader.h"
	//其他C头文件
}

//通知C++使用了c代码
#ifdef _cplusplus
extern "C"
{
	#endif
   //具体的代码
	#ifdef _cplusplus
}
#endif

具体示例:

#include<iostream>
int main()
{
#ifdef __cplusplus
    std::cout<<"Using c++!";
#else
    std::cout<<"Using c!";
#endif
    return 0;
}

猜你喜欢

转载自blog.csdn.net/enochhugh/article/details/83552176
cpp
今日推荐