1,作用域运算符“::”
#include<iostream>
using namespace std;
int avar;
int main(){
int avar;
avar=25; //给局部变量赋值
::avar=10; //给全局变量赋值
cout<<"local avar="<<avar<<endl; //输出局部变量avar的值
cout<<"global avar="<<::avar<<endl; //输出全局变量avar的值
return 0;
}
2,无名联合
无名联合是c++中一种特殊联合,它在关键字union后面没有给出联合名,它可使一组数据成员共享同一内存地址。
union{
int i;
double d;
}x;
在此无名联合中,无名联合变量x中的整型成员i和双精度型d具有相同的存储地址。其访问方式如下:
x.i;
x.d;
3,运算符new和delete
①new用于内存分配的最基本形式:
指针变量名=new 类型
在程序运行的过程中,运算符new从称为堆的一块自由存储区中为程序分配一块与类型字节数相适应的内存空间,并将该块内存的首地址存于指针变量中。例如:
int *p; //定义一个整型指针p
p=new int; //new动态分配存放一个整数的空间,并将其首地址赋给指针变量p
运算符delete用于释放运算符new分配的存储空间。该运算符释放空间额基本形式为:
delete 指针变量名;
其中指针变量保存着new分配的内存的首地址。例如:
delete p;//将new动态分配内存空间释放(其首地址已存放在指针变量p中)
一个使用new和delete的简单例子
#include<iostream>
using namespace std;
int main(){
int *ptr; //定义一个整型指针变量ptr
ptr=new int;//动态分配一个整型存储空间,并将首地址赋给ptr
*ptr=10;
cout<<*ptr;
delete ptr;//释放指针ptr指向的存储空间
return 0;
}
程序运行结果为:
10
new和delete完成的功能类似于函数malloc和free,难道它有什么优点吗?
(1),使用malloc函数时必须使用sizeof函数计算所需的字节数,而new可以根据数据类型自动计算所需分配内存的大小,这样就减少了发生错误的可能性。
(2),new能够自动返回正确的指针类型,而不必像malloc函数那样,必须在程序中进行强制转换,才能返回正确的指针类型。
②new为数组动态分配内存空间
(1),例如:
int *pi=new int[10];
//这时new为具有10个数组元素的整型数组分配了内存空间,并将其首地址赋给了指针pi。
//同时注意new为多维数组分配空间时,必须提供所有维的大小,如下例:
int *pi=new int[2][3][4];
(2), new 可以为简单变量分配内存的同时,进行初始化。基本形式为:指针变量名=new 类型(初值);
#include<iostream>
using namespace std;
int main(){
int *p;
p=new int(99);//动态分配内存空间,并将99作为初始值赋给它
cout<<*p;
delete p;
return 0;
}
(3),释放动态分配的数组存储区时,可使用 delete []指针变量名;
(4),使用new动态分配内存时,如果没有足够的内存满足分配要求,则动态分配空间失败,有些编译系统将返回空指针NULL。因此可以对内存的动态分配是否成功进行检查。如下例:
#include<iostream>
using namespace std;
int main(){
int *p;
p=new int;
if(!p){
cout<<"allocation failure"<<endl;
return 1;
}
*p=20;
cout<<*P;
delete p;
return 0;
}
注意:
- 内存动态分配成功后不宜变动指针的值,否则在释放存储空间时会引起系统内存管理失败。
- 用 new 分配的存储空间不会自动释放,只能通过delete释放。因此,要适时释放动态分配的存储空间。
4,引用
(1)引用的概念
建立引用就是给变量起一个别名。当申明一个引用时,必须同时用另一个变量的名字来将它进行初始化,即申明它代表哪一个变量,是哪一个变量的别名。就如同一个人可能有三四个名字,但实际上就是同一个人,用这三四个人名所做的事情,其实就是一个人所做的事情。简单总结:对一个引用的所有操作,实际上都是对其所代表的变量的操作。申明引用格式如下:
类型 &引用名=已定义的变量名;
int i=5;
int &j=i;//申明j是一个整型变量的引用,用整型变量i对它进行初始化
上述的申明中“&”是引用申明符,此时并不代表取地址符。 对变量申明一个引用,并不另外开辟内存单元,变量i和引用j占用内存的同一位置。即 i、j同时变化
关于引用的几点说明:
- 1,除了用作函数的参数或返回类型外,在申明引用时,必须**立即对它进行初始化,不能申明完成后再赋值。
int i;
int &j;//错误,没有指定j代表哪个变量
j=i;
- 2,为引用提供的初始值,可以是一个变量或另一个引用。例如:
int i=5;
int &j1=i;
int &j2=j1;//声明j2是整型引用j1的引用(别名)
这样定义后,变量i有两个别名:j1和j2.
- 3,指针是通过地址间接访问某个变量,而引用是通过别名直接访问某个变量。每次使用引用时,可以不用书写间接运算符“ * ” ,故使用引用可以简化程序。下面是一个引用和指针使用方法的比较实例:
#include<iostream>
using namespace std;
int main(){
int i=15;
int *iptr=&i;//定义指针变量iptr,将变量i的地址赋给iptr
int &rptr=i;//声明变量i的引用
cout<<"i is"<<i<<endl;
cout<<"*iptr is"<<*iptr<<endl;
cout<<"rptr is"<<rptr<<endl;
i=29;
cout<<"After changing i to 29:"<<endl;
cout<<"i is"<<i<<endl;
cout<<"*iptr is"<<*iptr<<endl;
cout<<"rptr is"<<rptr<<endl;
return 0;
}
程序运行结果如下:
i is 15
*ptr is 15
rptr is 15
After changing i to 29:
i is 29
*ptr is 29
rptr is 29
从上面这个例子就可以很容易搞懂引用和指针了。
(2)引用作为函数参数
引用作为函数参数是c++提供引用的重要用途之一。大家可以回忆下在学习c 语言时写过的两数交换的程序,那时是用指针变量作为函数的参数,下面我们举一个引用作为函数参数的例子:
#include<iostream>
using namespace std;
void swap(int &m,int &n){//形参m和n是整型变量的引用
int temp;
temp=m;
m=n;
n=temp;
}
int main(){
int a=5,b=10;
cout<<"a="<<a<<" b="<<b<<endl;
swap(a,b);//实参a,b都是整型变量,可以通过引用来修改实参a和b的值
cout<<"a="<<a<<" b="<<b<<endl;
return 0;
}
//程序运行结果如下:
a=5 b=10
a=10 b=5
(3)使用引用返回函数值
使用引用可以返回函数的值,采用这种方法可以将该函数调用放在赋值运算符的左边。通过下面一个例子进行体悟:
#include<iostream>
using namespace std;
int a[]={1,3,5,7,9};
int &index(int);//申明函数返回一个整型类型的引用
int main(){
index(2)=25;//将函数调用放在赋值运算符的左边,等价于将a[2]赋值为25
cout<<index(2);//等价于输出数组元素a[2]的值
return 0;
}
int &index(int i){
return a[i];//定义函数返回一个整型类型的引用,等价于返回数组元素a[i]
}
程序运行结果为:
25