文章目录

  • 引用变量
    • 1. 什么是引用、如何创建一个引用变量?
    • 2. 引用的具体使用方法
      • 2.1 引用做函数的形参
      • 2.2 引用参数的const用法
      • 左值、右值是什么?
      • 2.3 结构体的引用
      • 2.4 引用做函数返回值
      • 2.5 将引用用于类对象
    • 3 引用的本质是什么? 引用,指针和值传递的辨析
    • 4 什么时候使用引用参数?

参考文献:
C++ primer plus
对象、继承和引用
C++的左值和右值
黑马程序员:引用的本质

引用变量

1. 什么是引用、如何创建一个引用变量?

要搞清楚什么是引用,首先我们要清楚变编程语言的变量名或者叫标识符究竟是什么,比如int a; int *p; 这里面的a或者p,究竟是个什么呢? ———— 这些标识符本质上就是用来代指一个内存单元的.在汇编语言中,比如[0x1101]这就是一个内存单元,里面的0x1101是这个内存单元的地址或者说编号,外面的方括号用来表明直接寻址方式,即表示这个地址所代表的的内存单元。
而用一长串地址加一个方括号表示内存单元太过麻烦,我们就给这个[0x1101]这个内存单元起了一个好听的名字a,这个符号a经过编译器翻译和分配内存单元之后,所形成的的汇编指令,就被翻译成[0x1101]了,我们可以叫这个内存单元a,当然我们也可以叫它b或者dog随便什么名字都可以,一个内存单元当然可以拥有多个名字,至于叫什么其实无所谓,因为指的都是这个内存单元。这个小名b就是引用啦
int a = 0;
int &b = a;
这个b就是给a这个内存起了个小名b而已,并没有什么特别的。
&在C++中有两种用法,一种是引用,一种是取地址。

同样,指针int *p = &a; 中的p,所代表的也不过是一个普通的内存单元,我们就叫它[0x1102],

1、 我们&p ,也就是取这个内存单元的地址,也就是0x1102这个地址值。
2、我们输出p ,得到的就是这个内存单元里的内容,也就是a的地址呗,就是0x1101
3、 我们输出*p,这是解引用操作,得到的就是a所代表的内存单元存的的内容,或者说是指针p指向的内存单元的内容,就是0

那么我们既然知道了变量a引用变量b指的都是同一个内存单元[0x1101],那呢我们无论或者a或者b中的任何一个进行操作,[0x1101]这个内存单元都会发生相应的改变。

2.引用的注意事项
1、引用必须初始化: int &b; b = a;是错误的,必须是int &b = a,引用在初始化后,不可以改变:
2、一个别名不允许更改成另一个变量的别名,起别名后,别名只能代表一块内存,不能改变成另一块内存

示例代码

//1. 引用的基本语法
int a = 10;
int &b = a;   //给a对应的内存起个别名b,用b也可以操作这款块内存
b = 20;
cout <<"a= "<< a << endl;   // 20
cout << "b= "<<b << endl;   // 20b = 100;cout << "a= " << a << endl;  //100
cout << "b= " << b << endl;  //100//2 引用的注意事项:必须初始化,不可改变内存的指向
int c = 10;
int &d = c;   int g = 20;
d = g;  //赋值从操作,而不是更改引用
// int& d = g;  //这也不是更改引用,这是多次初始化了,也是错的,别名就不能更改cout << "c= " << c << endl;  //c和d的内容一样,因为这就是一块相同的内存区域
cout << "d= " << d << endl;
cout << "g= " << g << endl;

2. 引用的具体使用方法

2.1 引用做函数的形参

函数形参的形式一般分为三种:

  • 值传递方式:形参不能改变实参,形参和实参相当于是两块独立的内存,形参内存区数值的变化对于实参的内存单元中的数值是没有影响的。
  • 地址传递方式:即指针方式,通过另外一块内存单元(即指针变量)来指向实参的内存区,通过改变这个指针的指向,来直接对实参内存区中不同的单元进行操作。所以指针做函数形参是可以改变实参的数值的。
  • 引用方式:引用做函数形参时,就是相当于对这个实参的内存单元起了一个别名,实际上直接操作的就是实参的内存单元区域,所以引用方式也可以改变函数实参。

以常见的交换函数为例来说明三种形参的差别

#include<iostream>//值传递
oid mySwap01(int a, int b)
{int temp = a;a = b;b = temp;
}//地址传递
oid mySwap02(int* a, int* b)
{int temp = *a;*a = *b;*b = temp;
}//引用传递
oid mySwap03(int &a, int &b)  //相当于 int &a_2 = a; 给实参a起了个别名形参a, 形参a操作的还是实参a所代表的的那块内存单元,所以可以形参改变实参
{int temp = a;a = b;b = temp;
}int main(){using namespace std;int a = 10;int b = 20;mySwap01(a, b);     //值传递的方式形参不会改变实参cout << "a = " << a << endl;  //10cout << "b = " << b << endl;  //20a = 10;b = 20;mySwap02(&a, &b);     //地址传递的形参可以改变实参cout << "a = " << a << endl;   //20cout << "b = " << b << endl;   //10a = 10;b = 20;mySwap03(a, b);     //引用时形参可以改变实参cout << "a = " << a << endl;   //20cout << "b = " << b << endl;   //10return 0;
}

引用做形参的注意事项
值传递时,实参时允许传入一个常数或者表达式的,比如

double z = cube(x + 2.0);
z = cube(8.0);
z = cube(k);

但是传递引用的限制更严格,实参只能是变量名,而不能是一个常数或者表达式,
如下都是错误的

double refcube(double &ra)
{ra = ra*ra;return ra;
}int main()
{double z = refcube(3.0);  //错误 不能double &ra = 3.0double x = 10; double z = refcube(x + 3.0); //错误 不能double &ra = x + 3.0double z = refcube(x); //正确 ,相当于 double &ra = x
}

2.2 引用参数的const用法

常量引用: const
作用:

  1. 常量引用用来修饰形参,防止误操作,
  2. 在函数形参列表中,可以加const修饰形参,防止形参改变实参

注意:仅当参数为const引用时,如果实参与引用参数不匹配,C++将生成临时变量,可以传递参数的种类更丰富一些,而常规变量引用是不允许的。

double refcube(const double &ra)
{return ra*ra*ra;
}double side = 3.0;
double *pd = &side;
double &rd = side;
long edge = 5l;
double lens[4] = {2.0, 5.0, 10.0, 12.0};//side,len[2],rd,*pd都是有名称的1,double类型的数据对象,因此可以欸其创建引用,而不需要临时变量
double c1 = refcube(side);
double c2 = refcube(lens[2]);
double c3 = refcube(rd);
double c4 = refcube(*pd);//以下三种i情况,数据类型问题或者是表示式、常数,没有名称,都是需要创建临时变量,但不会报错,与常规变量引用不同。//edge虽然是变量,但是类型却不正确,double不能指向long
double c5 = refcube(edge);
//7.0和side+10.0都是double类型的数据,但是没有名称
double c6 = refcube(7.0);
double c7 = refcube(side+10.0);

一般来说const int &a = 10; 有问题,
但编译器会这样处理:
int tenmp = 10;
int &a = temp ;
这样就正确了

需要注意的是编译器只会对const引用做临时变量处理,而常规变量引用则不会

究其原因是因为常规引用中形参是要改变实参,而创建临时变量则会阻止这种改变,引起错误,所以方法就是直接禁止创建临时变量。
而对于const引用目的则是不想改变实参,只是想用引用方便一些,不需要像值传递时需要复制很大一块空间,所以加个const不允许改变参数值,如果不小心改变了,编译器会报错提醒程序员。所以这个时候允许创建临时变量,使用起来可以更方便,传入参数类型限制可以不用那么严格。

使用const的好处

  • 可以避免无意修改数据的编程错误
  • 能处理左值数据和右值数据,否则只能接受左值数据
  • 能够使函数正确生成并使用临时变量

左值、右值是什么?

左值:左值是一个可被引用的数据对象,例如变量、数组元素、结构成员、引用和解除引用的指针都是左值。(实际占用内存空间的数据),对cpu来说对左值可以进行读和写操作。(可以写在左边或右边)
右值:包括常量和包含多项的表达式(用引号扩起的字符串除外,他们由地址表示)。基本不占用内存,一般在寄存器里或者是立即数(汇编概念),只能进行读操作。
常规变量和const变量都可视为左值,因为可通过地址访问他们,但常规变量属于可修改的左值,而const变量属于不可修改的左值。

左值引用(使用&声明)是指向左值的,加了const之后也可以指向右值(实际上是创建了个临时变量)
C++11新增了右值引用,是用来指向右值的,用&&声明

double && rref = std::sqrt(36.00);   //左值引用就不允许这样做
double j = 15.0;
double && jref = 2.0*j+18.5;  //右值引用
std::cout << rref <<'\n';   //6.0
std::cout << jref <<'\n';  //48.5;

2.3 结构体的引用

引用非常适用于结构和类,引入引用机制主要就是为了用于这些类型的,而不是基本的内置类型。
使用方法与使用基本变量引用相同

struct free_throws
{std::string name;int made;int attempts;float persent;
};
//修改传入的结构
void set_pc(free_throws &ft);
//或者是不修改传入的结构
void set_pc( const free_throws &ft);

2.4 引用做函数返回值

  • 作用:引用是可以作为函数的返回值存在的,返回引用的函数实际上是被引用变量的一个别名
free_throws& accumulate(free_throws& target, const free_throws& source)
{target.attempts += source.attempts;target.made += source.made;set_pc(target);return target;
}

函数accumulate(a,b) 实际上就是a这个地址空间的一个别名,可以用来作为左值

  • 用法:函数的调用可以作为左值
   display(accumulate(team, two));  accumulate(accumulate(team, three), four);dup = accumulate(team, five);free_throws &a =  accumulate(team, five);accumulate(dup, five) = four;// 这条语句更详细的内容见下面的,const用于返回值类型
  • 注意:不要返回局部变量引用
//不要返回局部变量引用
int& test01()
{int a = 10;  //局部变量存放在栈区,出了函数之后就被编译器释放负掉了return a;
}//返回静态变量引用
int& test02()
{static int a = 10;  //静态变量存放在全局区,整个程序运行结束之后才由操作系统释放return a;
}int main()
{int &ref = test01();cout << "ref = " <<ref<< endl;    //第一次结果正确,是因为编译器做了一次保留cout << "ref = " << ref<<endl;    //第二次结果错误,是因为a的内存已经释放int& ref2 = test02();cout << "ref2 = " << ref2 << endl; //两次都正确,因为这块内存一直没有释放cout << "ref2 = " << ref2 << endl;return 0;
}

解决方法:

  1. 函数返回引用时,返回一个传入函数的参数。形参引用将指向实参数据区,返回引用也可以指向这个实参数据区,不去出现问题(比如上面accumulate( , )采取的方法)
  2. 用new来分配新的存储空间,

free_throws& clone2(free_throws& ft)
{free_throws newguy;   newguy = ft;return newguy;  //返回的是一个局部变量,在栈区,函数结束后这段内存空间就被释放了
}free_throws& clone(free_throws& ft)
{free_throws* pt = new free_throws{}; //使用new分配新的存储空间,由程序员自己释放,用一个指针指向这个空间*pt = ft;   //向这个空间写入数据return *pt;  //相当于 free_throws &clone(free_throws& ft) = *pt,返回这个*pt所代表的空间的一个引用  即clone(one)就是这个空间的第一个单元一个别名
}int main()
{free_throws& jolly = clone(one);display(jolly);   //每次显示结果都一样,因为堆空间是由程序员自己释放的。display(jolly);display(jolly);return 0;
}

但是这个方法也有一点问题,就是调用clone()函数时看不到new,程序员可能会忘了delete这段内存空间。

结构与返回的引用变量应用示例

//strc_ref.cpp -- using structure references
#include <iostream>
#include <string>
struct free_throws
{std::string name;int made;int attempts;float percent;
};void display(const free_throws& ft);
void set_pc(free_throws& ft);
free_throws& accumulate(free_throws& target, const free_throws& source);int main()
{//初始化结构体成员变量,指定的初始值(3个)比成员数(4个)少,剩下的成员(precent)将被设置为0free_throws one = { "Ifelsa Branch", 13, 14 };free_throws two = { "Andor Knott", 10, 16 };free_throws three = { "Minnie Max", 7, 9 };free_throws four = { "Whily Looper", 5, 9 };free_throws five = { "Long Long", 6, 14 };free_throws team = { "Throwgoods", 0, 0 };free_throws dup;set_pc(one);display(one);accumulate(team, one);display(team);// use return value as argumentdisplay(accumulate(team, two));             //返回引用的函数实际上是返回这个结构的别名,这个别名还可以作为左值,供左值引用来使用//相当于这两句:// accumulate(team, two)   返回team对象// display(team);         ft指向teamaccumulate(accumulate(team, three), four);display(team);//这里是赋值操作,相当于将team结构复制了一份赋值给dup (发生了拷贝)dup = accumulate(team, five);std::cout << "Displaying team:\n";display(team);std::cout << "Displaying dup after assignment:\n";display(dup);set_pc(four);//下面这条语句如果是按值返回是不能写在左边的,因为返回的是一个右值//但是用返回引用的方式就可以了,因为返回值是一个左值,可以对这个左值进行写操作(赋值)accumulate(dup, five) = four;//上面的两条语句就相当于://accumulate(dup, five);     dup = dup + five// dup = five;               dup = five// 其中第二条语句消除了第一条语句的工作,所以这种方法虽然能通过编译,但是不太好。std::cout << "Displaying dup after ill-advised assignment:\n";display(dup);// std::cin.get();return 0;
}void display(const free_throws& ft)      //形参为结构体常量引用,不能修改实参 ,只是用来打印结构体所有成员变量
{using std::cout;cout << "Name: " << ft.name << '\n';cout << "  Made: " << ft.made << '\t';cout << "Attempts: " << ft.attempts << '\t';cout << "Percent: " << ft.percent << '\n';
}
void set_pc(free_throws& ft)    //形参为结构体左值引用 ,用于设置分数
{if (ft.attempts != 0)ft.percent = 100.0f * float(ft.made) / float(ft.attempts);elseft.percent = 0;
}free_throws& accumulate(free_throws& target, const free_throws& source) //target可修改 , source不可修改 ,返回target的引用
{target.attempts += source.attempts;target.made += source.made;set_pc(target);return target;
}
  • const应用于返回类型

accumulate(dup, five) = four;
这条语句是可以通过编译的,因为函数返回指向dup的引用,其实是标识了dup这个内存块的,它是由地址的实实在在的一块内存空间的别名,是可以作为左值的。
而常规的函数返回类型返回的是右值,即不能通过地址访问的值,(比如 10 这种常数或者 x + y这种表达式),这种返回值只是位于临时的内存单元中,运行到下一条语句时,他们可能就不存在了

但是很明显,这里的赋值操作four ,覆盖了函数操作的dup空间,所以当你想想要使用引用,又不允许给返回的左值进行赋值操作时,可以使用const修饰
const free_throws & accumulate(free_throws& target, const free_throws& source);
相当于返回一个不可更改的左值(这块内存只能读不能写)。

使用const之后,

   display(accumulate(team, two));
//这里仍然可以使用,因为display()的形参也是const free_throws & 类型accumulate(accumulate(team, three), four);//这里会报错,因为第一个参数是非const类型//但这里影响不大accumulate(team, three);accumulate(team, four);//这样就可以了dup = accumulate(team, five); //从内存读数据没问题const free_throws &a =  accumulate(team, five);//接收也要加一个constaccumulate(dup, five) = four; //报错

2.5 将引用用于类对象

1. 使用引用方式将类的对象作为函数参数

#include<iostream>
#include<string>
using namespace std;//使用引用方式将类的对象作为函数参数
string version1(const string& s1, const string& s2);
const string& version2(string& s1, const string& s2);  //has side effect
const string& version3(string& s1, const string& s2);  //bad designint main()
{string input;string result;string copy;   //副本,后面用来恢复inputcout << "Enter a string: ";getline(cin, input);copy = input;cout << "Your string as entered: " << input << endl;result = version1(input, "***");cout << "Your string enhanced: " << result << endl;cout << "Your string original:" << input << endl;   //值传递原始内容不变result = version2(input, "###");cout << "Your string enhanced: " << result << endl;cout << "Your string original:" << input << endl;   //引用传递原始内容改变了//恢复input的内容cout << "Reseting original string\n";input = copy;result = version3(input, "@@@");   //这里程序会崩溃,这块内存都没了,还返回啥cout << "Your string enhanced: " << result << endl;cout << "Your string original:" << input << endl;return 0;
}string version1(const string& s1, const string& s2)  //有const时 ,"***"是char*类型,和引用类型不匹配时,程序能够创建一个正确类型的临时变量,使其能正确传参
{string temp;temp = s2 + s1 + s2;return temp;  //这里的temp s1 s2都是一个string类的对象 ,返回一个string类的对象
}const string& version2(string& s1, const string& s2)
{s1 = s2 + s1 + s2; //这里string类对象s1是可以修改的return s1;  //返回一个不可修改的string类的对象s1的引用
}const string& version3(string& s1, const string& s2)
{string temp;temp = s2 + s1 + s2;return temp;  //!!!注意这里返回了一个局部变量的引用,函数运行结束之后,temp这块内存就没有了,所以不能发这么写。
}

2. 在函数里,通过基类的引用,来指向派生类的对象,而无需强制类型转换

//filefunc.cpp -- function with ostream & parameter
/*这个程序要求用户输入望远镜的物镜和目镜的焦距,然后计算每个目镜的放大倍数,放大倍数等于物镜的焦距除以目镜的焦距
*/#include <iostream>  //和控制台有关
#include <fstream>   //和文件有关
#include <cstdlib>
using namespace std;//在函数里,通过基类的引用,来指向派生类的对象,而无需强制类型转换void file_it(ostream& os, double fo, const double fe[], int n);
//定义的这个基类的对象的引用ostream& os
//由于ostream是基类,而ofstream是派生类,
// 1. 派生类继承了基类的方法,派生类可以使用基类的特性
// 2. 基类的引用也可以指向派生类的对象!!!!!!!!!!
//这里的意思就是基类引用形参ostream & os  ,这里传递进去一个派生类ofstream创立的对象fout作为函数参数也是可以的const int LIMIT = 5;
int main()
{fstream fout;  //用fstream这个类定义一个对象foutconst char* fn = "ep-data.txt";fout.open(fn); //用open方法打开文档if (!fout.is_open()){cout << "Can't open " << fn << ". Bye." << endl;exit(EXIT_FAILURE); //这个宏在#include <cstdlib>}double objective;cout << "Enter the focal length of your telescope objective in mm:"; //输入物镜焦距cin >> objective;double eps[LIMIT]; for (int i = 0; i < LIMIT; i++)      //目镜有好几个呢{cout << "EyePieces #" << i + 1 << ": ";cin >> eps[i];}file_it(cout,objective,eps,LIMIT);  //cout是终端控制台的对象,终端输出显示file_it(fout, objective, eps, LIMIT);  //fout是文件的一个对象,文件输出显示 ,这里派生类对象fout也可以作为形参传入基类引用中cout << "Done." << endl;return 0;
}void file_it(ostream& os, double fo, const double fe[], int n)  //ostream类对象 , 物镜焦距,多个目镜焦距的数组,目镜个数
{os << "Focal length of objective: " << fo << endl;  //输出物镜倍数os << "f.1. eyepieces" << " magnification" << endl; //输出目镜倍数for (int i = 0; i < n; i++){os <<"  "<< fe[i] << " \t " << int(fo / fe[i] + 0.5) << endl;  //放大倍数取整}}

3 引用的本质是什么? 引用,指针和值传递的辨析

/普通变量、指针和引用的汇编实现*/

/*
总结:C++中的变量名,不论是int a 的a,还是int* p 的p,其本质都是一个计算机分配的内存单元的标识符,用来指代某个特定的内存单元
变量名本是是一个数值,并不占用内控空间来存储这个数值,而是直接在汇编指令中编译为 [a] 或[1122H],用直接寻址的方式来代表某一块内存

int *p = &a; 指针则是一个实际的内存单元,这个内存单元中存放了[a]这个内存单元的地址值,也就是变量名a被翻译成汇编指令后对应的数值
指针变量名p也是一个数值,被汇编程序翻译成指针变量的内存单元的地址值,[p]这个单元就是指针变量
[p]直接寻址,可以找到指针变量,[p]单元中存放了[a]这个单元的地址,也就是变量名a的数值

指针变量初始化的过程:
int *p = &a;
lea      eax, [a]
mov      dword ptr[p], eax
取[a]的单元的地址,经寄存器eax中转,放入[p]单元中指针变量解引用,即用*p来代表a单元,
*p = 4;
mov      eax, dword ptr[p]    从指针变量的内存单元中获取内存单元a(变量)的地址
mov      dword ptr[eax], 4    寄存器间接寻址在找到[a]这个内存单元,进行赋值变量赋值
a = 5;
mov      dword ptr[a]   a直接就代表一块特定的内存单元的地址,这里用的是直接寻址方式引用
int &q = a;
lea         eax, [a]
mov         dword ptr[q], eax指针常量
int* const r = &a;
lea         eax, [a]
mov        dword ptr[r], eax

可以见到,,引用的本质在汇编层面就是一个指针常量,他也是一个指针,只不过是一个只能指向[a]内存单元的指针,他的指向不可以改变,
所以可以避免指针指向其他位置造成混乱,[q] 和[a]是一个东西,q = a都是那个内存单元的地址的数值,两者是相等的
引用就是一个功能简化后的指针,用起来更方便。或者直接当成变量的别名即可,一码事。

int* p = &a;        // 指针初始化
// lea         eax, [a]              &a操作就是将a的地址放入寄存器中// mov         dword ptr[p], eax     在将这个地址放到指针变量的内存单元中
int& q = a;   //引用初始化
// lea         eax, [a]// mov         dword ptr[q], eaxint* s;  //这个指针变量的声明没有赋值,所以此时海内有开辟对应的指针变量的内存空间,没有相应的汇编指令
s = &a;
// lea         eax, [a]// mov         dword ptr[s], eax*p = 4;                              //给指针指向的内存单元赋值
// mov         eax, dword ptr[p]    *p解引用: 将指针变量的内存单元存放的内容(即变量a的地址)送到寄存器中,解引用就是获取指针变量中存放的地址
// mov         dword ptr[eax], 4    再采用寄存器间接寻址的方式将4放入变量a的内存单元中,先*p,再赋值,将4送到这个指针指向的内存单元中区
a = 5;
// mov         dword ptr[a], 5
a = b;
// mov         eax, dword ptr[b]
// mov         dword ptr[a], eaxp = &b;                    //给指针改变指向
// lea         eax, [b]
// mov         dword ptr[p], eax   int t = b; //常规变量赋值
// mov         eax, dword ptr[b]
// mov         dword ptr[t], eaxint* const r = &a;     //指针常量初始化
// lea         eax, [a]
// mov        dword ptr[r], eaxq = 6;
// mov         eax, dword ptr[q]// mov         dword ptr[eax], 6

4 什么时候使用引用参数?

引用:

  1. 形参可以修改实参
  2. 本质是个常量指针,直接指向参数内存,提高程序运行速度,节省内存空间。

对于传递的值不修改的函数

  • 数据将对象
  • 很小(内置类型或小型结构)———— 值传递
  • 数组 ———— 使用const指针
  • 数据对象较大 ———— const指针或const引用
  • 类对象 ———— const引用 ,传递类对象的标准方式是按引用传递

修改传递的值的函数

  • 内置数据类型 ———— 指针
  • 数组 ———— 只能指针
  • 结构 ———— 引用或指针
  • 类对象 ———— 引用

【C++引用超详细笔记, 引用、指针和值传递的汇编级辨析,对象、继承和引用】相关推荐

  1. Java并发编程(中下篇)从入门到深入 超详细笔记

    接上一篇博客笔记:Java并发编程(中上篇)从入门到深入 超详细笔记_未来很长,别只看眼前的博客-CSDN博客https://blog.csdn.net/weixin_53142722/article ...

  2. (超详细笔记整理)动力节点_老杜 | JavaSE零基础 :P329(方法) - P479

    JAVA基础学习 第二篇文章的连接: (超详细笔记整理)动力节点_老杜 | JavaSE进阶 [P486之后]. 文章目录 JAVA基础学习 方法 Java的主要内存空间 栈数据结构 **栈数据结构: ...

  3. 学习javascript这一篇就够了超详细笔记(建议收藏)上

    学习javascript这一篇就够了超详细笔记(建议收藏)上 1.初识 计算机基础导读 编程语言 计算机基础 初识js 浏览器执行 js组成 js初体验-三种书写位置 js注释 js输入输出语句 2. ...

  4. SPRING注解驱动开发-雷神课程超详细笔记

    SPRING注解驱动开发-雷神课程超详细笔记 时间:2021-03-21 2022-04-06更新:最近翻起一年多前写的笔记复习,还是收获颇多,很多当时无法理解的知识现在慢慢能理解了,可能是工作一年的 ...

  5. 清晰易懂!关于PS入门的超详细笔记!

    给大家分享一篇关于PS入门的超详细笔记!原理讲解清晰明了,虽不是新版本解析,但都是新手学习PS必掌懂的一些知识点,灰常的实用,转走收藏学习! 编辑:千锋UI设计 来源:PS学堂

  6. C++学习笔记(超详细笔记记录ing)

    C++学习笔记(11) 学习是一件任重而道远的事情,与其焦虑不如动手起来,借助平台记录自己学习笔记,希望和大家多多交流,今天又是努力成为程序媛的一天! 17.类和对象 17.3 C++对象模型和thi ...

  7. C语言基础入门笔记(超详细笔记,多出进行更新,将近九千字)

    下载VS2013,我们一起学习. #include 包含一个叫stdio.h的文件,文件包含令,预处理指令. stdio.h C语言的标准I/O库,用于读取和写入文件,也用于控制台的输入和输出. ma ...

  8. c6011取消对null指针的引用_C++| 函数的指针参数如何传递内存?

    函数的参数是一个一级指针,可以传递内存吗? 如果函数的参数是一个一级指针,不要指望用该指针去申请动态内存. 看下面的实例: #include using namespace std; void Get ...

  9. 超详细的const 指针与指向const的指针

    最近在复习C++,指针这块真的是重难点,很久了也没有去理会,今晚好好总结一下const指针,好久没有写过博客了,记录一下~ const指针的定义: const指针是指针变量的值一经初始化,就不可以改变 ...

最新文章

  1. ptam tracking
  2. Spring AOP Capability and goals
  3. 如何使用Microsoft技术栈
  4. python安装oracle驱动_python安装oracle扩展及数据库连接方法
  5. anaconda方法安装python教程_anaconda的安装教程和使用方法
  6. IE6、7 a链接内图片加滤镜后导致a标签链接失效问题解决
  7. mysql数据库的安全机制管理_mysql管理之安全机制
  8. mybatis association 问题
  9. leetcode978. Longest Turbulent Subarray
  10. fdfs手动上传下载
  11. Python华氏摄氏度的转换
  12. U盘写保护,不能被格式化
  13. matlab中的常用符号,matlab特殊符号表
  14. 计算机专业 在职跨英语,英语在职研究生跨专业可以吗?
  15. 安装Linux启动盘【准备8G以上U盘即可】
  16. 低功耗蓝牙(BLE)开发——如何妥善处理包大小(MTU)限制
  17. 比所有女生都小的男生mySQL_男生能接受比自己小很多的女生吗?
  18. 用计算机编程解魔方,魔方程序 (详细的解释)
  19. java文字列检查_java 检测文本、文件编码
  20. 李沐动手学深度学习第四章-4.9.环境和分布偏移

热门文章

  1. 谷歌Transformer再升级——新模型实现性能、速度双提升,发展潜力巨大
  2. 程序员vs瓦工 那么到底谁牛逼?
  3. 热释电红外传感器各种型号_热释电红外传感器结构及型号 - 全文
  4. 精彩纷呈,不虚此行——第五届上海燕博会(燕窝滋补品展)活动日程预告
  5. 《一位父亲给梦鸽女士的一封信》全文
  6. error C2664: 'LONG CTabCtrl::InsertItem(int,TCITEMW *)' : cannot convert parameter 2 from 'char *' t
  7. android_手机铃声设置
  8. 7-6 谷歌的招聘 (15 分)
  9. 酷比魔方Talk 5H (A5300)刷机包 MIUI V5 183期开发板
  10. 浅谈C# 多态的魅力(虚方法,抽象,接口实现) ----转