重生之我要学C++第二天

哈喽,今天是我重生的第二天,今天我学习了c++的引用、auto关键字、内联函数、范围for。

目录

一.引用

二.auto关键字

三.内联函数

四.范围for


一.引用

定义:引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间。是C++基于C语言指针的概念新增加的概念,底层实现是依靠指针。
接下来通过代码来见识下引用
#include<iostream>
using namespace std;
int main()
{
	int a = 2;
	int& b = a;//b就是是a的引用
	return 0;
}

从引用的定义来看,引用是变量的一个别名,和它所引用的变量共用一块内存空间。

因此,当b++时,a的也将发生改变。

    b++;
	cout << a << endl;

a的值为以下运行结果

我们可以总结:变量的引用可以直接访问这个变量在内存中的空间。进而通过引用直接改变这个变量的值。而在C语言中,要想改变变量的值,就是使用指针,变量的指针就是变量的地址,可以通过这个变量的地址解引用改变这个变量。

#include<stdio.h>
int main()
{
	int a = 2;
	int* b = &a;//指针存储a的地址
	(*b)++;
	printf("%d", a);
	return 0;
}

由此可知,引用一级指针都可以改变变量的值

那我们就可以举一反三的知道:一级指针的引用二级指针都可以改变一级指针

C++引用特性
1. 引用在 定义时必须初始化
#include<iostream>
using namespace std;
int main()
{
	int& a;//a未初始化,不合法
	return 0;
}
2. 一个变量可以有多个引用,引用的引用指向的还是同一内存空间。
#include<iostream>
using namespace std;
int main()
{
	int a = 2;
	int& b = a;//a的三个引用b、c、d
	int& c = a;
	int& d = b;//引用的引用指向的还是同一内存空间
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
	return 0;
}

3. 引用一旦引用一个实体,再不能引用其他实体
#include<iostream>
using namespace std;
int main()
{
	int a = 2;
	int x = 3;
	int& b = a;//a的引用
	b = x;//a的引用无法修改,这句代码含义是赋值:a=3
	return 0;
}

引用的使用场景

一.传参

当我们要写两个整型的交换函数时,只能将形参写成一级指针的形式,通过指针来交换两变量的值,当有了引用后,也可以将引用作为形参,通过引用交换两个变量。这里体现了一级指针和引用的相同作用。只不过引用的使用更加简单明了。

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

在数据结构阶段,单链表的头插函数是这样写的

void PushHead(struct ListNode** pphead,int n)
{
    //创建新节点
    struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
    newnode->date=n;
    //链接新节点
    newnode->next=*pphead;
    *pphead=newnode;
}

在这里,要想改变链表的头节点指针,就需要用到二级指针。用引用同样可以做到

void PushHead(struct ListNode*& phead,int n)
{
    //创建新节点
    struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
    newnode->date=n;
    //链接新节点
    newnode->next=phead;
    phead=newnode;
}

体现了二级指针和一级指针的引用相同的作用。

二.做返回值

引用做返回值,可以通过函数返回函数内对象的引用来在函数外修改这个对象。

#include<iostream>
#include<assert.h>
using namespace std;
struct sequence
{
	int* a;
	int size;
	int capcity;
};
int& SearchModify(sequence* seq,int pos)//查找pos下标位置的数据并修改
{
	assert(pos < seq->size);
	return seq->a[pos];
}

可以查找

struct sequence s;
int x=SearchModify(&s, 2);//查找下标为2位置的值

可以修改

SearchModify(&s, 2) = 3;//修改下标为2位置的值为3
注意: 如果函数返回时,出了函数作用域,如果返回对象还在 ( 还没还给系统 ) ,则可以使用 引用返回,如果已经还给系统了,则必须使用传值返回。
#include<iostream>
using namespace std;
int& func()
{
	int n = 2;//n是局部变量,出函数将销毁
	n++;
	return n;//但是返回了n的引用,让函数外可以找到已经销毁的空间
}
int main()
{
	int& a = func();//a这块空间是非法的
	return 0;
}

可以修改代码使正确。

stactic int n=2;//静态变量,出作用域不销毁

二.auto关键字

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:
1. 类型难于拼写
2. 含义不明确导致容易出错
使用 auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导 auto 的实际类型 。因此 auto 并非是一种 类型 的声明,而是一个类型声明时的 占位符 ,编译器在编译 期会将 auto 替换为变量实际的类型
auto会自动识别类型:
#include<iostream>
using namespace std;
int main()
{
	auto a = 3;//int
	auto b = 2.7;//double
	auto c = 'm';//char
	auto s = "ssacs";//string
    auto a = &a;//注意:auto与auto*没有区别
    auto* b = &a;
    auto& c = a;//引用必须auto&
	return 0;
}

 注意:auto类型不能用来做形参,不能用来声明数组。

三.内联函数

概念 :以 inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调 用 建立栈帧的开销 ,内联函数提升程序运行的效率。
特性:
1. inline是一种 以空间换时间 的做法,如果编译器将函数当成内联函数处理,在 编译阶段,会 用函数体替换函数调用 ,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
2. inline 对于编译器而言只是一个建议,不同编译器关于 inline 实现机制可能不同 ,一般建议:将函数规模较小 ( 即函数不是很长,具体没有准确的说法,取决于编译器内部实现 ) 是递归、且频繁调用 的函数采用 inline 修饰,否则编译器会忽视inline特性。
3. inline不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。建议将inline声明定义都放到.h文件中。
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
 cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
 f(10);
 return 0;
}
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl 
//f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

四.范围for

对于一个 有范围的集合 而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11 中引入了基于范围的 for 循环。 for 循环后的括号由冒号 分为两部分:第一部分是范 围内用于迭代的 变量 ,第二部分则表示被 迭代的范围
#include<iostream>
using namespace std;
int main()
{
	int arr [] = {1,2,3,4,5};
	//遍历数组
	for (int n : arr)
	{
		cout << n << " ";
	}
	return 0;
}

 

 由于范围for的第一个参数是用于迭代的变量,要想改变数组内的值就不能直接改变这个变量的值。例如

#include<iostream>
using namespace std;
int main()
{
	int arr [] = {1,2,3,4,5};
	//遍历数组
	for (int n : arr)//打印数组
	{
		cout << n << " ";
	}
	cout << endl;
	for (int n : arr)//数组元素全部*2
	{
		n*=2;
	}

	for (int n : arr)//打印数组
	{
		cout << n << " ";
	}
	return 0;
}

 

正确的方法是:使用引用做用于迭代的变量,因为数组的值会依次赋值给引用,就顺便得到了数组全部元素的引用。进而用每个元素的引用改变数组元素。

for (int& n : arr)//数组元素全部*2
{
	n*=2;
}

猜你喜欢

转载自blog.csdn.net/2301_76144863/article/details/131818113
今日推荐