01
1 預編譯常用的有,宏定義和包含庫。
2 庫:是實用工具的集和,由程序員編寫,可以完成一些特定的功能。
3 <> 系統庫 ""用戶自定義庫。
4 宏定義:定義符號常量,符號常量就是給常量取的名字。常量是在程序運行中不變的值。
? #define Pi 3.1415 (編譯后,進行用3.14替換PI,寫用PI) 這里的PI 就是給常量3.14取的一個名字。預編譯后進行替換。
? 此處是C語言常用。
? C++中一般使用const int pi=3.1415;(必須賦初值,以后不能改)
5 名字空間:大型程序由很多源文件組成。有可能很多人編寫的,而每個人都可以定義自己的函數,變量等。
? 為了避免重名,引入名字空間。同一個名字空間不可重名。
6 C++標準庫中的實體都是定義在名字空間std中。所以在引用標準庫的中名字,都需要指出名字空間std中的實體。
? 這解決了一疑問,就是using namespace std 和沒有 它的情況,前者 使用了后,就不要在指明。
7 C++處理的每一個數據必須指明類型。一個數據類型就是事先定義好的工具。2個特征:在內存如何表示,允許執行哪些運算。
8 整型數的溢出:設想 0111111111111111 (+32767) 讓他進行+1 操作,就會發生不是按照正常的想法來的+32768,而是
? 100000000000000(注意,此處不是-0,由于負數是用補碼表示,因此,這個是-32768)
9 實型的分類:float(4B),double,long double(8B,這個都是8B 為什么還要分long和非long呢?)
? 在float中,1B用于存指數,3B用于存尾數,因此,float表示的范圍是:2的-128次方 到 2的127次方。
? 注意:實數在計算機內是不能準確表示的,因此,無法對兩個實數采用相等比較。
10 實數常量:第一種,123.4,第二種,科學計數:尾巴*10的指數次方 123*10的三次方,可以記著:123e(E)3
?? 注意:e后必須是整數,e前必須由數字,如10的5次方,要表示成1e5
11 比較字符是比較他們的ASCII值,字符也就是‘2’,‘A’,如何判斷字符為數字,大寫字母?
?? if(ch>='0' && ch<='9')
?? if (ch>='A' && ch<='a')
12 如何輸出“” ,需要使用轉義字符 \, 另外一個,轉義字符\177(其中177是八進制,對應十進制為127),‘\n’ 也是字符常量。
13 typedef 就是重新命名類型名 如 typedef int INT,這個時候,就可以用INT,和int 作用一樣功能。
14 在執行運算過程中,c++ 只執行同類型的數據進行運算。因此 會發生自動類型轉換。轉換原則:非標準 轉換成標準類型,占用
?? 空間少的像大的進行轉換。數值范圍小的向范圍大的靠攏。
15 如果輸入的變量是字符,可以通過,cin.get(ch) or ch=cin.get(); (ch='a')
?? 注意:>> 認為空格和換行有特別的功能,會把它當作當成空白符號,而get 函數可以接收任何字符,包含 空白。
16 關系運算也就是大小于,等于等,>,<,==,!=,的優先級高于前兩個高于后面的兩個
17 !的優先級最高) &&(第二)? ||(最低),如 !p || q && r (先計算!p 然后q&&r)
18 如何判斷一個浮點數是否為0?if(fabs(a)<1e-6) ? cout<<“it is zero”
02
?1 如何求x的i次方 ?
??? 對于,for(int i=1;i<n;i++) x*=x;
? ? 這個應該是錯誤的,因為每次的結果,x的值發生了變化
? ? 就得不到i個x乘積的結果
??? 正確的應該是:
??? for(int xn=1,j=1;j<=n;++j) xn*=x;
??? 此為:x的i次方的結果
?? 其實,可以用cmath庫的一個函數 pow(x,i)
2 求n的階乘的兩個方法
?a:遞歸
?b:利用for循環,
?for(int j=1;j<=n;j++)
? ?? int result=1;
? ?? result*=j;
3 求解e的x次方代碼:
?
#include<iostream> using namespace std; double ex(int x){double ex=0; double p=1;int i=0;while(p>1e-6){ex+=p;++i;p=p*x/i;}return ex; }int main(){int x;cout<<"input x:"<<endl;cin>>x;double e=ex(x); cout<<"e 的"<<x<<"次方等于:"<<e<<endl;return 0; }
1 內存溢出:訪問數組的時候,由于不會檢查下標,所以,訪問一個int a[10] ,使用a[11],導致出現內存溢出。
2 在二分查找 需要注意,mid=(lh+rh)/2 因為在while循環中,每次都要作,所以放在whiel內部。
3 判斷一段話 由多少個單詞
#include<iostream> using namespace std; int main(){char sentence[80];char prev=' ';int i,counter=0; //counter沒有賦初值cin.getline(sentence,80);for(i=0;sentence[i]!='\0';++i)//循環寫成作80次,完全美必要 {if(prev==' ' && sentence[i]!=' ') counter++; //==錯誤寫成=prev = sentence[i];}cout<<"have "<<counter;return 0; }
?
03
1 函數命名規則: ?
? 如果1個,用一個小寫開頭的
? 如果有2個,第一個字母大寫:UpdateBig()
2 void類型的函數,看作是過程。
3 retrun 表示函數結束。沒有返回值,就表示函數結束。
4 函數調用過程:
5 計算return 后面表達式子的值,然后創建一個臨時變量,存放return的值。
6 系統為調用函數分配一快內存空間,稱為幀。
7 我們知道向函數傳遞的參數,可以2個,3個,這分為值傳遞,和引用傳遞,這個簡單
? 如果,要向函數傳遞100個呢,需要傳遞數組。
? 函數原型 應該類似
? int average(int a[10]) //這個10應該沒有意義 ,可以看作是引用傳遞哦,會改變數組的值的。,
? 正確的是,(int a[],int n) 前面只是一個地址,
8 內聯函數:函數調用會有額外開銷(固有的),函數執行也會浪費時間。如果函數小,執行時間短,
? 調用內聯函數時候,會把內聯函數的代碼復制插入到調用它的位置上。加長了生成的目標代碼。一般都是短小,精悍的代碼。
9 重載的必要條件:
? 參數數目不同
? 參數類型不同
? 滿足之一就可。
10 靜態全局 ,不能被其它原文見引用. 靜態局部,其它函數不能引用, 二者特點,在程序結束前都會一直存在。
? 在程序結束時,先殺靜態局部,在殺全局(不是靜態的)
11 extern :外部變量,首先一定時全局變量,
04
1 c++中只運行類型相同的指針互相賦值。
2 void類型指針只說明它是一個地址,但是沒有說明存放何種類型,因此,可以與任何類型指針進行賦值。
3 const int* p=&x ,指向常量的指針,*p不能改變,但是p=&y可以
? int * const p=&x,常指針,p=&y不可以,但*p可以改變。由于x地址固定,也就是說它只能指向x的地址。(常量性質)
? 綜合,指向常量的常指針,只能指向x,且不能修改x的值。
4 與數組的關系:關系非常密切,幾乎可以互換使用。
? 首先數組名可以看作一個指針,且時常量指針,也就是說,永遠指向這一個地址。如果,指針p=數組名,那么,它們可以等價
? 就有,p[3]=a[3]
? 指針的運算一般之和數組有關,對一個變量的指針運算沒有絲毫的意義。p+i = & a[i]
? p1+p2,沒有任何意義,但是p2-p1,表示他們之間元素個數。
? 數組名可以當作指針,=&a[0]
? 但是,他們不完全等價。知道就好。
5 動態內存
? int *p=new int;
? *p=10
? 等價與:int *p=new int(10);
?int *p=new int[10];
?和普通數組的區別:下標可以時2*n,既可以時表達式的值或者變量,而普通數組,必須時常量。
6 動態變量的存活:即使在函數里面,它也會一直存在,需要使用delete顯示刪除。
? delete p;
? delete [] p;
? 注意,如果時字符數組,可以使用delete p;
7 內存泄露:動態變量不用的時候i,沒有delete,就是動態變量沒有被釋放。導致,內存耗盡。
8 使用斷言確定new 是否成功
? #include<cassert>
? #i...
? {
??? int *p=new int;
??? assert(p!=0); //斷言不是真,就退出。
??? *p=20;
?? }
9 指針的應用:求方程的兩個根,使用void SolveQuadratic(double a,double b,double c,double *x1,double x2) ,首先在main函數里面定義兩個整形變量,然后傳地址到這個函數,這個根的值就可以保存起來了,可以保存兩個哈哈。不需要返回值。當然,可以返回其它的值。用作判斷。后面兩個稱為輸出參數。
10 數組作為函數參數,本質時地址傳遞,
? int a[]={2,3,4};
? sizeof(a)=12
? void f(int arr[])
?? sizeof(arr) =4 //此處為1個指針占用的字節。
11 統計字符串單詞個數
? int WordCount(const char *str) //傳遞字符串到函數。 它內涵\0
? {
??? int cnt=0;
?? while(*str!='\0'){
?? ?while(*s==' ') s++; //跳空白
??????? if(*s!='\0'){
?? ??? ?++cnt;? //找到一個單詞
?? ??? ?while(*s!=' '&& *s!='\0') s++; //跳過單詞
??? ?}
?? }
? return cnt;
12 函數的返回值可以時一個指針
? 比如,從一個字符串中取出一個字符串。char *subString(char *s,int start,int end)
?? int len=strlen(s);
?? if(start,end yu len de guanxi)
?? char *sub=new char[end-start+2];
?? strcpy(sub,s+start,end-start+1);
?? sub[end-start+1]='\0';
? return sub; //sub時動態的空間,離開函數依然可以用哦。
13 函數的返回值時引用 ,特點時不需要創建臨時變量保存返回值,直接返回變量本身,
?? 要確保這個變量在執行后存在。
14 main函數的參數,int main(int argc,char *argv[]),argc ,所有打出來的參數個數,argv[i],參數字符名字 argv[0]一般表示,執行文件名字
05
1 結構體的定義是如何定義的
struct Student{
?? ?char name[20];
?? ?int age;
}stu1;
stu1,是變量(對象),而Student就相當于一個類型,類似類中的類型名
也可以使用,Student stu2;定義一個結構體變量。
對于
struct{
?? ?char name[2];
?? ?int age;
}stu1;這個就不能在定義變量了,而前者是可以的。
使用花括號進行賦值。
<對于數組,不能使用a={1,2,3},而結構體可以,因此數組不能是左值,結構體則可以>
2 結構體和指針的關系?
結構體可以通過指針來進行訪問,其實是和變量一樣,都是通過指針簡介訪問
要注意指針的類型必須是結構體類型名
比如:Student *pst;
類似:
strut Student{
?? ?char name[2];
?? ?int age;
}*pst;
則,可以有pst=&stu1;
或者:pst=new Studnet;
而指針訪問通過-> ,如pst->name; 如同stu1.name;
3 什么是結構體數組?
定義了一個類型后,Student,他就可以定義數組了,Student stuArray[10];
4 結構體一般是什么傳遞?
首先它同基本數據類型一致,都是值傳遞。(會涉及到復制)
由于結構體一般比較大,選擇引用傳遞(指針過于復雜)
因為指針或引用傳遞這,形參和實參就公用了一塊內存,對形參改動,也就會改動實際參數,要解決這個防止實參被改變,可以使用const限定符,
<關于 A f(); 返回值的是一個副本,其實,也就是臨時變量>
struct Point{
?double x,y;
};
int main(){
? Point p1,p2;
? p1=setPoint(1,2);
? cout<<p1;
}
Point setPoint(double a,double b){
?? ?Point p;
???? p.x=a;??? //在函數結束,p死亡之前,賦值給一個臨時變量,所以沒問題,對引用是絕對不可以哦,~~,因為,消失了還怎么引用。
??? p.y=b;
?? return p; //我們在引用返回的時候,是不可以返回局部變量的,但是,這個不是,可以返回,
???????? //它會創建一個臨時變量,在函數結束的時候,回收幀后,然后把零食變量賦給p1;
}
5 鏈表是作用是什么?鏈表和數組的關系,可以用數組取代嗎?
它用來存儲一組同類數據。類似數組,但是數組使用的時候,必須確定元素個數。如果,元素個數不確定,并且數目很大的情況下,使用鏈表。
它可以進行動態內存分配的結構。不需要實現準備好一塊內存空間,當增加一個元素的時候,動態為它申請存儲空間,這楊的結果是,元素不是連續存儲的。這楊
找元素就比較難了,通過鏈來指向下一個節點的位置。也就是指向下一個節點的指針。
6 單鏈表是如何存儲的?它是一個結構體?
存儲一個單鏈表值需要存儲第一個節點的地址(也就是頭指針)
節點類型定義如下(是一個結構體)
struct LinkNode{
?? ?datatype data;
?? ?LinkNode *next;
};
7 單鏈表常用的有哪些基本操作?
創建,插入,刪除,訪問;
插入:在p節點后進行插入,步驟:
a:申請一個結點
b:將x放入這個結點數據里面
c:新結點和下一個結點鏈接
d:和新結點鏈接(都是針對當前結點(插入其后方))
注意cd順序,如果不當,可能造成后續結點失蹤的問題。
刪除:刪除結點x
a:找到x結點前的那個結點p
b:然后繞過x就可以了
p->next=p-next->next
注意:p->next 是和LinkNode 等價。
注意:上面的會導致內存泄露。需要回收空間。
完整的:
detPtr=p-next;
p->next=detPtr->next;
delete delPtr;
注意,這種情況假設了要刪除的結點前面是有一個結點的情況,特殊的,如何刪除第一個結點?同時,也不允許插入在第一個結點前面?
引入頭結點來解決這個問題。
8 什么是頭結點?作用是什么?
? 它不存放任何數據,它的指針指向第一個結點,引入頭結點后,依然有頭指針head。
? 那么有了它,就可以刪除第一個結點(有數據的點),以及插入為第一個結點。
? 反正,這個家伙很有用,可以簡化代碼。
#include<iostream> //值用一個p刪除測試 using namespace std; struct linkNode{int data;linkNode *next; //因為這個指針要指向linkNode的數據,就如int 類型的指針指向int 類型數據 }; int main(){linkNode *head,*p,*q;linkNode a={5,NULL}; //可以通過這種結構賦值,因為它是一個結構體 cout<<sizeof(a);return 0; }
?
#include<iostream> using namespace std; struct linkNode{int data;linkNode *next; //指向下一個結點的指針,必須有 }; int main(){int x;linkNode *head,*p,*rear; //head 頭指針,p被操作的當前指針,rear,表尾結點(也就是指向)head=rear=new linkNode; //此處生成頭結點,頭指針while(true){cin>>x;if(x==0) break;p=new linkNode;p->data=x;rear->next=p;rear=p;}rear->next=NULL; //表尾結點為空。cout<<"鏈表內容:"<<endl;p=head->next;while(p!=NULL){cout<<p->data<<'\t';p=p->next;}cout<<endl;return 0; }
#include<iostream> //約瑟夫環的問題 using namespace std; struct linkNode{int data;linkNode *next; }; int main(){int n;cout<<"please input the number of the people:"<<endl;cin>>n;linkNode *head,*p,*q;head=new linkNode;head->data=0;p=head;for(int i=1;i<n;i++){q=new linkNode;q->data=i;p->next=q;p=q;}p->next=head;//刪除過程q=head;/*while(q->next!=q){ //只要還多于兩個結點。p=q->next;q=p->next;//刪除一般需要一個輔助結點p->next=q->next;cout<<"被刪除的編號是:"<<q->data<<endl;delete q;q=p->next; //重新開始}**/for(;q!=q->next;){p=q->next;q=p->next;p->next=q->next;cout<<"被刪除的結點:"<<q->data<<endl;delete q; q=p->next;}cout<<"最后的勝利者是:"<<q->data<<endl;return 0; }
?
06
1 什么是抽象?怎樣理解它?
抽象是解決復雜問題的基本方法。所有的程序設計語言都提供抽象
a:機器語言對硬件進行抽象,程序員通過一些列二進制對計算機操作,而無需理解計算機硬件
b:高級語言對機器語言進行抽象,不用關心下層次怎么操作的。
2 面向過程和面向對象解決問題的思考方式有什么區別,舉個例子。
在面向對象設計中,主要工作是根據要解決的位難題創建新的數據類型,用這個類型的對象完成指定工作。
在求園的面積時候,
面向過程的方式:
a:輸入半徑
b:使用面積公式求出
c:計算出結果
面向對象的方式:
a:首先考慮需要什么工具,需要一個圓,需要保存一個圓
b:這個圓有什么特性,如半徑,周長
c:只要定義一個圓類型變量,來保存一個圓。然后這個變量告訴我們面積多少。
3 庫和類之間的關系是什么樣的?
c++數組的3個問題:
a:下標必須從0開始
b:不檢查下標是否越界
c:數組大小必須編譯時確定
對于array庫的幾個缺點說明:
a:每次調用與數組相關的,都要傳遞一個結構體
b:命名沖突,比如,其他庫,也有可能叫initialize的函數,如果調用(注意此時還沒有引入類)同時出現,就沖突了
c:用完還需要用戶顯示的歸還空間,不合適。
需要改進:arrayImprove.h
改進后,就避免了命名沖突,此時,函數的調用需要和結構體的變量一樣,通過.來進行,而且這些函數隸屬于結構體變量的成員
對于.h文件,它的名字的重要作用是要被包含在cpp文件里面。所以,文件名字很重要。要起的好。
4,類和其內聯函數什么關系
如果把成員函數的定義直接寫在類中,那么就默認是內聯函數。
當然,也可以把內聯定義寫在外面,然后用inline修飾就可以了。
5 如果用指針指向一個動態分配的空間,那么就可以通過指針來訪問任意元素,記住,它支持下標訪問。
6 對于課本中Raitional類的定義說明
a:工具函數不需要用戶自己調用,是類的內部工作。把它定義為私有的,可以通過類的成員函數來訪問。
實現方法:找出分子(num),分母(den)最大公因子,讓他們分別除以
?? ?int temp=num>den?num:den;
?? ?for(;temp>1;--temp)
?? ??? ?if(num%temp==0 && den% temp ==0){ num/=temp;den/=temp;break;}
?? ?}
7 對象定義有幾種方法,區別是什么?
a:普通變量一樣定義 Rational r1;
b:動態內存申請 Rational * p=new Rational; 這個時候,釋放對象,需要通過delete刪除指針就可以了。
???? 此時,就可以用 p->來訪問成員函數。
8 struct 中也有和類一樣的隱藏this指針,看來struct和類確實區別不大。
?? 當用對象調用成員函數的時候,編譯器會把相應的對象地址傳給形式參數this。
? 構造函數:不是由類的用戶調用,而是由系統在定義對象的時候自動調用,主要工作是對對象進行初始化。
? 初始化列表的作用:提高構造函數效率,能夠讓數據成員初始化和賦值同時進行。
? 特殊情況,必須使用:數據成員不是普通類型,是一個類對象,另一個包含常量的數據成員。
9 拷貝構造函數為什么存在?以及什么時候會被調用?
? 它以一個同類對象的引用作為參數
? 類名(const <類名> &)
? 默認系統會自動生成一個拷貝構造函數,通常情況下,默認的就能夠完成任務,但是,當數據成員含有動態分配的對象的時候,需要小心,最好自己寫一個
a:對象定義時: 如果之前,都定義好的,那么在=還會調用嗎,不會,
A a1(a2);
A a1=a2;
b:函數調用時
void f(A a)//要求要是值傳遞,如果參數時A a,A &b ,那么前者才會復制構造,而后者不會。
A b;
f(b) ; //首先創建一個形參對象a,然后,調用拷貝復制,用b初始化a,
c:函數返回
A f() //用戶自定義的類
{? //如果返回的時自定義類的引用會調用馬?黑,測試
? A a;
? return a; //執行到return,創建一個臨時對象,調用拷貝復制,給臨時對象。
}
代碼測試:
9 常量對象的存在以及用法?
如果把一個對象定義為常量
const Ration r(2,3);
只能初始化,不能賦值(初始化,會涉及到賦值,但是不一定要=,而=時賦值)
我們知道,修改對象都是通過成員函數來修改,所以,常量對象只允許調用常量成員函數。
const成員函數意思是:它告訴編譯器,它時安全的不會修改對象的數據成員的值。
使用的時候,類內聲明要加const,類外定義也要加入const,否則將會看成兩個函數/
任何不修改對象的成員函數都應該聲明為const的。也可以被其它對象調用。
10 常量數據成員如何使用?
它表示,他在對象生存期內是常量,即在對象生成時給出常量值,而在此對象生存期內,它的值不能改變。
class A{
?? ?private :
?? ??? ?const int size;
}
//必須在構造函數中進行初始化,而且一定時在初始化列表中完成。
11 靜態數據成員和靜態函數存在的意義,以及使用注意?
靜態數據成員屬于整個類,被它所有的對象共享(意味所有對象都可以使用)。和全局變量的使用區別:缺乏對數據的保護,所有的都能訪問,不安全,又體現不出和類的關系
我們知道,類定義只是給出了對象的構成,真正分配空間時在對象生成的時候。由于靜態數據不屬于對象,所以,靜態數據時單獨分配的。
只能分配一次,并且在cpp文件中實現。
類內使用static,類外不需要。
比如,我的利率時靜態數據,但是,有一天我突然變了,就需要一個靜態員函數來修改。這是它存在的意義,類內使用static,類外不需要
它可以通過對象來調用,常見的使用類名調用。
它是為類服務的。最大的特點是沒有隱藏的this指針。因此,它不能訪問一般的數據成員,只能訪問靜態數據和其它靜態成員函數。
用法:初始化靜態數據的值,普通成員函數完成不了的任務。
12 靜態常量static const int size的用法
當類需要共享一個常量,使用它。
一般來說,類的數據成員不能在類定義的時候初始化,普通的數據成員是在構造函數時進行初始化。靜態數據時在定義時初始化。而這個,必須在類定義時候i初始化。
用法:某個類需要用到一個數組
class A{
?? ?static const int SIZE=10;
?? ?int storage[SIZE}
}
對于不支持的使用枚舉代替
?enum {SIZE=10};
?int storage[SIZE];
13 友元如何使用?注意事項
訪問類的私有成員開一個后門,能夠使得全局函數和其它類的成員函數訪問到類的私有成員。
可以有:
友元函數:全局函數
友元類:外部類
友元成員函數:類的某一成員函數
友元關系時授予不是索取:
如果f時A的友元,在A中必須聲明。而不是f自稱時A的友元。
通常,把友元放在類內部第一行,并且不要加訪問控制。它不支持,對稱和傳遞。
#include<iostream> ?//拷貝構造函數調用的順序 using namespace std;class A{int x;public:A(int b=0):x(b){cout<<"construt instance :"<<x<<endl;}A(const A & ar){x=ar.x; cout<<"調用拷貝構造函數了。"<<endl;}void display(){ cout<<" x :"<<x<<endl;}~A(){cout<<"析構 :"<<x<<endl;} }; A global(5); //1, 全局對象,比main還早。 void f(){cout<<"start f():"<<endl;A a(3);static A local(4); //執行到f內部才開始執行這個 ,在main函數結束后開始析構,和全局相比,它首先析構 } int main(){A a(2);//2 ,執行mainA b(a);//3 ,調用拷貝構造//b=a;//這個不會調用,因為不是定義b的時候初始化// A c=b;//這個調用拷貝 f();return 0; }
?
07
08