#include
int main()
{
int a = 0;
int* pa = &a;
int** ppa = &pa;
**ppa = 1;
printf("%d\n", a);
return 0;
}
这里的ppa是二级指针,通过解引用访问一级指针,再对一级指针解引用访问变量a的空间,将其赋值为1.
图解:
我们使用多级指针访问变量是否麻烦呢?
答: 可能是在某些特定的场景下麻烦,因此出了引用。
代码:
#include
using std::cout;
using std::endl;
int main()
{
int a = 0;
int& b = a;//为了不增加符号负担,选取&作为取别名
b = 1;
cout << a << endl;
return 0;
}
错误示例:
#include
using std::cout;
using std::endl;
int main()
{
int a = 0;
int& b;
return 0;
}
2.别名与原变量名共用一块空间
证明:
#include
using std::cout;
using std::endl;
int main()
{
int a = 0;
int& b =a;
cout << &a << endl;
cout << &b << endl;
return 0;
}
注意代码解读:
int main()
{
int a = 0;
int& b = a;
int x = 2;
b = x;//这里是将x的值赋值给a变量,而不是给x取别名为b!
return 0;
}
举例:
int main()
{
int a = 0;
int& b = a;
int& c = a;
int& d = b;//对别名取别名还是a变量
return 0;
}
关于单链表中引用的使用:
typedef struct SListNode
{
int val;
int* next;
}SListNode,*PNode;
//这里的PNode即为SListNode*
void SListPushBack(PNode& p, int x)//相当于对一级结构体指针取别名
{
//……功能省略
}
int main()
{
SListNode* head;
SListPushBack(head, 1);
return 0;
}
#include
using std::cout;
using std::endl;
void Swap(int& n1, int& n2)//传进去相当于对原变量取别名
{
int tmp = n1;
n1 = n2;
n2 = tmp;
}
int main()
{
int x = 2;
int y = 1;
cout << "before " << x <<" "<< y << endl;
Swap(x, y);
cout << "after " << x <<" "<< y << endl;
return 0;
}
int add()
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = add();
return 0;
}
int& add()
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = add();//这里的add()可看做n变量的别名
return 0;
}
#include
using std::cout;
using std::endl;
int& add()
{
int n = 0;
n++;
return n;
}
int main()
{
int& ret = add();
//add()=1;
cout << ret << endl;
printf("hello\n");
cout << ret << endl;
return 0;
}
可这样对一个常量能取别名吗?
int main()
{
int& b = 1;
return 0;
}
如何正确的对一个常量取别名?
int main()
{
const int& b = 1;
return 0;
}
应用于变量中
码1:
int main()
{
int a = 0;
const int& b = a;
a++;
//b++;
return 0;
}
码2:
这样可以吗?
int main()
{
const int a = 0;
int& b = a;
return 0;
}
码3:
int main()
{
int a = 0;
float b1 = 11.0f;
a = b1;//这里的b1其实是隐式类型转换的结果,将b1值转换成浮点数,这里的b1是浮点数的常量
int& a1 = a;
const float& b = a;
//同理这里的a也是隐式类型转换的结果,既然是结果那就是float类型的常量,常量就是只读状态
//因此是要加const 并且是float类型的常量
printf("%d %f", a, b);
return 0;
}
int main()
{
int a = 0;
int* pa = &a;
int& b = a;
return 0;
}
#include
using std::cout;
using std::endl;
int add(int x,int y)
{
return x + y;
}
int main()
{
for (int i = 0; i < 1000; i++)
{
cout << add(1, i) << endl;
}
return 0;
}
如何优化这一段代码?这段代码为什么需要优化?
学过C语言的你想必会使用宏函数进行优化,那为什么要这样优化呢?学过函数栈帧其实就很简单,函数调用是需要调用函数栈帧的,当栈帧的空间大于我们有效代码的空间时,使用函数的负担就会较大。
如何进行优化?
#include
using std::cout;
using std::endl;
#define ADD(x,y) (((x)+(y))*10)//ADD建议全大写这可是程序员之间的悄悄约定过的哦
int main()
{
for (int i = 0; i < 1000; i++)
{
cout << ADD(1, i) << endl;
}
return 0;
}
为了解决C语言的缺陷,所以设计者在C语言的基础上设计出了内联函数。
用法:只需在函数的返回值类型前+inline即可,本质上是有效指令的替换.
#include
using std::cout;
using std::endl;
inline int add(int x,int y)//这里加了inline
{
return x + y;
}
int main()
{
for (int i = 0; i < 1000; i++)
{
cout << add(1, i) << endl;
}
return 0;
}
如何证明:
#include
using std::cout;
using std::endl;
#define ADD(x,y) (((x)+(y))*10)
inline int add(int x,int y)
{
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
cout << "hello" << endl;
return x + y;
}
int main()
{
for (int i = 0; i < 1000; i++)
{
cout << add(1, i) << endl;
}
return 0;
}
联系:register 也不会把是否放在寄存器的决定权交给你,只是起建议的作用。
inline int add(int x, int y)
{
return x + y;
}
inline int add(int x, int y);
#include
#include"add.h"
using std::cout;
using std::endl;
int main()
{
for (int i = 0; i < 1000; i++)
{
cout << add(1, i) << endl;
}
return 0;
}
原因:链接时做了生成段表(主要为函数和全局变量的地址)的工作,而内联函数的本质是替换(其地址是不会放在段表中的),当你在链接时进行查找时会发现在头文件中只有声明,但是定义不在头文件中,而在源文件中,这时你要去源文件中查找,但是段表里面并没有这个函数的地址,因此找不到所以会报错!
因此:要么在头文件中写内联函数的定义,要么就直接写在主函数所在的源文件中,并且在不同源文件中定义相同的内联函数,是不会报错的,因为就不会在段表里出现这几个函数!
拓展:本质上代码的运行都会化作二进制指令的执行,计算机将指令加载到内存中,每条指令都有一条特定的地址,常规函数的调用会指行函数调用指令,程序将在函数调用后立刻存储该指令的内存地址,并将函数的参数拷贝到堆栈,跳到目标函数的起点内存单元执行代码,然后跳回地址被保存的指令处,这来回调用会存在一定的开销
C语言的auto的作用是修饰声明周期和作用域都是局部的的变量,但基本上没什么用,所以在C++上改进了一下——自动识别(变量的数据)然后定义其类型。
int main()
{
auto x = 1;
int y = 1;
float z = 1.0;
auto n = 1.0f;
//auto w ;这句代码是不对的
return 0;
}
int main()
{
int x = 0, y = 1.0f;//这里可是发生了隐式类型转换
auto x = 0, y = 1;
//auto x =0,y = 1.0f;这行代码会报错
return 0;
}
#include
#include"add.h"
using std::cout;
using std::endl;
int main()
{
int a = 0;
auto* p = &a;
cout << typeid(p).name() << endl;//这里打印的就是int*
cout << typeid(a).name() << endl;
return 0;
}
错误示例——自定义类型:
typedef struct Student
{
int age;
char name[20];
int Id;
}Student;
int main()
{
auto x = { 18,"shunhua",11111111 };//无法识别
return 0;
}
错误示例——函数参数
int add(int x, auto y)
{
return x + y;
}
int main()
{
int a = 0;
auto& x = a;
return 0;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (auto x : arr)
{
cout << x << endl;
}
return 0;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (auto& x : arr)
{
cout << x << endl;
}
return 0;
}
void Print(int arr[10])
{
for (auto x : arr)//这里是指针不是数组因此语法报错
{
cout << x << endl;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
Print(arr);
return 0;
}
#include
using std::cout;
using std::endl;
int main()
{
auto x = 0;
auto y = NULL;
auto z =(void *)NULL;
auto n = nullptr;
cout << typeid(x).name() << endl;
cout << typeid(y).name() << endl;
cout << typeid(z).name() << endl;
cout << typeid(n).name() << endl;
return 0;
}