2011-05-09 190 views
19

std::strlen不處理不是\ 0終止的c字符串。它有一個安全版本嗎?有沒有strlen的安全版本?

PS我知道在C++中應該使用std :: string來代替c字符串,但在這種情況下,我的字符串存儲在共享內存中。

編輯

好吧,我需要補充一些解釋。

我的應用程序從共享內存(這是一些長度)獲取字符串,因此它可以表示爲一個字符數組。如果庫中存在編寫該字符串的錯誤,則該字符串不會被零終止,並且strlen可能會失敗。

+15

...那麼什麼_does_終止字符串?如果沒有字符串終止符,並且沒有其他方式從字符串本身推斷字符串的長度,則需要將該長度存儲在某個單獨的變量中。 – 2011-05-09 10:14:04

+9

如果你不知道長度,並且你無法知道長度,那麼你無法確定長度。 – 2011-05-09 10:17:11

+3

一段字符串有多長?兩次從一端到中間的距離。 – Johnsyweb 2011-05-09 10:20:55

回答

5

如果定義了C-字符串作爲

char* cowSays = "moo"; 

那麼你autmagically得到 '\ 0' 末和strlen將返回3.如果你將它定義成:

char iDoThis[1024] = {0}; 

你得到一個空的緩衝區(和一組字符,所有這些都是空字符)。只要不超過緩衝區長度,您就可以用自己喜歡的方式填充它。在開始strlen將返回0,一旦你寫了東西,你也會從strlen得到正確的數字。
你也可以這樣做:

char uhoh[100]; 
int len = strlen(uhoh); 

但這是不好的,因爲你不知道那是什麼陣列英寸它可能會碰到一個你可能沒有的空字符。重點在於空字符是定義的標準方式來聲明字符串已完成。
沒有空字符表示根據定義字符串未完成。改變這將打破字符串如何工作的範例。你想要做的是制定你自己的規則。 C++會讓你做到這一點,但你必須自己寫很多代碼。

編輯 從你新添加的信息,你想要做的是循環陣列上,檢查手空字符。如果您僅希望使用ASCII字符(尤其是在期待字母數字字符的情況下),您還應該進行一些驗證。這假定你知道最大尺寸。 如果您不需要驗證字符串的內容,那麼你可以使用strnlen家庭的功能之一: http://msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm

+4

謝謝。我正在尋找strnlen – 2011-05-09 10:44:10

+6

@VJo:因爲'strnlen'不是標準的C或C++,所以你可能更喜歡'memchr'(檢查null和指針減法)。或者你可能不介意'strnlen'在Windows和Posix中。 – 2011-05-09 11:27:00

+1

@Steve我不知道它不是標準的,但是因爲它是posix,所以對我來說(我正在使用linux)已經足夠了。我想這對於在Windows上編程的人來說也已經足夠了,因爲它在那裏 – 2011-05-09 11:38:40

11

非空終止的C字符串不是C字符串,它們只是字符數組,並且無法找到它們的長度。

+2

好的,但是有沒有替代std :: strlen這是安全的? – 2011-05-09 10:31:06

+3

@VJo「你沒有辦法找到他們的長度」你不明白嗎? – 2011-05-09 10:33:06

+7

@unapersson:假設用戶在「安全」字符串函數(如「strlcpy」)所使用的單詞「安全」的非正統含義中表示「安全」,那麼您所說的不是真實的。那麼,這是真的,但並不相關,因爲提問者並沒有要求如何找到沒有nul終結符的東西的「長度」,他問如何找到長度,如果它有一個,而不是如果它沒有崩潰。有人可能知道緩衝區的長度,但不知道它是否包含一個nul字節,它*可以找出哪個長度(如果是字符串)。 – 2011-05-09 11:21:23

0

您需要將您的編碼字符串。例如:

struct string 
{ 
    size_t len; 
    char *data; 
} __attribute__(packed); 

然後可以接受的任何字符的數組,如果你知道所述第一的sizeof(爲size_t)的共享存儲器位置的字節是字符數組的大小。當你想以這種方式鏈接數組時,它會變得棘手。

最好是相信你的另一端來終止它的字符串,或者推出你自己的strlen,它不會超出共享內存段的行列(提供你至少知道該段的大小)。

3

獲得一個更好的圖書館,或者驗證你擁有的圖書館 - 如果你不能相信你的圖書館做它說的話,那麼你希望你的程序如何?

那是說,假設你知道該字符串所在的buiffer,那

buffer[-1+sizeof(buffer)]=0 ; 
x = strlen(buffer) ; 
  • 使緩衝區比需要更大的長度,然後你可以測試庫。

    assert(x<-1+sizeof(buffer)); 
    
+3

那麼,寫這個庫的人不在這裏了,而且很sl。。我發現了一個導致strlen失敗的bug。無論如何,strnlen正在做我需要的東西 – 2011-05-10 06:38:32

14

您已經添加,字符串是共享內存。這保證了可讀性和固定大小。因此,您可以使用size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize)(請注意strnlen中的額外n)。

如果在input之後的共享內存中沒有\0,或者如果存在字符串長度,則將返回MaxPossibleSize。 (最大可能字符串長度當然MaxPossibleSize-1的,如果共享內存的最後一個字節是第一\0

+0

是的,那就是我所做的。感謝您的回答 – 2011-05-10 09:54:10

0

如果你需要得到共享內存的大小,儘量使用

// get memory size 
struct shmid_ds shm_info; 
size_t shm_size; 
int shm_rc; 
if((shm_rc = shmctl(shmid, IPC_STAT, &shm_info)) < 0) 
    exit(101); 
shm_size = shm_info.shm_segsz; 

相反使用strlen的時候可以使用shm_size - 1,如果你確定它是空的。否則,你可以通過data [shm_size - 1] ='\ 0'來終止它。然後使用strlen(data);

6
size_t safe_strlen(const char *str, size_t max_len) 
{ 
    const char * end = (const char *)memchr(str, '\0', max_len); 
    if (end == NULL) 
     return max_len; 
    else 
     return end - str; 
} 
+1

您可以重新命名該功能以符合以下要求:http://linux.about.com/library/cmd/blcmdl3_strnlen.htm – harper 2015-06-15 16:17:26

0

一個簡單的解決方案:

buff[BUFF_SIZE -1] = '\0' 

OFC這不會告訴你,如果該字符串最初正是BUFF_SIZE-1長或者它只是沒有結束...所以你需要爲XTRA邏輯。

0

這個怎麼樣便攜金塊:

int safeStrlen(char *buf, int max) 
{ 
    int i; 
    for(i=0;buf[i] && i<max; i++){}; 
    return i; 
} 
0

由於Neil Butterworth在他的回答上面已經說:C-字符串未由\ 0字符終止,不C-字符串!

你唯一的機會就是編寫一個不可變的適配器,或者用\ 0終止字符創建C字符串的有效副本。當然,如果輸入錯誤,並沒有像定義的C-字符串:

char cstring[3] = {'1','2','3'}; 

確實會導致意外的行爲,因爲可以有類似[email protected]\0在現在內存。所以例如strlen()的結果現在是6而不是3。

下面的方法顯示瞭如何在任何情況下,創建一個安全的C字符串:

char *createSafeCString(char cStringToCheck[]) { 
    //Cast size_t to integer 
    int size = static_cast<int>(strlen(cStringToCheck)) ; 
    //Initialize new array out of the stack of the method 
    char *pszCString = new char[size + 1]; 
    //Copy data from one char array to the new 
    strncpy(pszCString, cStringToCheck, size); 
    //set last character to the \0 termination character 
    pszCString[size] = '\0'; 
    return pszCString; 
} 

這可確保在您操作C-字符串不上別的東西寫入內存。

但這不是你想要的。我知道,但沒有其他方式來實現字符數組的長度沒有終止。這甚至不是一種方法。它只是確保即使用戶(或開發人員)插入*****工作正常。