1. 程式人生 > >總結之《征服C指標》

總結之《征服C指標》

對於接觸過c語言,而沒有理解指標以及記憶體佈局的人來說,《征服C指標》是不錯的選擇。

這本書中的補充內容也值得閱讀,通過和java,c++等一些語言比較,來體會c語言的魅力。

第一章  從基礎開始

幾乎所有的處理程式中,所謂的“指標型別的值”,實際是指記憶體的地址。

p28 的補充值得看,主要講了NULL, 0,'\0'的區別,不要使用NULL來結束字串,一般都用'\0'

p49 補充,c語言是不做陣列下標越界檢查的 

要點: 1.變數不一定按照宣告的順序儲存在記憶體中。

       2.對變數使用&運算子,可以取得該變數的地址。這個地址成為指向該變數的指標。

       3.指標變數hoge_p儲存了指向其他變數的地址的情況下,可以說“hoge_p指向hoge”。

       4.對指標變數運用*運算子,就等同於它指向的變數。如果hoge_p指向hoge, *hoge_p就等同於hoge。

       5.對指標加N,指標前進“當前指標指向的資料型別的長度*N”

       6.p[i]是*(p+i)的簡便寫法。

       7.在C中是不能將陣列作為函式引數進行傳遞的。但是,你可以通過傳遞指向初始元素的指標來達到將陣列作為引數進行傳遞的目的。

第二章  虛擬記憶體

這一章對於作業系統記憶體管理薄弱的人來說,看看有益

一個程式用兩個視窗來跑,相當於是兩個程序,兩個程序之間相互獨立互不影響,但是在列印變數的記憶體地址時卻是同一個地址。why?

原因是輸出指標的時候,列印輸出的並不是實體記憶體地址本身。

當今作業系統都會給每一個程序分配獨立的“虛擬地址空間”。這和C語言沒有關係,而是作業系統和cpu協同工作的結果。正是因為作業系統和cpu努力地為每一個程序分配獨立的地址空間,所以就算我們製造了一個bug,破壞了某個記憶體區域,頂多會使得當前程式趴窩,不影響其他程序。

當然,真正儲存記憶體資料的還是實體記憶體。作業系統負責將實體記憶體分配給虛擬地址空間,同時還會對每一個記憶體區域設定“只讀”或者“可讀寫”等屬性。

通常,因為程式的執行程式碼是隻讀的,所以有時候會和其他程序共享實體記憶體。另外,當我們啟動了幾個笨重的應用程式而使記憶體出現不足時,作業系統把實體記憶體中還沒有被引用的部分倒騰出來,儲存到硬碟上。當程式再次需要引用這個區域的資料的時候,再從磁碟寫回到記憶體。這個操作是在作業系統的後臺進行的,對於應用程式來說,壓根兒不知道背後發生的事。這是硬碟“咔嗒咔嗒”響,機器就慢了下來。

之所以能夠這樣,多虧了虛擬地址。正式因為避免了讓應用程式直接面對實體記憶體的地址,作業系統才能夠順利地對記憶體區域進行重新配置。

要點:

C中有三種記憶體領域的壽命

1.靜態變數的壽命從程式執行時開始,到程式關閉時結束。

2.自動變數的壽命到宣告該變數的語句塊執行結束為止。

3.通過malloc()分配的領域的壽命到呼叫free()為止。

將函式自身和字串常量彙總配置在一個只讀記憶體區域。執行時程式是隻讀的,在同一份程式被同時啟動多次的時候,通過在實體地址上共享程式

能夠節約實體記憶體。此外,由於硬碟上已經存放了可執行程式,就算記憶體不足,也不需要將程式交換到虛擬記憶體,相反可以將程式直接從記憶體中銷燬。

char *s = "abc";

s[0] = 'd';

這個字串常量是配置在只讀記憶體區域的,所以該寫法s[0]='d' 是不行的。

靜態變數總是在虛擬地址空間上佔有固定的區域。

各個目的碼之間通過連結器連結處理生成可執行程式  .o檔案即符號表(可重定位檔案),就是根據符號表的內容對函式,變數進行重定位連結。比如函式宣告在一個a.h檔案中,

定義在a.cpp檔案中,而呼叫在b.cpp檔案中,這時需要用連結器將函式的定義連結到b.cpp。

在宣告自動變數的函式執行結束後,自動變數就不能被使用了。所以自動變數重複使用記憶體區域,自動變數的地址是不一定的。

C語言中,在現有被分配的記憶體區域之上以“堆積”的方式,為新的函式呼叫分配記憶體區域。在函式返回的時候,會釋放這部分記憶體區域供下一次

函式呼叫。

C語言函式呼叫的實現:

1.在呼叫方,引數從後往前按順序被堆積在棧中。這就為可變長引數提供了基礎,可變長引數永遠都可以在記憶體中尋找到第一個引數。

2.和函式呼叫關聯的返回資訊也被堆積在棧中。所謂的返回地址,是指函式處理完畢後應該返回的地址。正因為返回地址被堆積在棧中,所以無論函式從什麼地方

被呼叫,它都能返回到呼叫點的下一個處理。

3.跳轉到作為被呼叫物件的函式地址。

4.棧為當前函式所使用的自動變數增長提供所需大小的記憶體區域。

5.在函式的執行過程中,為了進行復雜的表示式運算,有時候會將計算過程中的值放在棧中。

6.一旦函式呼叫結束,區域性變數佔用的記憶體區域就被釋放,並且使用返回資訊返回到原來的地址。

7.從棧中出去呼叫方的引數。

p70的補充 一旦函式執行結束,自動變數的記憶體區域就會被釋放。

assert(條件表示式)  若條件表示式的結果為真,什麼也不會發生;若為假,則會輸出相關資訊並且強制終止程式。 

利用malloc來進行動態記憶體分配

p = malloc(size);

free(p);

並且可以通過任意的順序釋放的記憶區域,稱為堆。

malloc的返回值的型別為 void*

系統呼叫brk()就是通過設定這個記憶體區域的末尾地址,來伸縮記憶體空間的函式的。

呼叫函式的時候,棧會向地址較小的一方伸長。多次呼叫malloc()時,會呼叫一次brk(),記憶體區域會向地址較大的一方伸長。

要點:

1.malloc不是系統呼叫

malloc()遍歷連結串列尋找空的塊,如果發現尺寸大小能夠滿足使用的塊,就分割出來將其變成使用中的塊,並且嚮應用程式返回緊鄰管理區域

的後面區域的地址。

free()將管理區域的標記改寫成“空塊”,順便也將上下空的塊合併成一個塊,這樣可以防止塊的碎片化。

free()之後,對應的記憶體區域是不會立刻返還給作業系統的。

calloc()使用和malloc()相同的方式分配nmemb*size大小的記憶體區域,並且將該區域清零返回。也就是和一下程式碼有同等效果

p = malloc(nmemb * size);

memset(p, 0, nmemb * size);

就算我們使用了calloc(),在釋放記憶體的時候也請使用free()。

還有一個realloc()

realloc(void *ptr, size_t size);

如果通過ptr傳遞的區域後面有足夠大小的空閒空間,就直接實施記憶體區域擴充套件。但是,如果後面的區域沒有足夠多的空閒空間,就分配其他新的

空間,然後將內容複製過去,而原來的部分會被作業系統自動回收。

另外,注意記憶體佈局的對齊,和位元組排序  大端儲存和小端儲存。

 第三章

主要著重講解了指標型別和陣列型別,以及多維陣列(其實在C中,是沒有多維陣列的,因為在記憶體中的儲存是一維的)

解讀C的宣告 const修飾符是重點 也是面試裡面的基礎

const char *str  或  char const *str

str = NULL;//  OK     只讀的是str所指的物件

*str = 'a';//  not OK

char * const str      只讀的是str自身

str = NULL;//  not OK

*str = 'a';//  OK

const char * const str

str = NULL;//  not OK

*str = 'a';//  not OK

另外注意結構體所用const的修飾符,在結構體上用const,結構體中的元素仍然可以修改,除非給結構體中的元素也加上const修飾。

要點:

    1.只有在宣告函式形參的情況下,int a[]和int *a才具有相同的意義。

    2.extern的宣告,意味著“使在某處宣告的物件能夠在當前的地方使用”,因此它不是定義   extern int a;

字串常量

char *str = "abc";

"abc"就是普通的"char的陣列",在表示式中被解釋成"指向char的指標",然後被賦給str。

第四章  

注意陣列和指標的常用方法

可變長陣列  和 p165 java陣列的聯絡。 java的陣列是儲存在堆中的(因為宣告int[] hoge = new int[10]),但不能改變長度,他沒有類似於realloc()這樣的函式。

可變長結構體

第五章 

實踐,推薦讀者認真將這一章的兩個案例 分別實現  有助於理解

相關推薦

總結征服C指標

對於接觸過c語言,而沒有理解指標以及記憶體佈局的人來說,《征服C指標》是不錯的選擇。 這本書中的補充內容也值得閱讀,通過和java,c++等一些語言比較,來體會c語言的魅力。 第一章  從基礎開始 幾乎所有的處理程式中,所謂的“指標型別的值”,實際是指記憶體的地址。 p28 的補充值得看,主要講了N

征服C指標筆記(原著《征服C指標》作者:前橋和彌 吳雅明 譯)

以下程式碼及其註釋  均為 自己手敲,並在notpad++ 上執行測試沒問題的。使用notepad++ 編譯需要安裝外掛MinGW ,並且設定環境變數。 Notepad++ 下載地址:   使用的外掛MinGW(綠色版,免安裝)下載地址: 安裝教程見:

征服C指標》——讀書筆記(1)

一、指標的基本知識 示例程式碼: #include <stdio.h> int main(void) { int hoge = 5; int piyo = 10; int *hoge_p; /*輸出每個變數的地址*/

征服C指標學習筆記

1.對變數使用&運算子,可以取得該變數的地址。這個地址稱為指向該變數的指標。    指標變數hoge_p儲存了指向其他變數的地址的情況下,可以說“hoge_p指向hoge”。   對指標變數運用*運算子,就等於它指向的變數。如果hoge_p指向hoge,*hoge_

學習《征服C指標》第一天

筆記: 1、什麼是指標型別?      指標型別和int型別,double型別一樣,他是存在“指標型別的變數”和“指標型別的值”的。 2、int  *p  這裡宣告的是變數p, p的型別是“指向int的指標”。 3、在C語言中,關於main函

征服C指標(講那麼複雜,中國人永遠都別想超越美國人)

征服C指標(講那麼複雜,中國人永遠都別想超越美國人) 一段永久掉坑的程式碼 結果沒有錯誤,為什麼掉坑 與大神對話後,我換了另一種寫法 解釋為什麼這樣子寫 一段永久掉坑的程式碼 #in

征服C指標》原始碼(第一章)

程式碼1-1#include <stdio.h> int main(void) { int hoge = 5; int piyo = 10; int *hoge_p; /* それぞれの変數のアドレスを表示

c++ 四大智慧指標 std::auto_ptr std::shared_ptr std::unuque std::weak_ptr 比較總結

1. 動態記憶體必要性 程式不知道自己需要多少物件;  程式不知道物件的準確型別;  程式需要在多個物件之間共享資料; 2. 動態記憶體在哪裡 程式有靜態記憶體、棧記憶體。靜態記憶體用來儲存區域性static物件、類static資料成員以及定義在任何函式之外的變數

C 指標總結

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

sklearn模型評估指標總結歸納

文章目錄 機器學習模型評估 分類模型 迴歸模型 聚類模型 交叉驗證中指定scoring引數 網格搜尋中應用 機器學習模型評估 以下方法,sklearn中都在

C++ Primer Plus書--C++指標及使用new分配記憶體,使用delete釋放記憶體

先來個簡單的程式初步認識一下指標  #include "iostream" using namespace std; int main() { // 定義一個int型變數 int num = 123; // 定義一個int型指標變數 int * p_num; // 指標指向

C++ premier Plus書--C++指標, 陣列, 結構體, 字串

指標和字串, demo: #include "iostream" #include "cstring" using namespace std; int main() { char animal[20] = "bear"; // 字元常量指標, 也就是bird指向

C++ premier Plus書C++指標,陣列,指標算術

首先看一下c++裡的動態建立陣列 int* p_array = new int[10]; new運算子返回第一個元素的地址, 也就是會把陣列的第一個元素的地址賦給指標p_array 當使用完new分配的記憶體時, 應該使用delete來釋放他們: delete[] p_array;

初階C-指標總結與坑

指標的定義 在電腦科學中,指標(Pointer)是程式語言中的一個物件,利用地址,它的值直接指向(points to)存在電腦儲存器中另一個地方的值。由於通過地址能找到所需的變數單元,可以說,地址指向該變數單元。因此,將地址形象化的稱為“指標”。意思是通過它能找到以它為地址的記憶體單元。

c/c++---用二級指標操作二維陣列

通過二級指標去訪問二維陣列需要先給二級指標分配等同於二維陣列行數的一維陣列指標,然後把二維陣列的每行首地址賦值給對應位置的一維指標上。之後就可以通過二維指標直接訪問了。 參考程式碼如下,可以看具體註釋輔助理解。   #include

C++ - 指標總結

指標是什麼? 指標是一變數或函式的記憶體地址,是一個無符號整數,它是以系統定址範圍為取值範圍,32位,4位元組。   指標變數: 存放地址的變數。在C++中,指標變數只有有了明確的指向才有意義。   指標型別 int*ptr; // 指向int型別的指標變

C++知識點備忘錄函式、指標(五)

1、引數為空 void say_hi():在C++中,括號為空與在括號中使用關鍵字void是等效的——意味著函式沒有引數。 2、傳遞陣列 為將陣列型別和元素數量告訴陣列處理函式,請通過兩個不同的引數來傳遞他們:         void fillArray(int a

C++面試總結常用基礎知識

轉載自:https://www.jianshu.com/p/e21d99638cf9C++程式設計師面試一般都是以下三板斧1.基礎問答2.然後一頓虛擬函式、虛擬函式表、純虛擬函式、抽象類、解構函式、拷貝建構函式3.運算元過載、STL、智慧指標-------------------分割線------------

菜鳥的C#學習旅——C#三大結構總結

  目錄 順序結構 一、順序執行 二、跳轉執行 選擇結構 一、if語句 二、if語句的巢狀 三、switch語句 四、switch語句的巢狀 五、if語句與switch語句相互巢狀 迴圈結構 一、while語句 二、do語句 三、

C++】STL常用容器總結十二:string類

13、string類 宣告 string類本不是STL的容器,但是它與STL容器有著很多相似的操作,因此,把string放在這裡一起進行介紹。 之所以拋棄char*的字串而選用C++標準程式庫中的string類,是因為他和前者比較起來,不必擔心記憶體是