六:引用和函数参数的传递
1:什么是引用
引用就好比是我们给变量起的一个别名。变量对应于某个内存地址,如果我们给变量起一个别名,就相当于变量和引用均对应到同一个内存地址。
类型名 &引用名 = 同类型的某变量名
int oneInt;//定义一个整型变量
int &name1 = oneInt;//name1就是一个引用,就是oneInt的别名,它的类型是int &型。
当我们声明引用后,系统并不为name1分配空间,name1和oneInt对应的是同一个地址,于是可以相互赋值。
当我们在引用时,变量已经进行初始化。系统会自动将变量初始化为0,不能出现空引用或者是声明引用的引用。引用名必须是一个合法的标识符。在定义引用的时候需要进行初始化。同一个变量的引用可以有多个。
2:常引用和普通引用
int oneInt;
const int &name1=oneInt;//定义了name1,它的类型是const int &。
常引用和普通引用的区别:
常引用:不能修改引用的变量值。
普通引用:可以修改引用的变量值。
代码示例
#include <iostream> using namespace std; /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char** argv) { int oneInt = 1;//定义一个整型变量 int & ref = oneInt;//普通引用 ref是oneInt的引用,是int & 类型 const int & refc =oneInt;// 常饮引用 refc是oneInt的普通引用 ref=2;//修改ref的值,此时ontInt的值也被修改为2 cout<<"ontInt="<<oneInt<<","<<"ref="<<ref<<endl; cout<<"refc="<<refc<<endl;//refc输出的是2,oneInt被普通引用做出了修改 oneInt=3;//ref被修改为3 cout<<"ref="<<ref<<endl; cout<<"refc="<<refc<<endl;//ref和refc均输出为3 int & refd = ref;//refd是ref的的引用,属于引用的引用,refd和ref都是oneInt的引用 cout<<"refd="<<refd<<endl; /*refc=4; cout<<"refc="<<refc<<endl; ref是常引用,不能对引用的变量值进行修改 */ return 0; }
运行结果
引用运用到函数中, 既可以当作函数的参数,也可以作为函数的返回值。
数据类型 & 函数名(参数列表);
代码举例
#include <iostream> using namespace std; int oneX = 10; int oneY =100; int & refValue(int & x) { return x; } int main() { refValue(oneX)=20;//返回值是引用 cout<<"oneX="<<oneX<<endl;//输出20 refValue(oneY)= 200; cout<<"oneY="<<oneY<<endl;//输出200 }
七:const 与指针共同使用
在C++中,使用const 限定访问权限,可以告诉编译器,所修饰的量是不能改变的,也就是不能作为左值使用。
在程序中使用指针,涉及有两个量:指针本身和指针所指向的内容。
当const 和指针共同使用时,书写位置不同,含义不同。
const修改指针变量时,基本含义:
唯一的const 位于 * 左边,表示指针所指数据时常量,数据不能通过本指针修改;
唯一的const 位于 * 右边,表示指针本身就是常量,不能让该指针指向其他内存地址;
* 左右各有一个const时,表示指针和指针所指的数据都是常量,都是不能被修改的。
代码示例
#include<iostream> using namespace std; int main() { int a1=3;//普通变量,a1的值可被修改 const int a2=a1;//数据是常量,数据不能通过本指针进行修改,a2的值不能被修改 int * a3=&a1;//普通指针指向普通变量,*a3可以被修改值 const int *a4=&a1;//数据时常量,a4的值不能被修改 int * const a5=&a1;//指针时常量,不能修改指针,到那时a5的值可以被修改 int const * const a6=&a1;//数据是常量,指针也是常量 const int * const a7=&a1;//数据是常量,指针也是常量 }
const 修饰规则:如果const是本行第一个标识符,则修饰右侧的内容;其余情况下const 修饰其左侧的内容。
八:函数重载
在程序设计中,通过一个函数名形参和返回值不一样,可以减少命名空间。
在面向对象程序设计中,是允许函数重载的。函数重载是指在程序的同一范围内声明几个功能类似的同名函数。使用同一个函数名作为功能一样的函数的函数名,并分别为其编写函数体,可实现各自的功能。
代码示例
//求两者中较大值的函数重载 int bigger(int x,int y) { if(x>y) return x; else return y; } float bigger(float x,flaot y) { if(x>y) return x; else return y; } double bigger(float x,flaot y) { if(x>y) return x; else return y; } //计算一个数值的绝对值的函数,也可以统一命名 int abc(int n) { return (n<0 ? -n:n); } float abc(float f) { if(f<0) f=-f; return f; } double abc(double m) { if(m<0) m=-m; return m; }
函数重载必须满足的条件:
参数表中对应的参数类型不同
参数表中参数个数不同
错误的重载方式:
void print(double);
void print(double &);//这两个函数,都可以使用一个对象作为实参,所以编译去区分不了调用的函数版本
float add(int,float);//整数和浮点相加,返回值是浮点
int add(int,float);//编译阶段,程序还没有执行,确定不了类型,因此编译器不能根据返回值确定应该调用那个函数。
注意事项
在两个函数同名但是参数个数不同,但是其中参数多的那个函数参数又可以读取默认值的情况下,可能会引发二义性:
假如我们定义了重载函数Sum(
int Sum(int a,int b, int c=0);
int Sum(int a,int b);
int Sum(1,2);//调用该函数会出错,因为编译器不知道应该以(1,2,0)作为参数去调用Sum()函数,还是以(1,2)作为参数去调用Sum()函数。
九:指针和动态内存分配
1:指针
指针变量中保存的是一个地址,有时也称指针指向一个地址。
我们来看一个例子:
int a=100,*p = &a;
这里,&是取地址符号,p是一个指针,指向整型变量a,那么p中就保存a的地址,p指向地址中的值是100,但不是p=100。 这里我们要区分地址和地址中的值,指针变量的值就是地址值,C++中指针变量是个变量,而不是地址。
2:动态分配
在C++程序编译的过程中进行静态内存分配,在程序执行过程中采用动态内存分配。
p = new T;
//T是任意类型名,p是类型为T*的指针。这样的语句会动态分配出一片大小为sizeof(T)的字节的内存空间(Sizeof是C/C++中的关键字,它是一个运算符,其作用是取得一个对象(数据类型或者数据对象)的长度(即占用内存的大小,以byte为单位),并且会将该内存空间的起始地址赋值给指针p;
int *p = new int;//*的作用是取内容,在运行过程中会动态分配一个内存空间,p指向这个空间的首地址,然后通过指针p可以读写该地址的内存空间。
* p =5;//表示向该空间中存入数值5。
动态分配一个整形数组
int *pArray;//指向数组的指针 int i=5; pArray=new int[i*20];//表示分配了100个元素的整型数组 pArray[0]=20;//表示数组的第一个值,数组的下标都是从零开始的的 pArray[99]=30;//数组的最后一个值
当我们在使用new运算符动态申请空间时,运行完毕后需要释放。C++中提供了一个用来释放动态分配内存空间的运算符 delete
int *q= new int; *q=8; cout<<*q<<endl; delete q;//q指向动态分配的空间 //假如我们使用 new 运算符动态分配一个数组,那么在释放数组时的语句如下 delete []指针;
需要注意的是,当我们使用delete 释放掉指针所指的空间后,如果再访问这个空间,也会得不到想要的结果。
十:用string 对象处理字符串
string是一个类,这个类型的变量是“string对象“,在接下的学习中,我们会更深入的介绍它。我们先可以把它理解为一个数据类型。也就是string类的对象,一个string类的对象可以用来保存一个具体的字符串。
不论字符串的长度如何,再同一种系统下,保存字符串的内存首地址是一样长的,也就是一个 string对象大小是固定的。
在程序中使用 string 对象时,必须在程序的包含头文件 string ,也就是再程序的最前面加上:#include <string>
1:string 对象的声明
string 变量名;
对string对象的初始化
#include <iostream> #include <string>//头文件 using namespace std; string str1;//声明string对象str1,值为空 string subject="math";//声明string对象 subject,并使用字符串常量进行初始化 string str2=subject;//声明string 对象str2 int main(int argc, char** argv) { cout<<"str1="<<str1<<",subject="<<subject<<endl; cout<<"str2="<<str2<<endl; return 0; }
此外,还可以使用字符数组对string 变量进行初始化:
char name[]="程序设计";
stirng c1=name;
还可以声明一个string 对象数组,也就是数组中每个元素都是字符串:
string subject[]={"Math","Chinese","English"};
cout<<subject[1]<<endl;//输出为 Chines
cout<<sizeof(subject)/sizeof(stirng)<<endl;//输出数组元素的个数:sizeof(subject)是整个数组占用的空间大小,sizeof(string)是每个 string 对象的大小。
2:string对象的操作和使用
string 对象可以用cin 和 cout 进行输入和输出,也可以相互之间互赋值,或者是用字符串常量和字符数组的名字进行赋值。
代码举例
int main() { string s1,s2; s1 ="C++程序设计"; s2=s1; string s3; cout<<"s3="<<s3<<endl; s3=s1+s2; cout<<"这时s3="<<s3<<endl; s3 +="de"; cout<<"这里s3=" <<s3<<endl; bool b=s1<s3; cout<<"bool="<<b<<endl;//已声明s1<s3,故输出bool是true,也就是1 char c=s1[2];//这里把s2看作一个数组,数组下标从0开始,则数组“c++程序设计”中下标为2的是“+” cout<<"c="<<c<<endl; cout<<"数组s1="<<s1<<endl; char arrstr[]="Hello"; s3=s1+arrstr;//+表示连接符 cout<<s3<<endl; return 0; }
运行结果
3:string 对象用法示例
string 类中为字符串提供了一些 成员函数,利用这些成员函数可以方便实现一些功能,调用方式:
string 对象名. 成员函数名(参数);
一些string类中常用的成员函数:
代码示例1
#include <iostream> #include <string.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ using namespace std; int main(int argc, char** argv) { string str; if(str.empty()) cout<<"str is null"<<",length="<<str.length()<<endl; else cout<<"str is not null"<<endl; str=str.append("abcdefg"); cout<<"str is "<<str<<",size="<<str.size()<<endl; const char*p=str.c_str(); cout<<"p="<<p<<endl; cout<<"find:"<<str.find("de",0)<<endl;//从零开始找,查找成功 cout<<"find:"<<str.find("de",4)<<endl;//从4开始查找,查找失败 ,下标为4是字母e,不能查找出de。只要是在d前面的字母开始查找,也就是在0--3这个范围进行查找均可查找成功,若超过这个范围就查找失败 。 string str1=str.insert(1,"123");//在下标1前面插入 ,也就是在下标为1 的 b前面插入 cout<<str1<<endl; return 0; }
运行结果
示例2
#include <iostream> #include <cstring> //在该程序中我们用到了strcpy()函数,因此它包含在头文件 cstring中,因此要在程序中使用“#include <cstring> ” using namespace std; int main() { string s1="c++程序设计";//一个汉字的长度是2 string s2="c++语言" ; string s3=s1+s2; string s4; s4=s1.append(s2);//将s1连接到s2结尾处 if(s3==s4)cout<<"结果相同"<<endl; else cout<<"结果不相同 "<<endl; int size=s1.size(); int length=s1.length(); cout<<"s1 size="<<s1.size()<<",s1 length="<<s1.length()<<endl;//这里 s1 的长度是将 s1和s2连接到一块的总长度,函数size() 和 length()都是返回数组长度 s1[0]='a';//此时 s1是“a++程序设计”,将s1的第一个字母改为a ,则输出的s1就不再是c++程序设计 string s5=s1.substr(3,4);//表示返回从第3个字符,长度为4的子串赋值给s5 ,也就是 程序 char str[20];//声明一个数组str,长度是20 strcpy(str,s5.c_str());//将s5中的字符串复制到str中(C++提供strcpy此类函数,为了对指针操作更加安全,避免内存泄露等异常状态的发生。) cout<<"s5="<<s5<<endl; cout<<"str="<<str<<endl; cout<<"s1="<<s1<<",s2="<<s2<<endl; cout<<"s4="<<s4<<endl; s1.swap(s2);//函数swap()表示交换,即将数组 s1和数组s2 进行交换 cout<<"此时s1="<<s1<<",s2="<<s2<<endl; cout<<"str="<<str<<endl; cout<<"s2=" <<s2<<endl; cout<<s2.find(str)<<endl; //表示在s2中查找str,str代表的是 程序,也就是说在s2数组中查找 程序 return 0; }
运行结果
总结
以上就是这篇文章给大家带来的知识点了,看到这里相信多多少少都会有些收获,接下来的文章还会给大家带来更多有关c++的东西,期待和大家进行交流。笔耕不息,生命不止~