簡體   English   中英

如何制作一個非空終止的c字符串?

[英]how to make a not null-terminated c string?

我想知道:char * cs = .....;如果cs指向內存塊但是沒有'\\ 0',那么strlen()和printf(“%s”,cs)會發生什么? 我寫這些線:

 char s2[3] = {'a','a','a'};
printf("str is %s,length is %d",s2,strlen(s2));

我得到結果:“aaa”,“3”,但我認為這個結果是因為'\\ 0'(或0字節)恰好位於s2 + 3位置。 如何制作一個非空終止的c字符串? strlen和其他c字符串函數嚴重依賴於'\\ 0'字節,如果沒有'\\ 0',我只想更深入,更好地了解這條規則。

ps:通過研究SO上的帖子來激發我的好奇心。 如何將const char *轉換為std :: string以及該帖子中的這些單詞:“這實際上比它看起來更棘手,因為你不能調用strlen,除非字符串實際上是nul終止的。”

如果它不是以null結尾,那么它不是C字符串,你不能使用像strlen這樣的函數 - 它們將從數組的末尾開始,導致未定義的行為。 你需要以其他方式跟蹤長度。

你仍然可以用printf打印一個沒有終止的字符數組,只要你給出長度:

printf("str is %.3s",s2);
printf("str is %.*s",s2_length,s2);

或者,如果您有權訪問數組本身,而不是指針:

printf("str is %.*s", (int)(sizeof s2), s2);

您還標記了C ++的問題:在該語言中,您通常希望避免所有這些容易出錯的malarkey並使用std::string

根據定義,“C字符串”以空值終止。 該名稱來自具有以null結尾的字符串的C約定。 如果你想要別的東西,它不是C字符串。

因此,如果您有一個非空終止的字符串,則不能在其上使用C字符串操作例程。 你不能使用strlenstrcpystrcat 基本上,任何采用char*但沒有單獨長度的函數都是不可用的。

那你能做什么? 如果您有一個非空終止的字符串,則您將分別擁有該長度。 (如果你沒有,你就搞砸了。你需要一些方法來找到長度,無論是通過終結器還是單獨存儲它。)你可以做的是分配一個適當大小的緩沖區,復制字符串,並附加一個null。 或者,您可以編寫自己的一組字符串操作函數,這些函數可以使用指針和長度。 在C ++中,你可以使用std::string的構造函數,它接受一個char*和一個長度; 那個人不需要終結者。

會發生什么是strlen繼續前進,讀取內存值,直到它最終變為null。 然后假設它是終結符並返回可能非常大的長度。 如果你在一個需要使用C字符串的環境中使用strlen,那么你可以將這個巨大的數據緩沖區復制到另一個不夠大的數據庫中 - 導致緩沖區溢出問題,或者最多你可以復制一個大量垃圾數據進入緩沖區。

將非空終止的C字符串復制到std:字符串將執行此操作。 如果你確定你知道這個字符串只有3個字符長並丟棄其余的字符串,那么你仍然會有一個大的長std:字符串,其中包含前3個好字符,然后是浪費。 那效率很低。

道德是,如果你使用CRT函數來操作C字符串,它們必須是空終止的。 它與任何其他API沒有什么不同,您必須遵循API為正確使用而設置的規則。

當然,沒有任何理由,你不能使用CRT的功能,如果你總是使用特定長度的版本(如strncpy()函數),但你必須限制自己只是那些, 總是和手動跟蹤的正確長度。

你的假設是正確的:你的strlen正在從純粹的運氣中返回正確的值,因為在你的不正確終止的字符串之后恰好在堆棧上有一個零。 它可能有助於字符串為3個字節,並且編譯器可能將堆棧上的內容與4字節邊界對齊。

你不能依賴於此。 C字符串最后需要NUL字符(零)才能正常工作。 C字符串處理很亂,容易出錯; 有些庫和API可以幫助減少它......但它仍然很容易搞砸。 :)

在這種特殊情況下,您的字符串可以初始化為以下之一:

  • char s2[4] = { 'a','a','a', 0 }; // good if string MUST be 3 chars long char s2[4] = { 'a','a','a', 0 }; // good if string MUST be 3 chars long
  • Bchar *s2 = "aaa"; // if you don't need to modify the string after creation char *s2 = "aaa"; // if you don't need to modify the string after creation
  • Cchar s2[]="aaa"; // if you DO need to modify the string afterwards char s2[]="aaa"; // if you DO need to modify the string afterwards

另請注意,聲明BC在某種意義上是“更安全”,即如果某人稍后出現並以改變長度的方式更改字符串聲明,則BC仍然自動正確,而A取決於程序員記得要更改數組大小並在末尾保留顯式空終止符。

約定規定具有終止\\0的char數組是空終止字符串。 這意味着所有str*()函數都希望在char-array的末尾找到一個null-terminator。 但就是這樣,它只是慣例。

按照慣例,字符串也應包含可打印字符。

如果你像你一樣創建一個數組char arr[3] = {'a', 'a', 'a'}; 你已經創建了一個char數組。 因為它沒有被\\0終止,所以它在C中不被稱為字符串,盡管它的內容可以打印到stdout。

你所做的是未定義的行為。

您正在嘗試寫入不屬於您的內存位置。

將其更改為

char s2[] = {'a','a','a','\0'};

在第7- 庫函數之前,C標准沒有定義術語字符串 C11 7.1.1p1中的定義如下:

  1. 字符串是由第一個空字符終止並包括第一個空字符的連續字符序列

(強調我的)

如果string的定義是由空字符終止的字符序列,則不以null結尾的非空字符序列不是字符串period。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM