自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C語言內(nèi)存地址基礎

開發(fā) 后端
從計算機內(nèi)存的角度思考C語言中的一切東東,是挺有幫助的。我們可以把計算機內(nèi)存想象成一個字節(jié)數(shù)組,內(nèi)存中每一個地址表示 1 字節(jié)。

從計算機內(nèi)存的角度思考C語言中的一切東東,是挺有幫助的。我們可以把計算機內(nèi)存想象成一個字節(jié)數(shù)組,內(nèi)存中每一個地址表示 1 字節(jié)。比方說我們的電腦有 4K 內(nèi)存,那這個內(nèi)存數(shù)組將會有 4096 個元素。當我們談論一個存儲地址的指針時,就當相于我們在談論一個存儲著該內(nèi)存數(shù)組某個元素索引的指針。逆向引用某個指針,將會得到數(shù)組中該索引所指向的 值。這一切當然都是謊言。操作系統(tǒng)對內(nèi)存的管理要遠比這復雜。內(nèi)存不一定連續(xù),也不一定按順序處理。但前面的類比是一種討論C語言內(nèi)存的簡單方式。

如果對『指針』、『地址』和『逆向引用』感到混亂,請看《C語言指針5分鐘教程》。// 譯注:“dereferencing” 的譯法比較多,本文采用了“逆向引用”。 

假設我們的計算機有 4K 的內(nèi)存,下一個開放地址的索引是2048。我們聲明一個新的字符變量i='a'。當該變量所 獲得的內(nèi)存放置了它的值,變量的名字也與內(nèi)存中的該位置關聯(lián),我們的字符i就獲得了一個存儲在2048位置的值。該字符是單字節(jié)的因此它只占用了索引為 2048 的位置。如果我們對 i 變量使用地址操作符(&),它將返回到索引為2048的位置。如果這個變量是另一種類型,比如是 int,它將占用4字節(jié),在數(shù)組中占用索引為 2048-2051 的位置。使用地址操作符仍將返回索引2048的位置,因為 int 型即便占用了 4 字節(jié),但它開始于 2048 位置。我們看一個例子:

  1. // intialize a char variable, print its address and the next address  
  2. char charvar = '\0';  
  3. printf("address of charvar = %p\n", (void *)(&charvar));  
  4. printf("address of charvar - 1 = %p\n", (void *)(&charvar - 1));  
  5. printf("address of charvar + 1 = %p\n", (void *)(&charvar + 1));  
  6.    
  7. // intialize an int variable, print its address and the next address  
  8. int intvar = 1;  
  9. printf("address of intvar = %p\n", (void *)(&intvar));  
  10. printf("address of intvar - 1 = %p\n", (void *)(&intvar - 1));  
  11. printf("address of intvar + 1 = %p\n", (void *)(&intvar + 1));  

運行將得到如下的輸出:

  1. address of charvar = 0x7fff9575c05f 
  2. address of charvar - 1 = 0x7fff9575c05e 
  3. address of charvar + 1 = 0x7fff9575c060 
  4. address of intvar = 0x7fff9575c058 
  5. address of intvar - 1 = 0x7fff9575c054 
  6. address of intvar + 1 = 0x7fff9575c05c 

在第一個例子的1-5行中,我們聲明了一個字符變量,并打印輸出該字符的地址,然后打印了內(nèi)存中位于該變量前后的兩個地址。我們是通過使 用&操作符并+1或-1來獲取前后兩個地址的。在7-11行的第二個例子中我們做了差不多的事,除了聲明了一個int型變量,打印出它的地址以及 緊鄰它前后的地址。

在輸出中,我們看到地址是 16 進制的。更值得注意的是,字符的地址前后相差1字節(jié)。int 型變量地址前后相差四字節(jié)。內(nèi)存地址的算法、指針的算法、都是根據(jù)所引用的類型的大小的。一個給定的類型的大小是依賴于平臺的,我們這個例子中的char 是1字節(jié),int是四字節(jié)。將字符的地址-1是改地址前的地址,而將int型地址-1是該地址前4個的地址。

在例子中,我們是用地址操作符來獲取變量的地址,這和使用表示變量地址的指針是一樣的效果。

英文原博中評論已經(jīng)提出:存儲&charvar-1(一個非法的地址因它位于數(shù)組之前)在技術上是未特別指出的行為。C的標準已經(jīng)聲明,未特別指出的以及在一些平臺存儲一個非法地址都將引起錯誤。

數(shù)組地址

在C語言中,數(shù)組是相鄰的內(nèi)存區(qū)域,它存儲了大量相同數(shù)據(jù)類型的值(int、long、*char等等)。很多程序員第一次用C時,會將數(shù)組當做指針。那是不對的。指針存儲一個簡單的內(nèi)存地址,而一個數(shù)組是一塊存儲多個值的連續(xù)的內(nèi)存區(qū)域。

  1. // initialize an array of ints 
  2. int numbers[5] = {1,2,3,4,5}; 
  3. int i = 0; 
  4.   
  5. // print the address of the array variable 
  6. printf("numbers = %p\n", numbers); 
  7.   
  8. // print addresses of each array index 
  9. do { 
  10.     printf("numbers[%u] = %p\n", i, (void *)(&numbers[i])); 
  11.     i++; 
  12. while(i < 5); 
  13.   
  14. // print the size of the array 
  15. printf("sizeof(numbers) = %lu\n"sizeof(numbers)); 

運行將得到如下的輸出:

  1. numbers = 0x7fff0815c0e0 
  2. numbers[0] = 0x7fff0815c0e0 
  3. numbers[1] = 0x7fff0815c0e4 
  4. numbers[2] = 0x7fff0815c0e8 
  5. numbers[3] = 0x7fff0815c0ec 
  6. numbers[4] = 0x7fff0815c0f0 
  7. sizeof(numbers) = 20 

在這個例子中,我們初始化了一個含有 5 個 int 元素的數(shù)組,我們打印了數(shù)組本身的地址,注意我們沒有使用地址操作符 & 。這是因為數(shù)組變量已經(jīng)代表了數(shù)組首元素的地址。你會看到數(shù)組的地址與數(shù)組首元素的地址是一樣的。然后我們遍歷這個數(shù)組并打印每個元素的內(nèi)存地址。在我們 的計算機中 int 是四個字節(jié)的,數(shù)組內(nèi)存是連續(xù)的,因此每個int型元素地址之間相差4。

在最后一行,我們打印了數(shù)組的大小,數(shù)組的大小等于sizeof(type)乘上數(shù)組元素的數(shù)量。這里的數(shù)組有5個int型變量,每一個占用4字節(jié),因此整個數(shù)組大小為20字節(jié)。

結構體地址

在C語言中,結構體一般是連續(xù)的內(nèi)存區(qū)域,但也不一定是絕對連續(xù)的區(qū)域。和數(shù)組類似,它們能存儲多種數(shù)據(jù)類型,但不同于數(shù)組的是,它們能存儲不同的數(shù)據(jù)類型。

  1. struct measure { 
  2.   char category; 
  3.   int width; 
  4.   int height; 
  5. }; 
  6.   
  7. // declare and populate the struct 
  8. struct measure ball; 
  9. ball.category = 'C'
  10. ball.width = 5; 
  11. ball.height = 3; 
  12.   
  13. // print the addresses of the struct and its members 
  14. printf("address of ball = %p\n", (void *)(&ball)); 
  15. printf("address of ball.category = %p\n", (void *)(&ball.category)); 
  16. printf("address of ball.width = %p\n", (void *)(&ball.width)); 
  17. printf("address of ball.height = %p\n", (void *)(&ball.height)); 
  18.   
  19. // print the size of the struct 
  20. printf("sizeof(ball) = %lu\n"sizeof(ball)); 

運行后的輸出結果如下:

  1. address of ball = 0x7fffd1510060 
  2. address of ball.category = 0x7fffd1510060 
  3. address of ball.width = 0x7fffd1510064 
  4. address of ball.height = 0x7fffd1510068 
  5. sizeof(ball) = 12 

在這個例子中我們定義了一個結構體measure,然后聲明了該結構體的一個實例ball,我們賦值給它的width、height以及 category成員,然后打印出ball的地址。與數(shù)組類似,結構體也代表了它首元素的地址。然后打印了它每一個成員的地址。category是第一個 成員,它與ball具有相同的地址。width后面是height,它們都具有比category更高的地址。

你可能會想因為category是一個字符,而字符型變量占用1字節(jié),因此width的地址應該比開始出高1個字節(jié)。從輸出來看這不對。 根據(jù)C99標準(§6.7.2.1),為邊界對齊,結構體可以給成員增加填充字節(jié)。它不會記錄數(shù)據(jù)成員,但會增加額外的字節(jié)。在實際中,大多數(shù)的編譯器會 使結構體中的每個成員與結構體最大的成員有相同大小,

在我們的例子中,你可以看到char實際上占用4字節(jié),整個struct占用12個字節(jié)。都發(fā)生了什么?

1.struct變量指向struct首元素的地址

2.不要假設struct的成員是與其它區(qū)域分離的大量特殊的字節(jié),它們也許有邊界字節(jié)或者內(nèi)存并不連續(xù)。使用地址操作符&來獲得成員的地址

3.使用sizeof(struct instance)來獲得struct的總大小,不用假設它是各個成員域的大小總和,也許還有補充。

結論

喜歡這篇博文可以幫你理解更多的在C中如何操作不同的數(shù)據(jù)類型的地址。在以后的博文中,我們將會繼續(xù)研究一下指針和數(shù)組的基礎。

原文鏈接:http://denniskubes.com/2012/08/17/basics-of-memory-addresses-in-c/

譯文鏈接:http://blog.jobbole.com/44845/

責任編輯:陳四芳 來源: 伯樂在線
相關推薦

2017-07-25 15:09:48

Linux地址轉化

2015-09-29 08:51:59

內(nèi)存地址主引導

2023-12-08 14:32:02

C語言編程文件操作

2011-05-11 15:45:50

內(nèi)存管理Objective-C

2022-01-13 10:30:21

C語言內(nèi)存動態(tài)

2021-12-16 06:52:33

C語言內(nèi)存分配

2021-06-01 07:16:21

C語言基礎代碼

2021-11-10 10:48:36

C++函數(shù)指針

2024-04-29 13:50:00

2010-01-19 14:45:35

C++語言

2021-04-27 13:56:49

內(nèi)存.映射地址

2020-10-19 09:34:04

C語言內(nèi)存錯誤編程語言

2021-02-20 06:13:18

C 語言C++

2015-05-05 14:40:31

2022-11-02 07:23:06

2020-11-04 08:37:37

C語言C++內(nèi)存

2021-02-21 12:09:32

C 語言基礎語法

2023-05-03 21:49:13

2011-07-15 09:20:52

C語言文件操作

2021-02-08 20:25:12

C 語言C++Linux
點贊
收藏

51CTO技術棧公眾號