c語言函數是如何獲取傳入的數組(指針)的指針所指向內容的長度的,有辦法嗎?

比如需要一個函數需要傳入一個指針來儲存數據,能判斷這個指針指向的空間是否足夠大來容納數據嗎? 很多庫函數都是另外傳入一個長度參數,能直接根據傳入的指針來獲取空間大小嗎? 這樣就不需要長度參數了。 對c++不是太會……,正在學習C,難道c語言沒有辦法嗎?


C 語言跟 C++ 是不同的。最大的不同之處在於,它不會象變魔法般的在後台以程序員不知道的方式添加一些奇奇怪怪的東西。——這可能是好事,也可能是壞事,取決於你在什麼領域進行編程。

一個數組就是一串序列,它的地址以及存儲的內容都一目了然在那裡了,沒有任何地方記錄了有關其「長度」的信息。所以你自然沒有辦法知道它的長度。信息都保存在內存中,你能獲取一個信息就意味著這個信息或者用來推算這個信息的相關信息必須被保存在內存中的某個地方,你能知道一個數組的長度就必須有某個地方保存了這個數組的長度信息。

題主要的是有某個「魔法」的方法知道一個指針指向的內容的長度,但如果你根本沒有在任何地方保存它的長度,沒有人知道,又如何能獲取?

所以,傳遞長度本質上來說就這麼幾個辦法,1,單獨傳一個長度參數,(C方式),或者對數據內容進行約定(C字元串方式),2,把數據包裝成一個結構,結構中有一個欄位是長度,另外一個欄位是數據內容,同時在添加一些其他的欄位作為控制信息等(C++方式)。3,其他各種黑科技,使用這些黑科技一般會造成程序不可移植,只能適用於特定場合。


輪子哥這樣調戲樓主是不對的:)

c語言裡面通常會多加一個參數來表示指針指向內容的長度,如:

ssize_t read_from_stream(stream_t* stream, void* buffer, size_t size)


如果數組帶長度信息,庫函數作者需要傳長度嗎?


沒有辦法,指針本身完全沒有攜帶長度信息。你能夠通過 sizeof 獲取數組的長度是因為:

編譯器在將 C 代碼轉換成彙編代碼時,自動將其替換成了實際的數值。

http://goo.gl/oqfRX1

http://goo.gl/RLTX5g

請將 Compiler 設置為 arm-linux-gnueabi-* 並將 Compiler options 置空

然後找到 bl printf 的上一句中#後面的那個數字


樓上很多回答都很有道理。從我理解的角度回答,這個可能和C的特性、歷史以及應用場景有關。大家都知道,除了彙編程序,應該C語言編譯出來的程序最小了,如果不出問題,效率也很高,為什麼?以前硬體多珍貴啊。(可以看計算機歷史了解)所以C編譯器在編譯時本身不會為指針或數組留下太多額外的管理結構,尤其是動態分配的內存以及在程序內部臨時在棧上開闢的內存。當然,全局數組是沒有問題的,可以不傳長度,這是因為編譯的時候已經記錄了。但也僅僅是全局數組,你懂的,不能分太多啊,浪費。(具體可以看彙編代碼,雖然有管理結構可能得到部分分配的數據的長度,但為了安全這部分對開發者和調用者都是不透明的)這就可以理解為什麼傳指針時為什麼在需要的時候還要同時傳內容長度,不然其他函數只拿到一個地址根本不知道該處理多長的內容。亂來很容易訪問越界的,不誇張說成熟的C程序中至少一半以上的bug和飛指針有關。一些技巧也有,但不建議用。畢竟查飛指針不是件好事。


比如:

function(XXX* array, int length)

再比如,實際最常用的:

int main(int argc, char** argv)
{

}


如果是new出來的話,有可能找到,想想delete []array時,系統是如何知道需要delete的長度的呢?一種說法是array指針的地址前面的地址,有保存該數組大小的信息,於是可以獲取到了,具體不確定


指針不帶長度信息,如果非要帶長度就只能用數組做參數,不同長度的數組屬於不同的類型,所以只能用模板函數了,就跟std::begin一樣

std::begin屬於通用的短小函數,不是這個類型的函數是沒必要這樣寫的,這也是"很多庫函數都是另外傳入一個長度參數"的原因


傳std::array或std::vector,永久解除煩惱


從C/C++來看,沒有辦法

對於特定的平台(Windows + msvcrtxxx或者Linux x.x.x + GCC x.x之類的)可能有平台依賴的解決方法

也就是找到分配的這段內存的頭部,可能會有一個存放有這段內存大小的結構,或者系統也可能有一些函數來獲取,但是這依賴於不同的實現。


指針只給出了兩種信息:所指向數據的類型地址

而根據兩者你是無法判斷該數據的地址範圍的(只知起始地址不知終結地址,另外類型也是無法幫助你的,請自行腦補)。

當然也有一些黑魔法(利用起始地址),具體可參考OOC。


c沒有。傳進來的東西及其上下文,必須自己心裡有數。

接受不了可以選擇別的語言。


加個參數把長度值傳進去不就是了。


最簡單的辦法就是再增加個入參讓調用者告訴你吧,否則自己處理確實太麻煩


c語言的情況下,老老實實的把長度帶上。

就好比你給搬家公司的人說我要搬家,然後人家說我派一輛車過去,你覺得這會有什麼問題?


歸根到底,指針只是一個變數,它不可能附帶長度。除非另傳一個參數,或者vector。


樓上回答很精彩,我試著從理論解釋一下。一個變數,通常包含兩種屬性,一個是類型,一個是操作。類型決定了大小和操作方式。指針也是變數,其兩個屬性沒辦法決定數組的長度的。另外,數組沒辦法做參數,即使有,一律轉為指針。所以要傳遞數組大小,需要另外的屬性,也就是另外的參數咯。


你可以規定數組的前若干個位元組用來存儲這個數組的長度,用的時候偏移一下再用。不過你得自己管理好。或者自己實現一個類似功能的結構體。


最近也在寫一個sntp client,需提供一個介面sntp_set_server(char **servers)讓外部來設定sntp sever的域名,域名是以指針數組的形式保存的,例如

static char *servers[] =

{

"pool.ntp.org",

"time-a.nist.gov",

"time-b.nist.gov",

NULL,

};

然後以二維指針作為實參傳入介面中。

在執行sntp時需要得到域名的數量這一參數,可以按照下面的辦法計算出來,兩個int變數初始化為0,然後根據下列代碼容易得出域名數量。

while(sntp_sever_names[i] != NULL)

{

num_servers++;

i++;

}

這就是把一個可變的數組,轉化為指針數組,然後計算該數組行數(即本例中域名數)的方法。當然,直接從外部傳個參數進來是最簡單的,但有時候別人不想修改他的代碼來迎合你,就只能這樣了吧,有其他的方法歡迎分享,我也還在進一步學習中


全局變數(?_?)


pansz說得有道理,指針蘊含的信息僅僅是數組在哪裡,一般的數組中所蘊含的是其他的信息而沒有長度的信息,所以僅僅根據指針是不能知道數組的長度的。

C/C++的字元串是特殊的數組。因為字元串中只有結束處才會用到"",所以可以根據""出現的位置推斷出字元串的長度。

因此,要知道數組的長度,一般都需要附加長度的信息,無論是單獨把長度作為參數傳給函數,還是把長度與數組包裝成一個結構體(C++或java等中的類)。除非已經知道數組中不會出現某個元素,把該元素(例如字元串的"")作為數組的結束標誌。


方法有2,都是需要額外的操作約定來完成,不如用通用的傳入個長度的方式。

方法一,在這個指針指向的數組的前面放數組大小。

template&

void Func(T* data)

{

size_t length = *((size_t*)data - 1);

}

這樣就取到了長度,初始化的時候需要額外管理這個長度。

方法二,參考字元串,數組用某個特定的值作為結束的標誌

template&

void Func(T* data)

{

T* curr = data;

while (*curr != T::end)

{

curr++;

}

}

因此,一般來說還是

template&

void Func(T*, size_t length);

簡單快捷


要是解決了這個問題,就不會有人說c語言指針學這麼不安全了,樓主加油,為我等解決此問題


推薦閱讀:

C語言零基礎想要自學,有什麼書可以推薦一下嗎?
寫操作系統只能用彙編和 C 語言嗎?
不同的IDE在編譯代碼時是否存在區別?如果有,那請問區別是什麼?
C語言為什麼要有 main 函數?具體作用是什麼?
如果scanf的格式指示符是%f,賦給一個double型的變數,在內存層面上會發生什麼?

TAG:C編程語言 | 函數 | 指針 |