C++学习——共勉(一)(2)

简介: C++学习——共勉(一)(2)

六:引用和函数参数的传递


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;
}


运行结果


1a199abab8c640469e1da691ddef3c56.png

引用运用到函数中, 既可以当作函数的参数,也可以作为函数的返回值。

数据类型 & 函数名(参数列表);


代码举例


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

23201e9ae5514698b611b56905e98cd6.png


此外,还可以使用字符数组对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;
} 


运行结果


3de3bf680877454baed4be3511141116.png


3:string 对象用法示例


string 类中为字符串提供了一些 成员函数,利用这些成员函数可以方便实现一些功能,调用方式:


string 对象名. 成员函数名(参数);


一些string类中常用的成员函数:

1675930376522.png


代码示例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;
}


运行结果


79c1f51f81b649fba5875fdf5b9c6e9d.png


示例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;
}


运行结果


464748b60154467c92b1457ea264b2c6.png


总结


以上就是这篇文章给大家带来的知识点了,看到这里相信多多少少都会有些收获,接下来的文章还会给大家带来更多有关c++的东西,期待和大家进行交流。笔耕不息,生命不止~


相关文章
|
23小时前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
10 4
2023/11/10学习记录-C/C++对称分组加密DES
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
89 0
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
26 1
|
5月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
5月前
|
人工智能 分布式计算 Java
【C++入门 一 】学习C++背景、开启C++奇妙之旅
【C++入门 一 】学习C++背景、开启C++奇妙之旅
|
5月前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
|
5月前
|
小程序 C++
【C++入门 二 】学习使用C++命名空间及其展开
【C++入门 二 】学习使用C++命名空间及其展开
|
5月前
|
C++
C++基础知识(四:类的学习)
类指的就是对同一类对象,把所有的属性都封装起来,你也可以把类看成一个高级版的结构体。
|
5月前
|
算法 C++ 容器