2017-04-17 29 views
-2
#include <stdio.h> 
#include <cs50.h> 

int main (void) 
{ 
    int *x; 
    x = malloc(sizeof(long long)*3); 
    scanf("%i %i %i",x, (x+1), (x+2)); 
    printf("%i\t %i\t %i\n",(int)x, (int)(x+1), (int)(x+2)); 
    printf("%i\t %i\t %i\n",*x, *(x+1), *(x+2)); 
    free(x); 
} 

這一計劃的輸入12,2,3輸出是:在c中如何分配內存,以及爲什麼兩個連續內存之間的差異總是4?

43171856   43171860  43171864 
12  2  3 

所以,我的問題是,爲什麼地址之間的差爲4在每種情況下, 如果*x43171856然後*(x+1)應該指向4317185而不是43171860sizeof(long long)也是8字節,所以如何分配內存在4317185643171860之間的這些4字節之間分配8個字節。

回答

1

這是C的真混亂位中的一個:x+1,當x具有指針類型,遞增sizeof(*x)x數值,由1

它必須是這樣,因爲對於任何指針類型T *xx+1&x[1]相同。 &x[1]是由x指向的僞陣列中的第二個T的地址。因此的x+1數值必須等於xsizeof(T)的數值,而你的情況是4

malloc,同時,不知道你通過它3*sizeof(long long)。它看到malloc(24)它給你24個字節,它(在你的平臺上)是六個int s。你只用了前三個,這很好,只是浪費了一點記憶。你可能打算寫3*sizeof(int)

3

首先,在你的代碼

printf("%i\t %i\t %i\n",(int)x, (int)(x+1), (int)(x+2)); 

調用實現定義的行爲,你想一個指針轉換爲整數。

如果你想打印指針

  • 使用%p格式說明
  • 投的參數void *

這就是說,指針運算榮譽的數據類型。您已聲明x是指向int的指針,因此任何指針算術都將基於sizeof(int),無論您的平臺中的評估結果如何。

引用C11,章§6.5.6/ P8,(重點煤礦

當具有整數類型的表達式添加到或從一個指針中減去,所述 結果具有的類型指針操作數。 如果指針操作數指向數組對象的元素,並且該數組足夠大,則結果指向從原始元素偏移的元素,以使得結果數組元素和原始數組元素的下標之差等於整數表達式。換句話說,如果表達式P指向 陣列對象的i個元素,表述(P)+N(等同於N+(P))和 (P)-N(其中N具有值n)指向,分別i+n和第i−n數組對象 的第012個元素,只要它們存在。 [...]

在你的代碼,你寫

x = malloc(sizeof(long long)*3); 

這是錯誤。在這個的情況下,您可能會更安全一些,因爲sizeof(long long)>=sizeof(int),但對於任何任意類型的情況都不是這樣。

  • 最好的情況:你最終會浪費記憶。
  • 最壞情況:您將最終訪問超出限制(無效)的內存。

更好,首選的方式來寫,這將是

x = malloc(sizeof*x * 3); //sizeof is not a function :) 

,然後檢查malloc()成功。這將分配所需的確切內存量,不多不少。

0

您正在使用一個int *,它通常是32位,因此是4個字節。 請嘗試使用長長的* x代替? 你有你說的分配的8 * 3字節byt只使用它們的4 * 3字節。 每一個fefeset(x + 1)只是偏離int的大小。

0

C 2011 Online Draft

6.3.2.1左值,數組和功能指示器
...
3除了當它是 sizeof操作者的操作數, _Alignof操作者 ,或者 一元運算符 &運算符,或者是一個字符串文字用法d初始化數組,具有 類型「被轉換爲與類型「的表達式」指針 類型「」指向 到陣列對象的初始元素,是'類型的陣列」的表達式不是左翼。如果數組對象具有 寄存器存儲類,則行爲未定義。

在大多數情況下,一個表達型的「的T陣列」將被轉換(「衰變」)來的「指針T」的表達式,表達式的值將是地址數組的第一個元素。

據我所知,在_Alignof操作子句是在網上草案在正式™糾正,不能隨意可用的標準,這就是爲什麼它在帖中剔除上述錯誤。

6.5.2數組下標
...
     後綴表達式後跟表達式在方括號 []是一個數組對象的元素的下標 指定。下標操作 [] 的定義是 E1[E2]相同 (*((E1)+(E2)))。因爲 應用於二進制 +操作者的轉換規則,如果 E1是一個數組對象(等同於一個指針數組對象的 初始元件)和 E2的是一個整數, E1[E2]指定 E2-第 元的 E1(從零開始計數)。

鑑於陣列T類型和整數ia,表達a[i]相當於(定義爲)*(a + i) - 給定一個地址a,偏移i元件T類型的從(不是字節)解決並取消引用結果。

如果a爲數組或指針表達和i是一個整數表達式,然後a[i]i[a]將產生相同的結果。

6.5.6加法運算符
...
     當具有整數類型的表達式被加到或減去一個指針,其結果具有指針操作數的類型。如果指針操作數指向數組對象的一個​​元素,並且該數組足夠大,則結果指向與原始元素偏移的元素,以使得結果數組元素和原始數組元素的下標之差等於整數表達式。換句話說,如果表達式 P點 所述 我的陣列對象的個元素,表述 (P)+N(等同於 N+(P))和 (P)-N(其中 N具有值 Ñ),分別指向中, + ñ和第 - ñ陣列對象的個元素,只要它們存在。此外,如果表達式指向數組對象的最後一個 元素,則表達式 (P)+1指向數組對象的最後一個元素之後的一個點,並且如果表達式 Q指向數組對象的最後一個元素之後的一個,表達式的表達式爲 Q (Q)-1指向數組對象的最後一個元素。如果指針操作數和結果都指向相同數組對象的元素,或者指向數組對象的最後一個元素,則評估不應產生溢出;否則, 行爲未定義。如果結果指向一個超出數組對象的最後一個元素,則不應將其用作被評估的一元運算符的操作數。

如果p是指向T類型的對象,則表達式p + 1產生該類型的下一個對象的地址。如果sizeof (T)爲1,則p + 1將地址加1。如果sizeof (T)爲4,則p + 1將地址加上。

類似地,表達++pp++預先p指向T類型的下一個對象

相關問題