C++入门1
C++输入输出
注意cin输入字符串时,以空格结束
#include<iostream>
using namespace std;
int main(){
char str[128]{};
cin>>str; //输入hello world
cout<<str;//输出hello
return 0;
}
所以用cin.getline(),该函数以回车结束
#include<iostream>
using namespace std;
int main(){
char str[128]{};
cin.getline(str,128); //输入hello world
cout<<str;//输出hello world
return 0;
}
该函数有三个参数,目标地址,字符个数,注意最后一个是’\0’,结束字符,默认是回车
cin.getline(str,128,‘#’);
getline也是string的一个函数,用法是针对字符串的。获得一行字符串,上文是针对字符数组的。用法又不同之处。
#include<iostream>
#include <string>
using namespace std;
int main() {
//char s[128] = {0};
//cin.getline(s, 12);
//cout << s << endl;
string s;
getline(cin, s);
cout << s;
return 0;
}
const和指针
const 在c和c++中的区别
在.c文件,虽然加const,但是编译时认为是变量,只是该值不可修改,所以不能定义固定大小数组,所以在c里面想要用真正的常量,可以用#define,定义宏,就可以定义固定大小的数组
int main(){
const int n=10;//虽然加const,但是编译时认为是变量,只是该值不可修改
//int ar[n]{1,2,3,4};//所以这里error
int* p=(int*)&n;
*p=100;//认为是变量,所以可以修改
printf("n=%d *p=%d\n",n,*p);//100 100
return 0;
}
在.cpp文件,在编译时认为是常量,只要不是取地址,遇见n就会用10替换
int main(){
const int n=10;//在编译时认为是常量,只要不是取地址,遇见n就会用个10替换
int ar[n]{1,2,3,4};//OK
int* p=(int*)&n;
*p=100;
printf("n=%d *p=%d\n",n,*p);//10 100
return 0;
}
c++编译时看到const就认为这是常量,对付常量的方式是将其替换,在编译的时候替换的,不是预编译,预编译对付的是宏
.cpp ==> .i ==> .s ==> .o/.obj ==> .exe
预编译 编译 汇编 链接
.o是二进制文件前面的是ASILL码文件
const 和指针关系
指针中有详细介绍: const与指针结合的三种作用
指针在赋值过程中,能力收缩是可以的,扩展是不行的,不安全
int main(){
int a{10},b{20};
int* ip1=&a;//*ip1=100;ip1=&b;
const int* ip2=&a;//*ip2=100 error ip2=&b OK
int const* ip3=&a; //*ip2=100 error ip2=&b OK
int* const ip4=&a;//ip4=&b error *ip4=100 OK
const int*const ip5=&a;//ip5=&b error *ip5=100 error
例子
int main(){
int a{10},b{20};
const int* p=&a;
//看下面四个式子那个不能编译通过
int* ip1=p;//error
const int* ip2=p; //OK
int* const ip3=p;//error
const int*const ip4=p;//OK
return 0;
int main(){
int a{10},b{20};
int*const p=&a;
//看下面四个式子那个不能编译通过
int* ip1=p;//OK ;ip1=&b,不会对p有影响,能力并没有扩展,所以下面三种都可以
const int* ip2=p; //OK
int* const ip3=p;//OK
const int*const ip4=p;//OK
return 0;
引用
引用的定义:类型&引用变量名称=变量名称;
这就是引用变量的定义。&和类型结合称之为引用符号,不是取地址的符,代表别名的意思。定义的时候必须初始化,没有空引用
int main(){
int a{10};
int& b=a;
int&&c=b;
}
没有二级引用,有二级指针
const 与&引用
普通引用只能引用普通变量,普通引用不能引用常变量,常引用是万能引用,常引用比较特殊,常引用可以引用普通变量,常引用可以引用常变量,也可以引用字面常量
如果希望形参的改变能改变实参,就用void func(int &a),如果不希望实参的改变影响实参,就用void func(const int&b)
int main(){
int a{10};
const int b{20};
//int&x=b;x+=100;//error
const int &x=b;//OK
//int tmp=b;
//const int&x=tmp;x的修改不能对b修改
const int&y=a;//ok y是a的别名,y只能读取a的值,不能通过y修改a的值
const int&z=10;
//int tmp=10;
//const int&z=tmp; 开辟了一个临时变量
}
当常引用在引用常量时,字面常量时会开辟一个临时空间,引用的是tmp,防止x的常性去掉后,会对b改变
void func(int x){}
void funb(int&b){}
void func(const int&b){
int x=b;
x+=10;
}
int main(){
int a=10;
funa(a);
funb(a);
func(a);
}
funa(a)其实就是把a赋值位x,x就是一个副本,x的改变不会影响a,funb(a)是a的别名,b的改变会影响a的值,func(a),b不能改变,但是可以再创建一个副本x
&引用的作用
当函数调用Swap函数时,a就是x的别名,b就是y的别名,点函数将a和b交换,实际上就是将x和y进行了交换
用指针实现Swap还需要防止空指针,野指针
void Sawp(int&a,int&b){
int tmp=a;
a=b;
b=tmp;
}
int main(){
int x=10,y=20;
Swap(x,y);
return 0;
对数组的引用
int (&x)[5]=ar;x是一个引用,对数组的引用,该数组的大小是5,每个数据是整型,x是ar的别名,先解释(),在从右向左解释,引用一个数组,该数组的大小是5,数组的元素是整型,ar符合这个要求,所以x即是ar的别名
int main(){
int a=10,b=20;
int ar[5]{1,2,3,4,5};
int (&x)[5] = ar;
x[0]=100;//等价ar[0]=100;
return 0;
int& cr[5];//error,看右边[5]是一个数组,需要空间,而&是别名,不需要空间,就产生了矛盾,从而我们不能定义数组,使数组的元素类型是引用
int main(){
int ar[5]{1,2,3,4,5};
sizeof(ar);//大小为20
int (&x)[5] = ar;//x是ar的别名
int (*p)[5] = &ar;//p指向了一个数组
int* s[5]={};//s是一个数组,里面的类型是指针
int& cr[5];//*******88error
return 0;
下面都能编译通过,p指向a的地址,将s1指向a的地址时,如果将s1指向b的地址,不会影响a
int main(){
int a=10,b=20;
int* const p=&a;
int*s1=p;
const int*s2=p;
int* const s3=p;
const int *const s4=p;
int&*s1//error 不能使指针指向别名,下面的前两个不能编译通过
int main(){
int a=10,b=20;
int* const p=&a;
//下面的前两个不能编译通过
int*&s1=p;
const int*&s2=p;
int* const &s3=p;
const int *const &s4=p;
对指针的引用
int*&sp=ip;是对指针的引用,sp就是ip的一个别名,ip是int*类型,所以sp就是整型指针类型的别名,对sp的操作就是对ip的操作
int main(){
int a=10,b=20;
int ar[5]{1,2,3,4,5};
int (&x)[5]=ar;
int*ip=&a;
int*&sp=ip;
*sp=100;//等价于*ip=100;
sp=&b//说明ip也指向b了
return 0;
}
引用与指针的区别
从语法层面
从语法规则上讲,指针变量存储某个实例(变量或对象)的地址;引用是某个实例的别名。
程序为指针变量分配内存区域;而不为引用分配内存区域
解引用是指针使用时要在前加“*”;引用可以直接使用。
指针变量的值可以发生改变,存储不同实例的地址;引用在定义时就被初始化,之后无法改变(不能是其他实例的引用)。
指针变量的值可以为空(NULL,nullptr);没有空引用。
指针变量作为形参时需要测试它的合法性(判空NULL);引用不需要判空;
对指针变量使用"sizeof"得到的是指针变量的大小。对引用变量使用"sizeof"得到的是变量的大小。
理论上指针的级数没有限制;但引用只有一级。即不存在引用的引用,但可以有指针的指针。
++引用与++指针效果不一样,要想一样,指针需要解引用
从汇编层面
在汇编层面引用实际上是一个指针,在语法层面引用是一个别名,引用在底层当做一个指针处理
lea的意思是取a的地址放在eax里,mov的意思是将eax的值赋值给p
int main(){
int a=10;
int&rb=1;
int*p=&a;
int x=0;
x=rb;
x=*p;
return 0;
}
底层引用的实现原理,就是一个const rb
new和delete
new关键字
内核:操作系统
栈区:函数的形参,非静态的局部变量,函数现场保护数据等等,栈是向下增长的。
共享库的内存映射区域:用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。
堆区:用于程序运行时动态内存分配,堆是可以上增长的。
数据段:存储全局数据和静态数据,分为.bss和.data。
代码段:可执行的程序(机器指令)和常量数据。
free()时会检查越界标记
new 不但可以动态申请内存空间,还可以拿括号的值初始化 new做了三件事
1 sizeof(int) 2 malloc 3 initvalue
malloc只能申请空间,不能初始化
ips ips都是在栈空间申请的变量,只有主程序结束才能回收,而他们各自申请的空间都在堆区
int main(){
int*ipa=(int*)malloc(sizeof(int));
int*ips=new int(10);
free(ipa);ipa=nullptr;
delete ips;ips=nullptr;
区别:
1、new/delete是C++中的运算符(关键字)。malloc / free是函数。
2、 malloc申请内存空间时,手动计算所需大小,new只需类型名,自动计算大小3、 malloc申请的内存空间不会初始化,new可以初始化;
4、malloc的返回值为void*,接收时必须强转,new不需要;
5、malloc申请内存空间失败时,返回的是NULL,使用时必须判空;
new申请内存空间失败时抛出异常,所以要有捕获异常处理程序;也可以不让其抛出异常
int main(){
int n=10;
cin>>n;
int*ipa=(int*)malloc(sizeof(int)*n);
int*ips=new int[n];//sizeof(int)*10;malloc;初始化为随机值
int*ips=new int[n]{1,2,3,4,5,6};
free(ipa);ipa=nullptr;
delete []ips;ips=nullptr;
return 0;
}
new函数方式使用
其实和malloc是一样的,需要强转
new关键字调用可以初始化值,而函数调用不具备初始化的能力,失败会抛出异常,出否明确不让其抛出异常
int main(){
int n = 10;
int*ipa=(int*)malloc(sizeof(int)*n);
if(ips==nullptr)return 1;
int *ipb = (int*)::operator new(sizeof(int)*n);
//if(ipb==nullptr)就会抛出异常
free(ipa);ipa=nullptr;
::operator delete(ipb);ipb=nullptr;
return 0;
}
可以不让其抛出异常,就可以用if判断空
int *ipb = (int*)::operator new(sizeof(int)*n,nothrow);
int*s=new(nothrow)int(10);
定位new
并不申请空间,而是对申请的空间进行初始化,只要有空间就可以初始化。new里面一旦放了指针,我们就认为是定位new
int main(){
int n = 10;
int* ipa =(int*)ma1loc(sizeof(int));
int* ipb = (int*)::operator new(sizeof(int) * n) ;
new(ipa) int(20);//对ipa指向的空间初始化为20
new(ipb) int[]{ 1,2,3,4};//初始化一组数据
free(ipa);
::operator de1ete(ipb) ;
return 0;
}
这里是小端存储,高地址存放高位数,低地址存放低位数
new与mallco的区别11点
1.new关键字 一个函数
2.new可以重载,malloc不可重载
3.new返回类型,不用强转,malloc需要强转
4.new自动计算类型大小
5.malloc只是申请空间,new不但申请空间还要调用构造函数
6.new申请空间失败会抛出异常,malloc失败返回空指针
7.new delete new[] delete[] malllc free
8.new可以按照函数方式调用,
9.定位new new§初始化空间
有空间不一定有对象,有对象一定有空间
10.内置类型可以混用,自己设计的类型,没有析构函数,也可以混用。一般不要说,
11.多态释放资源时。虚析构函数。
new可以进行函数重写的目的
delete的目的: