C++入门1(C++输入输出 引用 const与指针&引用 new和delete)

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的目的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值