C++基础汇总(一)
C/C++的內容又多又雜,常常看到有人羅列相關書單,覺得毫無意義,我不相信他們真的完全掌握了其中任何一本。學習任何東西,首先要掌握基本概念,基礎不牢地動山搖,因為高級的內容都是通過低級的概念來描述的。當基本概念都沒理解透,學習再多都是空中樓閣。這里羅列了一些聽基本的問題,雖然看著不難,但是精確理解每句話中的每個詞真的并不容易。
變量聲明和定義區別?
-
聲明僅僅是把變量的聲明的位置及類型提供給編譯器,并不分配內存空間;定義要在定義的地方為其分配存儲空間。
-
相同變量可以再多處聲明(外部變量extern),但只能在一處定義。
"零值比較"?
-
bool類型:if(flag)
-
int類型:if(flag == 0)
-
指針類型:if(flag == null)
-
float類型:if((flag >= -0.000001) && (flag <= 0. 000001))
strlen和sizeof區別?(編譯期&&運行期)
-
sizeof是運算符,并不是函數,結果在編譯時得到而非運行中獲得;strlen是字符處理的庫函數。
-
sizeof參數可以是任何數據的類型或者數據(sizeof參數不退化);strlen的參數只能是字符指針且結尾是'\0'的字符串。
-
因為sizeof值在編譯時確定,所以不能用來得到動態分配(運行時分配)存儲空間的大小。
同一不同對象可以互相賦值嗎?(深淺拷貝)
-
可以,但含有指針成員時需要注意。
-
對比類的對象賦值時深拷貝和淺拷貝。
結構體內存對齊問題?
-
結構體內成員按照聲明順序存儲,第一個成員地址和整個結構體地址相同。
-
未特殊說明時,按結構體中size最大的成員對齊(若有double成員),按8字節對齊。
static作用是什么?在C和C++中有何區別?
-
static可以修飾局部變量(靜態局部變量)、全局變量(靜態全局變量)和函數,被修飾的變量存儲位置在靜態區。對于靜態局部變量,相對于一般局部變量其生命周期長,直到程序運行結束而非函數調用結束,且只在第一次被調用時定義;對于靜態全局變量,相對于全局變量其可見范圍被縮小,只能在本文件中可見;修飾函數時作用和修飾全局變量相同,都是為了限定訪問域。
-
C++的static除了上述兩種用途,還可以修飾類成員(靜態成員變量和靜態成員函數),靜態成員變量和靜態成員函數不屬于任何一個對象,是所有類實例所共有。
-
static的數據記憶性可以滿足函數在不同調用期的通信,也可以滿足同一個類的多個實例間的通信。
-
未初始化時,static int變量默認值為0。
結構體和類的區別?
- 結構體的默認限定符是public;類是private。
? ? ? ? ? ??? ? ? C++中結構體也可以繼承。
malloc和new的區別?
-
malloc和free是標準庫函數,支持覆蓋;new和delete是運算符,并且支持重載。
-
malloc僅僅分配內存空間,free僅僅回收空間,不具備調用構造函數和析構函數功能,用malloc分配空間存儲類的對象存在風險;new和delete除了分配回收功能外,還會調用構造函數和析構函數。
-
malloc和free返回的是void類型指針(必須進行類型轉換),new和delete返回的是具體類型指針。
指針和引用區別? ? ?- C++編譯器在編譯過程中使用常指針作為引用的內部實現,因此引用所占用的空間大小與指針相同;指針是具體變量,需要占用存儲空間。
-
引用在聲明時必須初始化為另一變量,一旦出現必須為typename refname &varname形式;指針聲明和定義可以分開,可以先只聲明指針變量而不初始化,等用到時再指向具體變量。
-
引用一旦初始化之后就不可以再改變(變量可以被引用為多次,但引用只能作為一個變量引用);指針變量可以重新指向別的變量。(常量指針)
-
不存在指向空值的引用,必須有具體實體;但是存在指向空值的指針。
宏定義和函數有何區別?
-
宏在編譯時完成替換,之后被替換的文本參與編譯,相當于直接插入了代碼,運行時不存在函數調用,執行起來更快;函數調用在運行時需要跳轉到具體調用函數。
-
宏函數屬于在結構中插入代碼,沒有返回值;函數調用具有返回值。
-
宏函數參數沒有類型,不進行類型檢查;函數參數具有類型,需要檢查類型。
-
宏函數不要在最后加分號。
宏定義和const區別?
-
宏替換發生在編譯階段之前,屬于文本插入替換;const作用發生于編譯過程中。
-
宏不檢查類型;const會檢查數據類型。
-
宏定義的數據沒有分配內存空間,只是插入替換掉;const定義的變量只是值不能改變,但要分配內存空間。
宏定義和typedef區別?
-
宏主要用于定義常量及書寫復雜的內容;typedef主要用于定義類型別名。
-
宏替換發生在編譯階段之前,屬于文本插入替換;typedef是編譯的一部分。
-
宏不檢查類型;typedef會檢查數據類型。
-
宏不是語句,不在在最后加分號;typedef是語句,要加分號標識結束。
-
注意對指針的操作,typedef char * p_char和#define p_char char *區別巨大。
宏定義和內聯函數(inline)區別?
-
在使用時,宏只做簡單字符串替換(編譯前)。而內聯函數可以進行參數類型檢查(編譯時),且具有返回值。
-
內聯函數本身是函數,強調函數特性,具有重載等功能。
-
內聯函數可以作為某個類的成員函數,這樣可以使用類的保護成員和私有成員。而當一個表達式涉及到類保護成員或私有成員時,宏就不能實現了。
條件編譯#ifdef, #else, #endif作用?
-
可以通過加#define,并通過#ifdef來判斷,將某些具體模塊包括進要編譯的內容。
-
用于子程序前加#define DEBUG用于程序調試。
-
應對硬件的設置(機器類型等)。
-
條件編譯功能if也可實現,但條件編譯可以減少被編譯語句,從而減少目標程序大小。
區別以下幾種變量?
const int a; int const a; const int *a; int *const a;-
int const a和const int a均表示定義常量類型a。
-
const int *a,其中a為指向int型變量的指針,const在 * 左側,表示a指向不可變常量。(看成const (*a),對引用加const)
-
int *const a,依舊是指針類型,表示a為指向整型數據的常指針。(看成cons
-
t(a),對指針const)
?關鍵問題點:const?屬于修飾符?,關鍵是看const?修飾的位置在那里
1、const?int?*a
這里const?修飾的是int,而int定義的是一個整值
因此*a?所指向的對象?值?不能通過?*a?來修改,但是?可以重新給?a?來賦值,使其指向不同的對象
eg:
??????? const?int?*a?=?0;
??????? const?int?b?=?1;
??????? int?c?=?1;
? ? ? ?a?=?&b??//? 額外:注意不能通過a?來修改?b值
? ? ? ?a?=?&c??//? ?額外:雖然c本身不是一個常量
? ? ? ? *a?=?2??//error 為題就在這里,不能修改通過?*a?所指向的對象值,最后賦值得對象是c,因此不能通過*a?來修改c值。
2、int??*const?a???????
這里const修飾的是?a?,a代表的是一個指針地址
因此不能賦給a其他的地址值,但可以修改a指向的值
這有點和cont?int?*a相反的意味,例子就不說了
?
3、至于int?const?*a?和?const?int?*a?的意義是相同的?他們兩個的作用等價
補充:
4、const?int?*?const?a?
這個代表a所指向的對象的值以及它的地址本身都不能被改變
5、?const?int?*const?a
a所指向的對象及對象的值均不可改變。
關于const的點滴補充:
1、const?對象的地址只能賦值給指向const?對象的指針
2、指向const?對象的指針可以?被賦?以?一個非const?對象的地址?
3、指向const?得指針常被用作函數的形式參數,保證被傳遞給函數的實際對象在函數得實際對象在函數中不會被修改
4、常量在定義后就不能被修改,所以它必須被初始化。未初始化的常量定義將導致編譯錯誤(上面都是在說明const得問題,所以沒有賦值,實際語句中要賦值的)
volatile有什么作用?
-
volatile定義變量的值是易變的,每次用到這個變量的值的時候都要去重新讀取這個變量的值,而不是讀寄存器內的備份。
-
多線程中被幾個任務共享的變量需要定義為volatile類型。
什么是常引用?
-
常引用可以理解為常量指針,形式為const typename & refname = varname。
-
常引用下,原變量值不會被別名所修改。(不能通過引用修改原值)
-
原變量的值可以通過原名修改。
-
常引用通常用作只讀變量別名或是形參傳遞。
? ? ? ? ? ?
區別以下指針類型?
int *p[10] int (*p)[10] int *p(int) int (*p)(int)-
int *p[10]表示指針數組,強調數組概念,是一個數組變量,數組大小為10,數組內每個元素都是指向int類型的指針變量。
-
int (*p)[10]表示數組指針,強調是指針,只有一個變量,是指針類型,不過指向的是一個int類型的數組,這個數組大小是10。
-
int *p(int)是函數聲明,函數名是p,參數是int類型的,返回值是int *類型的。
-
int (*p)(int)是函數指針,強調是指針,該指針指向的函數具有int類型參數,并且返回值是int類型的。
常量指針和指針常量區別?
-
常量指針是一個指針,讀成常量的指針,指向一個只讀變量。如int const *p或const int *p。
-
指針常量是一個不能給改變指向的指針。如int *const p。
a和&a有什么區別?
假設數組int a[10]; int (*p)[10] = &a;-
a是數組名,是數組首元素地址,+1表示地址值加上一個int類型的大小,如果a的值是0x00000001,加1操作后變為0x00000005。*(a + 1) = a[1]。(數組指針也是迭代器,可以進行加減運算)
-
若(int *)p ,此時輸出 *p時,其值為a[0]的值,因為被轉為int *類型,解引用時按照int類型大小來讀取。
- int arr[5] = {1,2,3,4,5};int* p = &arr[2];int j = p[1]; //j==arr[3] 即相當于 *(p+1)int k = p[-2]; //k==arr[0] 即相當于 *(p-2)
?
數組名和指針(這里為指向數組首元素的指針)區別?
-
二者均可通過增減偏移量來訪問數組中的元素。
-
數組名不是真正意義上的指針,可以理解為常指針,所以數組名沒有自增、自減等操作。
-
當數組名當做形參傳遞給調用函數后,就失去了原有特性,退化成一般指針,多了自增、自減操作,但sizeof運算符不能再得到原數組的大小了。
野指針是什么?
-
也叫空懸指針,不是指向null的指針,是指向垃圾內存的指針,指向未定義的內存空間。
-
產生原因及解決辦法:
-
指針變量未及時初始化 => 定義指針變量及時初始化,要么置空。
-
指針free或delete之后沒有及時置空 => 釋放操作后立即置空。
-
堆和棧的區別?
-
申請方式不同。
-
棧由系統自動分配。
-
堆由程序員手動分配。
-
-
申請大小限制不同。
-
棧頂和棧底是之前預設好的,大小固定,可以通過ulimit -a查看,由ulimit -s修改。
-
堆向高地址擴展,是不連續的內存區域,大小可以靈活調整。
-
-
申請效率不同。
-
棧由系統分配,速度快,不會有碎片。
-
堆由程序員分配,速度慢,且會有碎片。
-
delete和delete[]區別?
-
delete只會調用一次析構函數。
-
delete[]會調用數組中每個元素的析構函數。
總結
以上是生活随笔為你收集整理的C++基础汇总(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JSP页面中四种“返回按钮”的使用
- 下一篇: C++面向对象基础(二)