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*)#
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;
}