C++學習筆記

C語言__指針
==============================================
有一個變量專門用來存放另一變量的地址,則它稱爲“指針變量”。指針變量的值是地址。(指針是一個地址,而指針變量是存放地址的變量)

定義指針變量時要注意兩點:
1)指針變量前面的“*”表示該變量的類型爲指針型變量。指針變量名是pointer_1、pointer_2,而不是*pointer_1、*pointer_2;
2)在定義指針變量時必須指定基類型。(一個指針變只能只能指向同一個類型的變量,不能忽而指向一個整型變量,忽而指向一個實型變量)
請牢記:指針變量中只能存放地址(指針),不要將一個整數(或任何其他非地址類型的數據)賦給一個指針變量。
1)&:取地址運算符;
2)*:指針運算符(或稱“間接訪問”運算符),取其指向的內容
*p表示取其指針變量p所指向的存儲單元的內容

由於“單向傳送”的“值傳遞”方式,形參值的改變不能使實參的值隨之改變。爲了使在函數中改變了的變量值能被main函數所用,不能採取上述把

改變值的變量作爲參數的辦法,而應該用指針變量作爲函數參數,在函數執行過程中使指針變量所指向的變量值發生變化,函數調用結束後,這些變

量的變化依然保留下來,這樣就實現了“通過調用函數使變量的值發生變公,在主調函數(如main函數)中可以使用這些改變了的值”的目的。
(不可能通過調用函數來改變實參指針變量的值,但可以改變實參指針變量所指變量的值)

C語言規定數組名(不包括形參數組名,形參數組並不佔據實際的內存單元)代表數組中首元素(即序號爲0的元素)的地址。

在編譯時,對數組元素a[i]就是按*(a+i)處理的,即按數組首元素的地址加上相對位移量得到要找的元素的地址,然後找出該單元中的內容。


變量和數據類型
=================================
1、在編程時,常量和變量必須遵循“先聲明,後使用”的原則,即所有常量和變量必須在使用前用說明語句進行說明,否則編譯時將會產生錯誤。
2、預定義符號即定義宏常量(#define pi 3.141592654)在編譯時使用常數替代了所有的預定義符號,這樣在代碼中的相應位置實際都是常數。程序

中過多的常數會導致程序代碼量變大,而且在多個源文件中定義了同樣的符號,會產生符號重定義的問題。
3、變量的存儲類型:
1)auto:屬於一次性存儲,其存儲空間可被若干變量多次覆蓋使用
2)register:存儲在通寄存器中
3)extern:在所有函數和程序段中都可引用
4)static:在內存中是以固定地址存放的,在整個程序運行期間都有效
默認情況下,變量的存儲類值爲auto        C++語言是大小寫敏感的語言。
    一般來說,操作系統和C++標準庫裏的標識符以下劃線開頭,這是約定俗成的。用戶應該避免使用下劃線作爲自己定義的標識符的開頭。此外,

不能用關鍵字和保留標識符來給自定義的變量命名。
全局變量:其說明語句不在任何一個類定義、函數定義或複合語句(程序塊)中的變量。全局變量所佔用的空間在內存的數據區,在程序運行的整個過

程中位置保持不變。
局部變量:其說明語句在某一個類定義、函數定義或複合語句(程序塊)中的變量。局部變量所佔用的空間在爲程序運行時所設置的臨時工作區中,以

堆棧的形式允許反覆佔用和釋放。
4、類型轉換是用來把一個類型的值轉換成另一個類型。C++是強類型的語言,即其每一個值都有它相應的類型。當用戶需要把一個值轉換爲另一個類

型時,就需要使用一些方式進行類型轉換。C++中,支持隱式轉換和顯式轉換兩種。隱式轉換意味着編譯器認爲轉換是合理的或者是安全的。而顯式

轉換意味着編譯器能夠找到一個轉換方式,但是它不保證這個轉換是否安全,而是需要程序員額外指出。


運算符和表達式
===================================
1、C++中包含了C語言中的運算符和表達式,並且又增加了一些新的運算符,有:
1)::    作用域運算符
2)new    動態分配內存單元運算符
3)delete 刪除動態分配的內存單元運算符
4)*和->* 成員指針選擇運算符
運算符的優先級:單目運算符>*或/>%>+或-
2、位運算,左移運算(<<)指左移後,低位補0,高位捨棄;右移運算(>>)指右移後,低位捨棄,高位無符號數補0,有符號數補符號位。
1001>>2        0010
1001<<1        0010
~1001        0110
3、邏輯表達式,C++規定:只對能夠確定整個表達式值所需要的最少數目的子表達式進行計算。也就是說,當計算出一個子表達式的之後便可確定整

個邏輯表達式的值時,後面的子表達式就不需要再計算了,整個表達式的值就是該子表達式的值,這種表達式也稱爲短路表達式。(短路表達式只需

要計算許多子表達式中的若干個,這樣可以大大減小計算機的運算量)


程序控制結構
=======================================
1、C++定義了運算符"<<"和">>"的iostream類。在I/O流類的定義中,把C++語言中的左、右移位運算符<<和>>通過運算符重載的方法定義爲插入(輸

出)和提取(輸入)運算符。
2、continue語句與break語句的主要區別是,continue語句是根據條件判斷只結束本次循環,不結束整個循環結構;而break語句不進行判斷,結束

整個循環結構,然後執行循環體後面的語句。return語句又稱返回語句,可用來停止執行當前函數,轉而執行調用該函數後面的語句(需要注意的是

,所返回表達式的類型必須與函數的類型一致)。


函數
==============================================
1、C++不允許函數的定義嵌套,即在函數定義中再定義一個函數是非的。但是函數可以被一個函數調用,也可以調用另一個函數,它們之間可以存在

着調用上的嵌套關係。
2、在C++程序中調用函數之前,首先要對函數進行定義。如果調用此函數在前,函數定義在後,就會產生編譯錯誤。爲了使函數的調用不受函數定義

位置的影響,可以在調用函數前進行函數的定義。這樣,不管函數是在哪裏定義的,只要在調用前進行了函數的定義,就可以保證函數調用的合法性


3、函數原型也稱函數聲明或函數模型。在主調函數中,如果要調用另一個函數,則須在本函數或本文件中的開頭將要被調用的函數事先作一聲明。

聲明函數就是告訴編譯器函數的返回類型、名稱和形參表構成,以便編譯系統對函數的調用進行檢查。(注意:函數聲明不能省略參數的類型,也不

能省略函數的返回值類型或改變參數順序)
4、C++有兩種不同的函數:庫函數和自定義函數。庫函數是C++系統提供的標準函數,用戶一般不必自己定義,需要時直接調用即可。在調用庫函數

時,一般在文件的開頭通過#include宏命令引用庫函數對應的原型聲明文件,自定義函數則是根據程序的需要由用戶自行定義。(注意:在實際程序

中,#include命令後一般使用<>符號來調用庫函數,使用""符號來調用自定義函數)
5、傳值調用就是指當一個函數被調用時,C++根據實參和形參的對應關係將實參的值一一複製給形參,即實參的值單向傳遞給形參。函數本身不對實

參進行任何操作,即使形參的值在函數中改變,實參的值也不會受到影響。
6、引用傳遞方式是在函數定義時在形參前面加上引用運算符"&"。在函數調用時,參數傳遞的內容不是實參的值,而是實參的地址,即將實參的地址

放到C++爲形參分配的內存空間中,因此形參的任何操作都會改變相應的實參的值。
7、遞歸調用:一個函數直接或間接地調用自身,這種現象就是函數的遞歸調用。遞歸調用有兩種方式:直接遞歸調用和間接遞歸調用。
8、帶默認形參值的函數:在C++語言中調用函數時,通常要爲函數的每個形參給定對應的實參。若沒有給出實參,則按指定的默認值進行工作。當一

個函數既有定義又有聲明時,形參的默認值必須在聲明中指定,而不能在定義中指定。只有當函數沒有聲明時,纔可以在函數定義中指定形參的默認

值。此外,默認值的定義必須遵守從右到左的順序,如果某個形參沒有默認值,則它左邊的參數就不能有默認值。在進行函數調用時,實參與形參按

從左到右的順序進行匹配,當實參的數目少於形參時,如果對應位置形參又沒有設定默認值,就會產生編譯錯誤;如果設定了默認值,編譯器將爲那

些沒有對應實參的形參取默認值。(形參的默認值可以爲全局常量、全局變量、表達式、函數調用,但不能爲局部變量)

9、一個程序將操作系統分配給其運行的內存塊分爲4個區域:
1)代碼區:存放程序的代碼,即程序中各個函數中的代碼塊
2)全局數據區:存放程序全局數據和靜態數據
3)堆區:存放程序的動態數據
4)棧區:存放程序的局部數據,即各個函數中的數據
10、對於全局變量還有以下幾點說明:
1)外部變量可加強函數模塊之間的數據聯繫,但又使這些函數依賴這些外部變量,從而使得這些函數的獨立性降低;
2)在同一源文件中,允許外部變量和內部變量同名。在內部變量的作用域內,外部變量將被屏蔽而不起作用;
3)全局變量的作用域是從定義點到本文件結束。如果定義點之前的函數需要引用這些外部變量時,需要在函數內對被引用的外部變量進行說明。
全局變量的定義和說明是不一樣的。全局變量的定義,其必須在所有的函數之外定義,且只能定義一次。而外部變量的說明,一般出現在要使用該外

部變量的函數內,而且可以出現多次。

11、函數重載:函數重載是指同一個函數名可以對應着多個函數的實現。每一類實現對應着一個函數體,這些函數的名字相同,但是函數的參數的類

型不同,這就是函數重載。函數重載又稱爲函數的多態性,是指同一個函數名對應着多個不同的函數。所謂“不同”是指這些函數的形參表必須互不

相同,或者是形參的個數不同,或者是形參的類型不同,或者是兩者都不相同,否則將無法實現函數重載。重載函數的類型,即函數的返回類型,可

以相同,也可以不同。但如果僅僅是返回類型不同而函數名相同、形參表也相同,則是不合法的,編譯器會給出語法錯誤。


編譯預處理
=======================================
1、預處理就是對源文件進行編譯前,先對預處理部分進行處理,然後對處理後的代碼進行編譯(預處理是在編譯之前的處理,而編譯工作的任務之

一就是語法檢查,預處理不作語法檢查)。這樣經過處理後的代碼,將會變得很精短。預處理的命令可以劃分爲文件包含、條件編譯、佈局控制和宏

替換4個大類:
1)文件包含(#include)是一種最爲最見的預處理,主要是作爲文件的引用組合源程序正文;
2)條件編譯(#if,#ifndef,#ifdef,#endif,#undef等)也是比較常見的預處理,主要是進行編譯時進行有選擇的挑選,註釋掉一些指定的代碼,以達

到版本控制、防止對文件重複包含的功能;
3)佈局控制(#progma)也是應用預處理的一個重要方面,主要功能是爲編譯程序提供非常規的控制流信息;
4)宏替換(#define)是最常見的用法,其可以定義符號常量、函數功能、重新命名、字符串的拼接等各種功能。
2、在帶參宏定義中,形式參數不分配內存單元,因此不必作類型定義。而宏調用中的實參有具體的值。要用它們去代換形參,因此必須作類型說明

,這是與函數中的情況不同的。在函數中,形參和實參是兩個不同的量,各有自己的作用域,調用時要把實參值賦予形參,進行值傳遞。而在帶參宏

中,只是符號代換,不存在值傳遞的問題。
3、內聯函數,也稱爲內嵌函數,當在一個函數的定義或聲明前加上關鍵字inline則就把該函數定義爲內聯函數,它主要用於解決程序的運行效率。

若把一個函數定義爲內聯函數後,在程序編譯階段,編譯器就會在每次調用該函數的地方都直接替換爲該函數體中的代碼,由此省去函數的調用、相

應地保存現場、參數傳遞和返回操作等所需的時間,從而加快整個程序的執行速度。
4、文件包含命令,其意義是把尖括號< >或""內指定的文件包含到本程序來,成爲本程序的一部分。使用尖括號表示在包含文件目錄中去查找(包含

目錄是由用戶在設置環境時設置的),而不在源文件目錄去查找;使用雙引號則表示首先在當前的源文件目錄中查找,若未找到纔到包含目錄中去查

找。在使用#include文件包含命令時要注意如下兩個事項:
1)一個include命令只能指定一下被包含文件,若有多個文件要包含,則需用多個include命令;
2)文件包含允許嵌套,即在一個被包含的文件中又可以包含另一個文件。
一般來說,在軟件開發中將符號常量、全局變量、函數聲明包含在頭文件(.h文件)中,並將其定義放在.cpp文件中。然後在使用的時候,包含對應的

頭文件即可。
5、C++中,預處理程序中的#error指令用於程序的調試,在編譯中遇到#error指令就停止編譯


數組
============================================
1、二維數組在內存中的排列順序是“先行後列”,即在內存中先存第一行的元素,然後再存第二行的元素。(在定義數組時,不能用變量來描述數組

定義中的元素個數)
2、在對數組初始化時,也可以只對數組中的部分元素指定初始值。初始化值的個數可以少於或等於數組定義的元素的個數,但不可以多於數組元素

的個數,否則會引起編譯錯誤。當初始化值的個數少於數組元素個數時,前面的元素按順序初始化相應的值,後面不足的部分由系統自動初始化爲零

(對數值數組)或空字符'\0'(對字符數組)。
3、strcpy()函數用於拷貝字符串,其主要功能是將源字符串拷貝到目標字符串,調用的形式strcpy(char destination[],const char source[]);目

標字符呂必須定義得足夠大,以便容納複製過來的字符串。
4、strcat()函數用於連接字符串,主要功能是將字符串source接到字符串target的後面,調用形式是strcat(char target[],const char source

[]);
5、字符數組與字符串是不一樣的。兩者最顯著的區別在於,字符串的長棄是其中字符的數目再加1,因爲其包含了結束符'\0',而字符數組的長度就

是其中字符的數目。


指針
===========================================
1、把指針指向的變量的數據類型稱爲指針的數據類型;而任何一個指針變量本身數據值的類型都是unsigned long int。指針變量的類型確定後只能

指向這種既定的數據類型,不可指向其它類型的數據。
2、&運算符:爲取地址運算符,&x的值爲x的地址
*運算符:指針運算符,或指向運算符,也稱間接運算符,*p代表p所指向的變量(利用指針來訪問變量需要使用間接訪問運算符*)
px:指針變量,它的內容是地址量
*px:指針的目標變量,它的內容是數據
&px:指針變量佔用的存儲區域的地址
3、指針運算是以指針變量所持有的地址值爲運算量進行的運算。因此,指針運算的實質是地址的計算。指針運算的種類是有限的,它只能進行算術

運算、關係運算和賦值運算。
4、指針的算術運算:
指針與整數的加減運算(px+n,px-n):指針作爲地址量加上或減去一個整數n,其意義是指針當前指向位置的前方或後方第n個數據的位置。由於指針

可以指向不同數據類型,即數據長度不同的數據,所以這種運算的結果取決於指針指向的數據類型。
p+n的實際操作是:(p)+n*sizeof(數據類型)
p-n的實際操作是:(p)-n*sizeof(數據類型)
其中,(p)表示指針p中的地址值,而不是&p,sizeof(數據類型)的長度單位爲字節
5、指針的關係運算:與指針的處術運算類似,在兩個指向相同類型變量的指針之間可以進行各種關係運算。指向不同數據類型的指針之間的關係運

算是沒有意義的,指針與非0整數之間的關係運算也是沒有意義的。但是指針可以和0之間進行等於或不等於的關係運算。(根據指針與0的比較,可

以用於判斷指針p是否爲空指針)
6、在C++語言中,可以聲明指向void類型的指針,指向void類型的指針稱爲void指針。此外,在聲明指針時,還可以用關鍵字const進行修飾,用關

鍵字const修飾的指針稱爲const指針。
1)void指針不指向一個確定的類型數據,它的作用僅僅是用來存放一個地址。void指針它可以指向任何類型的C++數據。也就是說,可以用任何類型

的指針直接給void指針賦值。但是,如果需要將void指針的值賦給其他類型的指針,則需要進行強制類型轉換。
2)如果在指針定義前加上關鍵字const,就包含一些特殊含義,而關鍵字const放在不同的位置表示的意義也不相同,主要如下:
a.關鍵字const放在指針類型前,就是聲明一個指向常量的指針。此時,在程序中不能通過指針來改變它所指向的值,但是指針本身的值可以改變,

即指針可以指向其他數據。
b.關鍵字const放在“*”和指針名之間,就是聲明一個指針常量(也稱常指針)。因此,指針本身的值不可改變,也即它不能再指向其他數據,但它所

指向的數據的值可以改變。
c.在指針類型前和“*”和指針名之間都加關鍵字const,則是聲明一個指向常量的指針常量,指針本身的值不可改變,它所指向的數據的值也不能通

過指針改變。
7、在C++語言中,數組指針就是一個指向數組的指針,而指針數組就是其元素爲指針的數組。
8、如果函數的某個參數是指針,對這個函數的調用就是傳址調用,也就是使實參指針和形參指針變量指向同一內存地址。在被調用函數的運行過程

中,對形參指針所指向的地址中內容的改變也會影響實參。(當以數據的地址作爲實參調用一個函數時,被調用函數的形參也必須是可接收地址的變

量,並且數據類型必須與被傳送的數據類型相同。由於數組名是一個指針,因此,數組名也可以用做函數的參數,也屬於傳址調用)
9、指針型函數,除了void類型的函數之外,函數在調用結束後都會有返回值,指針同樣也可以作爲函數的返回值。當一個函數的返回值是指針類型

時,這個函數就是指針型函數。通常非指針型函數調用結束後,可以返回一個變量,但是每次調用只能返回一個數據。但有時需要從被調函數返回一

批數據到主調函數中,這時可以通過指針型函數來解決。
10、函數指針則是指向函數的指針。在定義了指向函數的指針變量後,在使用函數指針之前,必須先給它賦值,使它指向一個函數的入口地址。由於

函數名是函數在內存中的首地址,因此可以將函數名賦給函數指針變量。即:函數指針名=函數名;
11、C++中可以定義一個字符數組,實現字符串的存儲,並通過數組下標來訪問指定字符。事實上,C++還提供了另外一個存儲訪問字符串的方法,即

字符指針,定義一個字符指針,便可以通過指針的指向來訪問指定字符:
1)strcat():字符串連接函數,其原型爲char *strcat(char *s1,char *s2),將字符串s2連接到字符串s1的後面,並返回s1的地址值;
2)strcmp():字符串比較函數,其原型爲int strcmp(const char *s1,const char *s2,[int n]),比較字符串s1和s2的大小(如果有參數n,比較前

n個字符的大小)。當字符串s1大於、等於或小於字符串s2時,函數返回值分別是正數、零和負數;
3)strcpy():字符串複製函數,其原型爲char *strcpy(char *s1,const char *s2),將s2所指向的字符串複製到s1所指向的字符數組中,然後返回

s1的地址值;
4)strlen():字符串長度計算函數,原型爲int strlen(const char *s),該函數返回字符串s的長度。


構造數據類型
==============================================
1、構造數據類型是根據已定義的一個或多個數據類型用構造的方法來定義的。也就是說,一個構造類型的值可以分解成若干個“成員”或“元素”

。每個“成員”都是一個基本數據類型或是一個構造類型。在C++中,構造類型有:數組類型、結構體類型、共用體類型、枚舉類型和用戶自定義數

據類型。
2、結構體就是一個可以包含不同數據類型的結構,其是一種可以自己定義的數據類型,它的特點和數組主要有兩點不同:
1)結構體可以在一個結構中聲明不同的數據類型;
2)相同結構的結構體變量是可以相互賦值的,而數組是做不到的。
3、定義結構體類型變量:在完成一個結構體定義之後,就可以像定義基本數據類型變量一樣定義結構體類型的變量和數組了。一般來說,結構體類

型變量的定義可以通過四種方式完成:
1)先定義結構體類型再單獨進行變量定義;
2)緊跟在結構體類型說明之後進行定義;
3)在說明一個無名結構體類型的同時直接進行定義;
4)使用typedef說明一個結構體類型名後再用新類型名來定義變量。
4、初始化結構體變量:對結構體變量進行賦初值時,C++編譯程序按每個成員在結構體中的順序一一對應賦初值,不允許跳過前面的成員給後面的成

員賦初值。但是,C++允許只給前面的若干個成員賦初值,對於後面未賦值的成員,系統自動賦默認的初值。
5、引用結構體成員變量:一般來說,如果已定義了一個結構體變量和一個指向該結構體的指針變量,則可用以下三種形式來引用結構體變量中的成

員:
1)結構體變量名.成員名;
2)指針變量名->成員名;
3)(*指針變量名).成員名;
6、結構體作爲函數參數:一般來說,結構體作爲函數參數使用的是引用傳遞。這是因爲利用引用傳遞的好處很多,其效率和指針相差無幾,但引用

的操作方式和值傳遞幾乎一樣。種種優勢都說明善用引用可以使程序易讀和易操作,它的優勢是當結構很大的時候,避免傳遞結構變量很大的值,節

省內存,提高效率。
7、共用體類型說明:共用體類型的說明與結構體類型說明方式完全相同。不同的是,結構體變量中的成員各自佔有自己的存儲空間,而共用體變量

中的所有成員佔有同一個存儲空間,因此賦初值時只能賦一個值,通常編譯系統中認爲是第一個成員變量的值。
8、枚舉類型:如果在給定枚舉常量的時候不指定其對應的整數常量值,系統將自動爲每一個枚舉常量設定對應的整數常量值。當採用默認值時,枚

舉常量的對應值從0開始,而部分常量已經賦值了,則其餘枚舉常量的對應值爲前一枚舉常量對應的整數常量的值加1。(枚舉變量的使用和整數常量

的使用一樣,其每個枚舉常量對應了一個整數常量,並且可以進行各種整數常量的運算。)
9、類型重定義typedef:爲了解決用戶自定義數據類型名稱的需求,C++中引入類型重定義語句typedef,可以爲數據類型定義新的類型名稱,從而豐

富數據類型所包含的屬性信息。(typedef只是爲已知數據類型增加一個新的名稱)
1)爲基本數據類型定義新的類型名;
2)爲自定義數據類型(結構體、共用體和枚舉類型)定義簡潔的類型名稱;
3)爲數組定義簡潔的類型名稱;
4)爲指針定義簡潔的名稱。
10、位域:在實際的程序設計中,有時需要存儲少量的信息,這些信息並不需要佔用一個完整的字節,而只需佔幾個或一個二進制位。如果給其分配一個字節的空間,便浪費了存儲空間。因此,C++中引入了位域這一數據類型。所謂位域就是把一個字節中的二進制位劃分爲幾個不同的區域,並說明每個區域的位數,每個域有一個域名,允許在程序中按域名進行操作。這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。
1)一個位域必須存儲在同一個字節中,不能跨兩個字節。若一個字節所剩空間不夠存放另一個位域時,應從下一個字節起存放該位域;
2)由於位域不允許跨兩個字節,因此位域的長度不能大於1個字節的長度,也就是說,不能超過8位二進制位;
3)位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。
小結:C++中,結構體、共用體和枚舉類型是使用較多的構造數據類型。在定義結構體變量時,每一個成員都要分配空間存放各自的數據。共用體是另一種構造數據類型,但在定義共用體變量時,只按佔用空間最大的成員來分配空間,在同一時刻只能存放一個數據成員的值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章