本篇文章是個人的C++學習記錄,也算是《C++ Primer Plus》的讀書筆記,如有錯誤,期望指正
成都創(chuàng)新互聯從2013年成立,先為吳堡等服務建站,吳堡等地企業(yè),進行企業(yè)商務咨詢服務。為吳堡企業(yè)網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。第一章 預備知識 類和對象在c++中,類是一種規(guī)范,描述了一種新型數據格式,對象是根據這種規(guī)范構造的特定數據結構
也就是說,類是抽象的,描述了有什么數據?對數據有哪些操作?而對象是具體的,是類的實例化
OOP(面向對象編程)并不僅僅是將數據和方法合并成類定義。
模板是一種對類型進行參數化的工具,模板是泛型編程的基礎,而泛型編程指的就是編寫與類型無關的代碼,是C++中一種常見的代碼復用方式。模板分為模板函數和模板類;模板函數針對參數類型不同的函數;模板類主要針對數據成員和成員函數類型不同的類。
以上是對C++一些相較于C而言比較“新”的東西的總結,也是作者接下來要重點學習的地方
第二章 C++ 內置數據類型 基本類型整型變量:bool、char、signed char、unsigned char、short、 unsigned short、int、unsigned int、long、unsigned long
浮點型變量:float、double、long double
對于整型變量,頭文件climits中定義了符號常量來表示類型的屬性,可自行查看。
對于浮點類型,只要包含頭文件“stdio.h”即可使用printf進行格式化輸出。
C++算術運算符
+、-、*、/、%分別為加、減、乘、除、求余
對于除法,分別有int類型、long類型、double類型、float類型
#include#include"stdio.h"
using namespace std;
int main(){
int a=2,b=5;
float c=3.78343;
cout<
復合類型數組、C風格字符串、string類字符串、結構體、共用體、枚舉、指針、vector類、array類……
數組聲明數組,需要指出:儲存在每個元素中的值的類型、數組名、數組中的元素數
typeName arrayName[arraySize];
//其中,arraySize指定元素數目,它必須是整型常數或const值,也可以是常量表達式。簡而言之,不能是變量(程序運行過程賦值的量)
//數組是由其他類型來創(chuàng)建的復合類型,不能僅僅將某種東西聲明為數組,它必須是特定類型的數組。
初始化數組,只有在定義數字時才能使用初始化,以后就不能使用了,也不能把一個數組賦給另一個數組,但可以用下標給元素賦值
int text[2] = {1,2}; float b[5] = {1,2,3};//可以不完全賦值,但不能超額
short things[] = {1,5,3,8};//計算元素個數時,可以用
int num = sizeof things / sizeof (short);
數組賦值
int main(){
int a[10];char b[10];string c[10];
cin>>a;//報錯
cin>>b;//允許
cin>>c;//報錯
return 0;//a=,b=,c=,也報錯,不能整體賦值,只能單元素賦值
}//字符串(字符數組)可以整體cin,其他數組只能單元素cin
C風格字符串C風格字符串的本質是一個以空字符’\0’為結尾的char數組,將字符串存儲到數組中,有兩種方式
char dog[8]={'f','a','t','e','s','s','a','\0'}
char bird[11]="Mr.Cheeps"http://后兩種方式會自動在結尾添加'\0'
char fish[]="Bubbles"http://兩種方式都要求數組長度大于等于字符串加'\0'的長度
//注意,不能先定義再賦值,如:char a[10];a="XXX";//a是數組第一個元素的指針,不能改變值。
//但是可以對單個元素賦值,如:char a[10];a[0]='x';
? 拼接字符串,在cout時,任何兩個由空白(空格、制表符、換行符)分隔的字符串常量,都會自動拼接成一個。
cout<<"sfsagsg""sagsagasg";cout<<"sagasghsahas" "asfagasgsa";
cout<<"safsagasdhrwjnf"
"sagasghshdahna";
const int Arsize=20;
char name[Arsize];
char dessert[Arsize];
cin>>name;cin>>dessert;
cout<<"hello"<
? 面向行的輸入
const int Arsize=20;
char name[Arsize];char dog[Arsize];
cin.getline(name,20);//遇見換行符或者到達大值(算上換行)停止,吃掉換行符,并把它變成空字符
cin.get(dog,20);//遇見換行符或者到達大值(算上換行)停止,不吃換行符,把它留在輸入流中
cin.get();//接收留在輸入流中的換行符
cin.get(name,Arsize).get();cin.get(dog,Arsize).get();//與cin.getline(name,Arsize).getline(dog,Arsize);等效
(cin>>name).get();//cin>>name返回的是cin對象,可以調用get()
string類#include#includeusing namespace std;
int main(){//string對象在很多方面與字符數組相同,初始化方式可以一樣,可以cin,可以cout,也可以用數組表示法訪問單個字符
string str1;string str2="asdfg";
str1="sdafasf";str2="asdfgg";
cout<
運算符重載注意:使用重載的運算符 + 時,必須保證前兩個操作數至少有一個為 string 類型。例如,下面的寫法是不合法的:
#include#includeint main()
{string str = "cat";
cout<< "apple" + "boy" + str; // illegal!
return 0;
}
查找string str;
cin >>str;
str.find("ab");//返回字符串 ab 在 str 的位置
str.find("ab", 2);//在 str[2]~str[n-1] 范圍內查找并返回字符串 ab 在 str 的位置
str.rfind("ab", 2);//在 str[0]~str[2] 范圍內查找并返回字符串 ab 在 str 的位置
//first 系列函數
str.find_first_of("apple");//返回 apple 中任何一個字符首次在 str 中出現的位置
str.find_first_of("apple", 2);//返回 apple 中任何一個字符首次在 str[2]~str[n-1] 范圍中出現的位置
str.find_first_not_of("apple");//返回除 apple 以外的任何一個字符在 str 中首次出現的位置
str.find_first_not_of("apple", 2);//返回除 apple 以外的任何一個字符在 str[2]~str[n-1] 范圍中首次出現的位置
//last 系列函數
str.find_last_of("apple");//返回 apple 中任何一個字符最后一次在 str 中出現的位置
str.find_last_of("apple", 2);//返回 apple 中任何一個字符最后一次在 str[0]~str[2] 范圍中出現的位置
str.find_last_not_of("apple");//返回除 apple 以外的任何一個字符在 str 中最后一次出現的位置
str.find_last_not_of("apple", 2);//返回除 apple 以外的任何一個字符在 str[0]~str[2] 范圍中最后一次出現的位置
//以上函數如果沒有找到,均返回string::npos
cout<< string::npos;
子串str.substr(3); //返回 [3] 及以后的子串
str.substr(2, 4); //返回 str[2]~str[2+(4-1)] 子串(即從[2]開始4個字符組成的字符串)
替換str.replace(2, 4, "sz");//返回把 [2]~[2+(4-1)] 的內容替換為 "sz" 后的新字符串
str.replace(2, 4, "abcd", 3);//返回把 [2]~[2+(4-1)] 的內容替換為 "abcd" 的前3個字符后的新字符串
插入str.insert(2, "sz");//從 [2] 位置開始添加字符串 "sz",并返回形成的新字符串
str.insert(2, "abcd", 3);//從 [2] 位置開始添加字符串 "abcd" 的前 3 個字符,并返回形成的新字符串
str.insert(2, "abcd", 1, 3);//從 [2] 位置開始添加字符串 "abcd" 的前 [2]~[2+(3-1)] 個字符,并返回形成的新字符串
追加除了用重載的+
操作符,還可以使用函數來完成。
str.push_back('a');//在 str 末尾添加字符'a'
str.append("abc");//在 str 末尾添加字符串"abc"
刪除str.erase(3);//刪除 [3] 及以后的字符,并返回新字符串
str.erase(3, 5);//刪除從 [3] 開始的 5 個字符,并返回新字符串
交換str1.swap(str2);//把 str1 與 str2 交換
其他str.size();//返回字符串長度
str.length();//返回字符串長度
str.empty();//檢查 str 是否為空,為空返回 1,否則返回 0
str[n];//存取 str 第 n + 1 個字符
str.at(n);//存取 str 第 n + 1 個字符(如果溢出會拋出異常)
實例查找給定字符串并把相應子串替換為另一給定字符串
string 并沒有提供這樣的函數,所以我們自己來實現。由于給定字符串可能出現多次,所以需要用到find()
成員函數的第二個參數,每次查找之后,從找到位置往后繼續(xù)搜索。直接看代碼(這個函數返回替換的次數,如果返回值是 0 說明沒有替換):
int str_replace(string &str, const string &src, const string &dest)
{int counter = 0;
string::size_type pos = 0;
while ((pos = str.find(src, pos)) != string::npos) {str.replace(pos, src.size(), dest);
++counter;
pos += dest.size();
}
return counter;
}
從給定字符串中刪除一給定字串
方法和上面相似,內部使用erase()
完成。代碼:
int str_erase(string &str, const string src)
{int counter = 0;
string::size_type pos = 0;
while ((pos = str.find(src, pos)) != string::npos) {str.erase(pos, src.size());
++counter;
}
return counter;
}
給定一字符串和一字符集,從字符串剔除字符集中的任意字符
int str_wash(string &str, const string src)
{int counter = 0;
string::size_type pos = 0;
while ((pos = str.find_first_of(src, pos)) != string::npos) {str.erase(pos, 1);
++counter;
}
return counter;
}
結構體數組可以將多個同類型元素存儲在一起,而結構體可以將多種類型的數據存儲在一起
struct text{
char name[20];
float volume;
double price;
};//結構體由其他類型數據組成,各類型依然遵守原來的用法,初始化方法、賦值方法……
int main(){//可以將一個結構賦給另一個結構(他們的類型相同時)
text a={};
//a={"asdad","2.5","2.5"};和大多數(除了string之外)混合類型一樣,不能“賦值”
cin>>a.name;//可以單元素cin,不能整體cin(cin>>a)
text b={"sadfa",2.5,2.5};//初始化方式這樣
//cout<共用體共用體可以存儲不同的數據類型,但只能存儲其中的一種類型
union one4all{
int int_val;
long long_val;
double double_val;
}pail;//可以用pail存儲int、long、double中的一種,條件是在不同的時間進行。
共用體與結構體共用
struct wight{
char brand[20];int type;
union id{
long id_num;
char id_char[20];
}id_val;//id_val為組成部分,調用時要通過id_val,id_num,id_char為id_val成員,一個有值另一個就會沒值
};
struct other{
char brand[20];int type;
union {
long id_num;
char id_char[20];
};//匿名共用體,id_num,id_char為結構體成員,一個有值另一個就會沒值
};//匿名匿的是共用體和共用體變量的名,不單單是共用體變量的名
int main(){
wight a={};other b={};
cin>>a.id_val.id_char;
cin>>b.id_num;
return 0;//這里共用的作用是,可以根據type判斷id是那種類型,這樣就減少了空間占用。
}
枚舉enum spectrum {red,orange,yellow,green,blue,violet,indigo,ultraviolet};
//讓spectrum成為新類型的名稱,它被稱為枚舉,花括號里的東西變成符號常量
spectrum a;//則a只能用花括號里的東西賦值
enum bits {one=1,two=2,three=3};
enum {on=1,tw=2,thre};//枚舉相當于多個const,但是值只能是整數
指針和NEW
指針#includeusing namespace std;
int main(){
int a=3;int* b=&a;//類型名* 指針名=&變量名
cout<
int a=80;
const int* text0=&a;//指向 const int(常量)的指針
int* const test1=&a;//指向 int 的 const 的指針(指針本身不能被改變)
//注意,可以將const數據或非const數據的地址賦給指向const的指針(不能通過指向const的指針修改數據)
//但是不能將const數據的地址賦給非const指針
指針、數組、字符串int main(){
int num_text[5]={1,3,5,7,9};
char char_text[6]={'a','b','c','d','e','\0'};
int* nt=num_text;char* ct=char_text;
cout<
對于數組與字符串而言,指針名和數組名都是指向第一個元素的指針,但是cout字符串指針時,會打印出整個字符串
使用 *指針 等效于變量名, *(指針+1)意味著下一個元素,即text[3] == *(te+3)
new 與 deletetypeName * pointer_name = new typeName
//程序員告訴new要一個什么類型的內存,new就會找到這樣一個內存塊,并返回它的指針
#includeusing namespace std;
int main(){
int n;cin>>n;
int* int_point = new int;
int* ints_point = new int[n];
char* char_point = new char;
char* chars_point = new char[n];//new可以用來創(chuàng)建動態(tài)數組
delete [] chars_point;
delete [] ints_point;
delete int_point;
delete char_point;
}//new完不要忘記delete
使用new創(chuàng)建動態(tài)結構
struct test{
int num;
char name;
};
int main(){
auto* st = new test;
cin>>st->name;
cin>>(*st).num;
cout<<(*st).name<<" "<num;
return 0;
}
d 3
d 3
int main(){
auto* st = new test[3];
cin>>(st+1)->name;
cin>>(*(st+1)).num;
cout<<(*(st+1)).name<<" "<<(st+1)->num;
return 0;
}
d 3
d 3
數組的替代品
模板類 vectorhttps://www.runoob.com/w3cnote/cpp-vector-container-analysis.html
引用變量(見函數探幽部分)
第三章 循環(huán)與關系表達式
for 循環(huán)
while循環(huán)
do…while循環(huán)
第四章 函數C++自帶了一個包含函數的大型庫(標準ANSI庫加上多個C++類),但真正的編程樂趣在于編寫自己的函數
構建函數- 提供函數定義
void functionName(parameterList)//參數列表,要說清楚參數類型和參數名
{
wuliwala;
return xxx; //可選
}
typeName functionName(parameterList)
{
wuliwala;
return xxx; //必須和typeName一樣
}
- 提供函數原型
void functionName(parameterList);//參數列表可以只寫參數類型
typeName functionName(parameterList);//在使用函數之前聲明(一般放在main()之前)
- 調用函數
functionName(實參(用逗號隔開));
注意C++對于返回值的類型有一定的限制:不能是數組,但可以是其他任何類型(整數、浮點數、指針、甚至可以是結構和對象)
但是,C++可以將數組作為結構或對象的組成部分來返回。另外,C++可以以任何數據類型為參數
void test0(int a){//以變量為參數,函數體內用的是實參的副本,副本改變不會影響實參
cin>>a;
cout<>*a;//以指針為參數,通過指針會影響實參
cout<<*a<<"\n";
}
void test2(const int* a){
//"cin>>*a;"錯誤,不能通過const的指針修改指向值
cout<<*a<<"\n";
}
//const可以保護指針指向的內容,確保它不會在函數里被修改,數組的指針也可以保護,啥都能保護
int main(){
int b;
int* c=&b;
test1(c);
cout<
int test0(int* a){
cin>>a[0];
cin>>*(a+1);
return a[0]+1;
}
//指針會被函數當做數組名直接用
int test1(int a[]){
cin>>a[0];
cin>>*(a+1);
return a[0]+1;
}
//如果實際想操作的不是數組,建議不要用指針,直接用int test(int a){}比較好
int main(){
int a[3]={1,2,3};
cout<
int a=80;
const int* text0=&a;//指向 const int(常量)的指針
int* const test1=&a;//指向 int 的 const 的指針(指針本身不能被改變)
//注意,可以將const數據或非const數據的地址賦給指向const的指針(不能通過指向const的指針修改數據)
//但是不能將const數據的地址賦給非const指針
return 0;
使用數組區(qū)間的函數/函數與字符串int sum_arr(const int* begin,const int* end){
const int* pt;
int total=0;
for(pt=begin;pt!=end;pt++){
total = total + *pt;
}
return total;
}
int main(){
int a[5]={1,2,3,4,5};
cout<
char* builder(char c,int n){
char* pstr = new char[n+1];
pstr[n]='\0';
while (n-->0){
pstr[n]='c';
}
return pstr;
}
int main(){
char* ps=builder('d',3);
//delete[] pstr;不能解放pstr,它在函數里面,應該用ps把它接出來,然后解放
cout<
函數與結構struct time{
int hours;
int mins;
};
time sum(time m,time n){
time total={0,0};
total.hours=m.hours+n.hours;
total.mins=m.mins+n.mins;
return total;
}
int main(){
time m = {3,2};
time n = {4,6};
time s = sum(m,n);
cout<
函數與二維數組int sum(int ar2[][4],int size){
int total=0;
for(int r=0;r{1,2,3,4},{9,8,7,6},{2,4,6,8}};
//data是一個數組名,該數組有三個元素,每個元素都是由4個int組成的數組
//也就是說,每個元素都是一個指針,指向由4個int組成的數組的指針
//以data為參數時,應該這樣描述:int (*ar2)[4] 或者 int ar2[][4]
//這時,我們要對行數用另一個參數加以限制
int sums=sum(data,2);
cout<
函數與stringvoid display(const string sa[],int n){
for(int i=0;i
遞歸
含義第一要素:明確函數想要干什么
對于遞歸,我覺得很重要的一個事就是,這個函數的功能是什么,他要完成什么樣的一件事,而這個,是完全由你自己來定義的。也就是說,我們先不管函數里面的代碼什么,而是要先明白,你這個函數是要用來干什么。
例如,我定義了一個函數
// 算 n 的階乘(假設n不為0)
int f(int n){
}
這個函數的功能是算 n 的階乘。好了,我們已經定義了一個函數,并且定義了它的功能是什么,接下來我們看第二要素。
第二要素:尋找遞歸結束條件
所謂遞歸,就是會在函數內部代碼中,調用這個函數本身,所以,我們必須要找出遞歸的結束條件,不然的話,會一直調用自己,進入無底洞。也就是說,我們需要找出當參數為啥時,遞歸結束,之后直接把結果返回,請注意,這個時候我們必須能根據這個參數的值,能夠直接知道函數的結果是什么。
例如,上面那個例子,當 n = 1 時,那你應該能夠直接知道 f(n) 是啥吧?此時,f(1) = 1。完善我們函數內部的代碼,把第二要素加進代碼里面,如下
// 算 n 的階乘(假設n不為0)
int f(int n){
if(n == 1){
return 1;
}
}
有人可能會說,當 n = 2 時,那我們可以直接知道 f(n) 等于多少啊,那我可以把 n = 2 作為遞歸的結束條件嗎?
當然可以,只要你覺得參數是什么時,你能夠直接知道函數的結果,那么你就可以把這個參數作為結束的條件,所以下面這段代碼也是可以的。
// 算 n 的階乘(假設n>=2)
int f(int n){
if(n == 2){
return 2;
}
}
注意我代碼里面寫的注釋,假設 n >= 2,因為如果 n = 1時,會被漏掉,當 n<= 2時,f(n) = n,所以為了更加嚴謹,我們可以寫成這樣:
// 算 n 的階乘(假設n不為0)
int f(int n){
if(n<= 2){
return n;
}
}
第三要素:找出函數的等價關系式
第三要素就是,我們要不斷縮小參數的范圍,縮小之后,我們可以通過一些輔助的變量或者操作,使原函數的結果不變。
例如,f(n) 這個范圍比較大,我們可以讓 f(n) = n * f(n-1)。這樣,范圍就由 n 變成了 n-1 了,范圍變小了,并且為了原函數f(n) 不變,我們需要讓 f(n-1) 乘以 n。
說白了,就是要找到原函數的一個等價關系式,f(n) 的等價關系式為 n * f(n-1),即
f(n) = n * f(n-1)。
找出了這個等價,繼續(xù)完善我們的代碼,我們把這個等價式寫進函數里。如下:
// 算 n 的階乘(假設n不為0)
int f(int n){
if(n<= 2){
return n;
}
// 把 f(n) 的等價操作寫進去
return f(n-1) * n;
}
至此,遞歸三要素已經都寫進代碼里了,所以這個 f(n) 功能的內部代碼我們已經寫好了。
例子//斐波那契數列的是這樣一個數列:1、1、2、3、5、8、13、21、34....,
// 即第一項 f(1) = 1,第二項 f(2) = 1.....,第 n 項目為 f(n) = f(n-1) + f(n-2)。
// 求第 n 項的值是多少。
int fibo(int n){
if(n<=2){
return 1;
}
return fibo(n-1)+fibo(n-2);
}
int main(){
cout<
//一只青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
int gua(int n){
if(n<=2){
return n;
}
return gua(n-1)+gua(n-2);//第一次跳一級還剩n-1級,跳兩級還剩n-2級
}
int main(){
cout<
函數指針#includedouble betsy(int);
double pam(int);
void estimate(int lines, double (*pf)(int));//傳參時特征標和返回值都應匹配
// 第二個參數是一個函數指針,它指向參數為int、返回值為double的指針
int main()
{
using namespace std;
int code;
cout<< "How many lines of code do you need? ";
cin >>code;
cout<< "Here's Betsy's estimate:\n";
estimate(code, betsy);
cout<< "Here's Pam's estimate:\n";
estimate(code, pam);
// cin.get();
// cin.get();
return 0;
}//函數指針使得一個函數可以調用不同的函數
//直接在函數中調用函數則做不到這一點
double betsy(int lns)
{
return 0.05 * lns;
}//兩種函數對應兩種“算法”
//使用函數指針可以靈活的任意調用
double pam(int lns)
{
return 0.03 * lns + 0.0004 * lns * lns;
}
//函數名就是函數指針,聲明指針的格式:typeName (*pointName)(argumentType)
void estimate(int lines, double (*pf)(int))
{
using namespace std;
cout<< lines<< " lines will take ";
cout<< (*pf)(lines)<< " hour(s)\n";
}//(*pf)可以是任意滿足類型的函數,而不是確定的函數
How many lines of code do you need?30
Here's Betsy's estimate:
30 lines will take 1.5 hour(s)
Here's Pam's estimate:
30 lines will take 1.26 hour(s)
const double* f1(const double ar[],int n);
const double* f2(const double [],int);//返回值為指向常量的指針,參數列表為常量數組和int
const double* f3(const double *,int);
//需要注意的是,f1、f2、f3的特征標看似不同,但實際上相同
//接下來聲明一個指針,它可指向這三個函數之一,假設給指針名為pa
const double* (*pl)(const double*,int);
const double* (*pl)(const double*,int) = f1;//可以在聲明的同時初始化
auto p2 = f2;//用auto將更加方便
typedefint main(){
typedef double real;
real a=3.5;
typedef const double* (*p_fun)(const double*,int);
//*p_fun = f1錯誤用法
p_fun f1;//正確用法
typedef int* test;
test b;//正確用法
//*test b;錯誤用法
}
第五章 函數探幽
內聯函數常規(guī)函數和內聯函數之間的主要區(qū)別不在于便攜方式,而在于C++編譯器如何將他們組合到程序中
用通俗的語言來講,普通函數在程序調用函數時,會跳到函數內存塊,再跳回來,
而對于內聯函數,編譯器將使用相應的函數代碼替換函數調用,
內聯函數的運行速度比常規(guī)函數稍快,但需要占用更多內存。
#includeusing namespace std;
//使用inline函數,必須在函數聲明和函數定義前加上關鍵字inline
inline double square(double x)
{
return x * x;
}//這里直接在main之前定義,就不用再聲明了
int main()
{
double a, b;
double c = 13.0;
a = square(5.0);
b = square(4.5 + 7.5); //可以用表達式做參數
cout<< "a = "<< a<< ", b = "<< b<< "\n";
cout<< "c = "<< c;
cout<< ", c squared = "<< square(c++)<< "\n";
cout<< "Now c = "<< c<< "\n";
return 0;
}
a = 25, b = 144
c = 13, c squared = 169
Now c = 14
引用變量C++新增了一種復合類型——引用變量,引用是已定義的變量的別名,它最主要的用途是用作函數的形參,
通過將引用變量作為參數,函數將使用原始數據,而不是其副本。
//C和C++使用&來指示變量的地址,C++給&符號賦予了另一個含義
int rats;
int& rodents = rats;//使rodents成為rats的另一個名字
//在上句中,&不是地址運算符,而是類型標識符的一部分
//就像char*表示指向char的指針一樣,int&是指向int的引用
//上述引用聲明允許將rats和rodents互換,它們指向相同的值和內存單元
int rats = 101;
int& rodents = rats;
int* prats = &rats;
//引用看上去很像(*指針),但實際上,引用還是不同于指針的,除了表示方法不同外,還有其他差別
//比如,引用不能像指針那樣,先聲明、再賦值,必須在聲明引用變量時同時初始化
//引用更接近const指針,必須在創(chuàng)建時初始化,一旦與某個變量關聯起來,就將一直效忠于它。
int& rodents = rats;
int* const pr = &rats;
//二者類似,其中引用rodents扮演的角色與表達式*pr相同
//引用變量的值一旦確定,就不會更改
int rats = 101;
int* pt = &rats;
int& rodents = *pt;//rodents在此處初始化
int bunnies = 50;
pt = &bunnies;//將pt改變,而rodents似乎會隨著pt改變(畢竟初始化的時候,rodents是*pt的別名)
//但是,rodents并不會被改變,因為它效忠的永遠是那一刻的*pt,也就是rats
//哪怕*pt在未來變了,它也不會改變
將引用作為函數參數引用經常被用作函數參數,使得函數中的變量名成為調用程序中的變量的別名
這種做法并沒有繞過引用不能先定義再賦值的設定,因為函數直到被調用,它里面的變量才會被定義
void swapr(int& a, int& b)
{
int temp;
temp = a; a = b; b = temp;
}
void swapp(int* p, int* q)
{
int temp;
temp = *p; *p = *q; *q = temp;
}
void swapv(int a, int b)
{
int temp;
temp = a; a = b; b = temp;
}
int main()
{
using namespace std;
int wallet1 = 300; int wallet2 = 350;
cout<< "wallet1 = $"<< wallet1<< " wallet2 = $"<< wallet2<< endl;
cout<< "Using references to swap contents:\n";
swapr(wallet1, wallet2);//參數傳遞實現了int& a=wallet1 和 int& b=wallet2
cout<< "wallet1 = $"<< wallet1<< " wallet2 = $"<< wallet2<< endl;
cout<< "Using pointers to swap contents again:\n";
swapp(&wallet1, &wallet2);//參數傳遞實現了int* a=&wallet1 和 int* b=&wallet2
cout<< "wallet1 = $"<< wallet1<< " wallet2 = $"<< wallet2<< endl;
cout<< "Trying to use passing by value:\n";
swapv(wallet1, wallet2);//參數傳遞實現了int a=wallet1 和 int b=wallet2
cout<< "wallet1 = $"<< wallet1<< " wallet2 = $"<< wallet2<< endl;
return 0;
}
wallet1 = $300 wallet2 = $350
Using references to swap contents:
wallet1 = $350 wallet2 = $300//使用引用互換,成功
Using pointers to swap contents again:
wallet1 = $300 wallet2 = $350//使用指針互換,成功(又換回來了)
Trying to use passing by value:
wallet1 = $300 wallet2 = $350//使用副本互換(值傳遞),失?。]變)
注意事項避免返回函數終止時不再存在的內存單元引用
const int& clone(int& ft)//本代碼塊為錯誤示范
{
int a;
a=ft;
return a;//把ft的值給了a,并且返回a
}//該函數返回了一個臨時變量的引用
const string& version3(string& s1,const string& s2)
{
string temp;
temp = s2+s1+s2;
return temp;//返回了臨時變量的引用
}
string version1(const string & s1, const string & s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;//返回類型為string,temp將被復制到一個臨時存儲單元
}
const string & version2(string & s1, const string & s2) // has side effect
{
s1 = s2 + s1 + s2;
return s1; //返回了已有的引用
}
const string & version3(string & s1, const string & s2) // bad design
{
string temp;
temp = s2 + s1 + s2;
return temp;//返回了臨時變量的引用,錯誤示范
}
int main()
{
string input;
string copy;
string result;
cout<< "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 original string: "<< input<< endl;
result = version2(input, "###");
cout<< "Your string enhanced: "<< result<< endl;
cout<< "Your original string: "<< input<< endl;
cout<< "Resetting original string.\n";
input = copy;
result = version3(input, "@@@");
cout<< "Your string enhanced: "<< result<< endl;
cout<< "Your original string: "<< input<< endl;
return 0;
}
Enter a string:sdfaf
Your string as entered: sdfaf
Your string enhanced: ***sdfaf***
Your original string: sdfaf
Your string enhanced: ###sdfaf###
Your original string: ###sdfaf###//version2直接用了input的引用,導致input也隨之變化
Resetting original string.
Process finished with exit code -1073741819 (0xC0000005)//version3報錯
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
網站欄目:C++學習筆記(更新)-創(chuàng)新互聯
當前URL:http://bm7419.com/article20/cdidjo.html
成都網站建設公司_創(chuàng)新互聯,為您提供軟件開發(fā)、網站維護、企業(yè)網站制作、商城網站、營銷型網站建設、手機網站建設
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源:
創(chuàng)新互聯