1、C++的const比C語言#define更好的原因?
首先,它能夠明確指定類型,有類型檢查功能。
其次,可以使用C++的作用域規則將定義限制在特定的函數[常函數]或文件中。
第三,可以將const用於更復雜的類型,比如數組和結構。
C語言中也有const,在C語言中分配內存,其與C++中const的區別是:一是作用域規則不同;另一個是,在C++中可以用const值來聲明數組長度。在C++中const在沒有取地址和加extern時,是不分配內存空間的,和#define有相同的效果,常量折疊。
注意:外部要能訪問test.cpp中的const形式的n, 必須在test.cpp中定義的時候用extern限定。
test.cpp
extern const int n = 100; //必須加extern
#include <iostream>
using namespace std;
extern const int n;
int main()
{
cout << n << endl;
return 0;
} </iostream>
2、逗號運算符
逗號運算符的特性有下面幾個:
(1)它確保先計算第一個表達式,然后計算第二個表達式;
i = 20, j = 2 * i; // i set to 20, then jset to 40
(2)逗號表達式的值是第二部分的值。例如,上面表達式的值為40。在所有運算符中,逗號運算符的優先級是最低的。例如:
cats = 17, 240; //被解釋為:(cats =17), 240;
也就是說,將cats設置為17,后面的240不起作用。如果是:
cats = (17, 240); //cats=240。
3、不能簡單地將整數賦給指針,如下所示:
int *ptr;
ptr = 0x12342342; // type mismatch
在這里,左邊是指向int的指針,但右邊是一個整數。在C99標准發布之前,C語言允許這樣賦值。但C++在類型一致方面的要求更嚴格,編譯器將顯示一條錯誤消息,通告類型不匹配。要將數字值作為地址來使用,應通過強制類型轉換將數字轉換為適當的地址類型:
int *ptr;
ptr = (int *) 0x12342342; // type now match
這樣,賦值語句的兩邊都是整數的地址,因此這樣賦值有效。但是這樣做很危險。隨意的數值可能是指向系統的重要文件,這樣就會是系統崩潰。
注意,pt是int值的地址並不意味着pt本身的類型是int。例如,在有些平台中,int類型是個2字節值,而地址是個4字節值。
4、C++的多態性分為靜態多態和動態多態。
靜態多態性:編譯期間確定具體執行哪一項操作,主要是通過函數重載和運算符重載來實現的;
動態多態性:運行時確定具體執行哪一項操作,主要是通過虛函數來實現的。
5、下面的程序輸出結果是多少?
#include
int main()
{
int x=2,y,z;
x *=(y = z = 5); printf(“%d\n”,x); //10
z = 3;
x ==(y = z); printf(“%d\n”,x); //10
x =(y == z); printf(“%d\n”,x); //1
x = (y&z); printf(“%d\n”,x); // 與運算 3
x = (y&&z); printf(“%d\n”,x); //1
y = 4;
x = (y | z); printf(“%d\n”,x);//或運算 7
x = (y || z); printf(“%d\n”,x);//1
return 0;
}
6.下面的程序輸出結果是多少?
#include
main()
{
int b = 3;
int arr[] = {6,7,8,9,10};
int *ptr = arr;
*(ptr++)+=123;//先算等號右邊再算左邊的;
//*ptr=*ptr+_123; 即arr[0]=129;
//千萬不要認為是:*(ptr++)=*(ptr++)+123;
//還有就是要認清++和--的作用;
printf(“%d,%d\n”,*ptr,*(++ptr)); //8 8
//printf函數的運算設計到進棧和出棧,運算順序是從右向左;
//先算*(++ptr),后算*ptr;
printf("%d\n",arr[0]); //129
}
7、C++存儲方案:C++三種,C++11四種
這些方案的區別就在於數據保留在內存中的時間。
自動存儲持續性:在函數定義中聲明的變量(包括函數參數)的存儲持續性為自動的。它們在程序開始執行其所屬的函數或代碼塊時被創建,也即用到時分配內存,在執行完函數或代碼塊時,它們使用的內存被釋放回收,且能夠重復使用。C++有兩種存儲持續性為自動的變量。
靜態存儲持續性:在函數定義外定義的變量和使用關鍵字static定義的變量的存儲持續性都為靜態。它們在程序整個運行過程中都存在,且靜態變量一開始就在內存中。C++有3種存儲持續性為靜態的變量。
動態存儲持續性:用new運算符分配的內存將一直存在,直到使用delete運算符將其釋放或程序結束為止。這種內存的存儲持續性為動態,有時被稱為自由存儲(free store)或堆(heap)。
線程存儲持續性(C++11):當前,多核處理器很常見,這些CPU可同時處理多個執行任務。這讓程序能夠將計算放在可並行處理的不同線程中。如果變量是使用關鍵字thread_local聲明的,則其生命周期與所屬的線程一樣長。本書不探討並行編程。
8、自己寫string類注意事項:
CString & CString::operator=(constCString &st)
{
if(this == & st)
return * this;
delete [] str;
len= st.len;
str= new char [len + 1];
strcpy(str,st.str);
return *this;
}
主要注意一下四點:
(1)、是否把返回值類型聲明為該類型的引用?並在結束前是否返回該實例自身的引用(保證連續賦值);
(2)、是否把參數設置為const &?(否則會調用拷貝構造函數,其次防止意外改變參數)
(3)、是否記得釋放自身的內存?(否則會內存泄露,指針指向了其他的地方)
(4)、是否進行了實例對象的等值判斷,是否為同一個實例?(否則釋放實例的時候,將參數的內存頁釋放,找不到賦值對象引起錯誤)
9、虛函數原理考點,例如下面程序的輸出是什么?
class A {
public:
virtual void funa();
virtual void funb();
void func();
static void fund();
static int si;
private:
int i;
char c;
};
問:sizeof(A) = ?
解答:
關於類占用的內存空間,有以下幾點需要注意:
(1)如果類中含有虛函數,則編譯器需要為類構建虛函數表,類中需要存儲一個指針指向這個虛函數表的首地址,注意不管有幾個虛函數,都只建立一張表,所有的虛函數地址都存在這張表里,類中只需要一個指針指向虛函數表首地址即可。
(2)類中的靜態成員是被類所有實例所共享的,它不計入sizeof計算的空間
(3)類中的普通函數或靜態普通函數都存儲在棧中,不計入sizeof計算的空間
(4)類成員采用字節對齊的方式分配空間
答案:12(32位系統)或16(64位系統)
10、C++中可以重載的運算符:new/delete、new[]/delete[]、++等。
不可以重載的運算符:、.、::、?:、sizeof、typeid、.、**、不能改變運算符的優先級。
11、重載++和–時是怎么區分前綴++和后綴++的?
當編譯器看到++a(先自增)時,它就調用operator++(a)/operator++();
但當編譯器看到a++時,它就調用operator++(a, int) /operator++(int)
[有類型無變量是啞元]。即編譯器通過調用不同的函數區別這兩種形式。
12、在C++中,如果確定了某一個構造函數的創建過程,在該構造函數中如果調用了其它重載的構造函數,它將不會執行其它構造函數的初始化列表部分代碼,而是執行函數體代碼,此時已經退化成普通函數了。例子說明如下:
class CBook {
public:
double m_price;
CBook() {
CBook(8.8);
}
CBook(double price) : m_price(price) { }
};
int main() {
CBook c;
cout << c.m_price << endl; // 此時並不會輸出理想中的8.8
}
13、C的結構體和C++結構體的區別
(1)C的結構體內不允許有函數存在,C++允許有內部成員函數,且允許該函數是虛函數。所以C的結構體是沒有構造函數、析構函數、和this指針的。
(2)C的結構體對內部成員變量的訪問權限只能是public,而C++允許public,protected,private三種。
(3)C語言的結構體是不可以繼承的,C++的結構體是可以從其他的結構體或者類繼承過來的。
以上都是表面的區別,實際區別就是面向過程和面向對象編程思路的區別:
C的結構體只是把數據變量給包裹起來了,並不涉及算法。
而C++是把數據變量及對這些數據變量的相關算法給封裝起來,並且給對這些數據和類不同的訪問權限。
C語言中是沒有類的概念的,但是C語言可以通過結構體內創建函數指針實現面向對象思想。
14、可作為函數重載判斷依據的有:參數個數、參數類型、const修飾符;
不可以作為重載判斷依據的有:返回類型。
15、如何將一個小數分解成整數部分和小數部分?
要記得利用頭文件中的庫函數modf,下面是函數原型(記住一些實用的庫函數,避免自己重寫):
fractpart= double modf(double num, double*Intpart); // 將num分解為整數部分intpart和小數部分fractpart(返回值決定)
16、易誤解:
如果int a[5], 那么a與&a是等價的,因為兩者地址相同。
解答:一定要注意a與&a是不一樣的,雖然兩者地址相同,但意義類型不一樣,
&a是整個數組對象的首地址,int(*p)[5];因此&a+1相當於a的地址值加上sizeof(int) * 5,也就是a[5],下一個對象的地址,已經越界了;
而a是數組首地址,也就是a[0]的地址,&a[0];a[0]的類型是int,而a+1相當於a的地址加上sizeof(int),即a[1]的地址。
17、注意sizeof不是函數而是運算符,所以在計算變量所占用空間大小時,括號是可以省略的,但在計算類型大小時括號則不能省略:
比如int i = 0; 則
sizeof int; //ERROR
sizeof i=4; //OK
18、快速排序為什么比堆排序效率高?
(1)比較的次數,堆排序比較的次數比快排多;有很多都是無謂的比較,快排每調整一次每個元素都是朝正確的位置進一步,但是堆排序不是,最后一個元素調整到第一個,下次可能又跳回到最后一個;隨機性太大;
(2)cache局部性原理。堆排序都是不相鄰的,數據極不友好,快排都是相鄰的,移動的快,充分利用率cache。
缺點:快排是遞歸調用,消耗的空間較大。
19、數據庫中nchar()和char()、varchar()和nvarchar()的區分?
char[10]
是定長的,也就是當你輸入的字符小於你指定的數目8時,它會再后面補空值-'\0'。當你輸入的字符大於指定的數時,它會截取超出的字符。
varchar[10]
長度為 n 個字節的可變長度且非 Unicode 的字符數據。n 必須是一個介於 1 和 8,000 之間的數值。存儲大小為輸入數據的字節的實際長度,而不是 n 個字節。所輸入的數據字符長度可以為零。
例如輸入“hello”,那么氣長度不是10,而是5+1=6,
為什么“+1”呢?這一個字節用於保存實際使用了多大的長度。
nvarchar[10]
包含 n 個字符的可變長度 Unicode 字符數據。n 的值必須介於 1 與 4,000 之間。字節的存儲大小是所輸入字符個數的兩倍。所輸入的數據字符長度可以為零。Unicode字符集就是為了解決字符集這種不兼容的問題而產生的,它所有的字符都用兩個字節表示,即英文字符也是用兩個字節表示。
例如兩字段分別有字段值:我和coffee
那么varchar字段占2×2+6=10個字節的存儲空間,而nvarchar字段占8×2=16個字節的存儲空間。
從空間上考慮,用varchar合適;從效率上考慮,用char合適,關鍵是根據實際情況找到權衡點。
這三種從名字上看比前面三種多了個“N”。它表示存儲的是Unicode數據類型的字符。我們知道字符中,英文字符只需要一個字節存儲就足夠了,但漢字眾多,需要兩個字節存儲,英文與漢字同時存在時容易造成混亂,Unicode字符集就是為了解決字符集這種不兼容的問題而產生的,它所有的字符都用兩個字節表示,即英文字符也是用兩個字節表示。nchar、nvarchar的長度是在1到4000之間。和char、varchar比較起來,nchar、nvarchar則最多存儲4000個字符,不論是英文還是漢字;而char、varchar最多能存儲8000個英文,4000個漢字。可以看出使用nchar、nvarchar數據類型時不用擔心輸入的字符是英文還是漢字,較為方便,但在存儲英文時數量上有些損失。
所以一般來說,選擇標准:如字段值只是英文可選擇varchar,而字段值存在較多的雙字節(中文、韓文等)字符時用nvarchar
優缺點:
char:可以看出,是利用空間換時間,處理比較方便,英文一個字節存儲。
【存儲很短的信息;固定長度的,比如人名,這些步長而且長度大體相當;十分頻繁改變的column。】
varchar:空間效率高,節約內存;但是時間效率有所下降,容易出現內存碎片,尤其當更新時的數據比元數據量大時,比較繁瑣。另外,varchar申請的時候不能過於康概,要按需索取。對於相同的字符串,其存儲空間雖然相同,但是對於內存的消耗是不同的。
20、如何解決在構造函數里統計對象計數不准確的問題?
原因:可能因為拷貝構造函數而產生的對象,這樣就不會調用構造函數。解決辦法,提供一個顯示的賦值構造函數處理計數問題。
student::student(const student &st)
{
num++;
}
21、快排中中值的選取:
(1)固定元素法:取第一個或者最后一個作為partition的pivot。
(2)隨機元素法:隨機生成作為partition的pivot。
(3)三數取中或者無數取中法;