2015年12月11日 星期五

字串複製

C 標準函式庫的字串是以 0 為結尾的 char 陣列,字串長度不計結尾 0,實際儲存空間至少要字串長度加 1。
函數字串結尾?回傳值說明
strcpy()必定結果字串事先確保結果空間要足夠。
strncpy()未必限定結果最大長度。
strlcpy()必定libbsd,非 POSIX,限定結果最大長度。
memcpy()必定事先需要知道字串長度或最大長度。
memmove()必定同 memcpy(),並允許記憶體空間可以重複。
strdup()必定動態取得的結果字串
strndup()限定結果最大長度。
strdupa()函式結束時結果空間自動釋出。
strndupa()函式結束時結果空間自動釋出,限定結果最大長度。
sprintf()
vsprintf()
必定字串長度類似 strcpy()。
snprintf()
vsnprintf()
限定結果最大長度。類似 strlcpy()。
asprintf()
vasprintf()
結果空間動態取得,類似 strdup()。

最簡單的字串複製,莫過於
char *strcpy(char *dst, const char *src)
複製 src 字串到 dst,回傳 dst。其內部基本作法是從位址 src 開始一個 byte 一個 byte 複製到 dst 開始的記憶體空間,直到複製的資料內容是 0 結束。必須確保 src 字串有結尾 0,以及 dst 開始有足夠的記憶體空間,至少是 src 字串長度加 1。另外一點就是 src 跟 dst 記憶體空間避免重複 (dst 指標比 src 指標小應該沒關係,但不能保證)。

如果 src 字串可能大於 dst 可容納的空間的話,就要限制最大的複製大小。
char *strncpy(char *dst, const char *src, size_t n)
跟 strcpy() 一樣,但多了檢查最多複製 n bytes。要注意的是可能沒複製到字串結尾 0,這樣的話 dst 字串就沒結尾。如果要確保 dst 有結尾,dst 最後要多預留一個 byte 並且放 0。

libbsd 提供 (來自 BSD,非 POSIX 標準) 跟上述 snprintf() 作用一樣,但樣子像 strncpy():
size_t strlcpy(char *dst, const char *src, size_t n)
一樣最多從 src 複製 n-1 byte,回傳值為複製的 byte 數。如果回傳值 >= n,則有截斷情形。

sprintf()、snprintf()、vsprintf()、或 vsnprintf() 是複製成某種格式的字串,格式也可以包含字串。這些會自動確保複製結果的字串有結尾 0,他們的回傳值是不含結尾 0 總共複製了幾個 byte。其中 snprintf() 跟 vsnprintf() 有限制含結尾 0 總共複製的大小。
int snprintf(dst, n, "%s", src)
跟 strncpy() 的作用的相像,但最多只會從 src 複製 n-1 bytes 到 dst,回傳值 ≥ n,就表示 src 後面有截斷沒複製到。

如果已經知道 src 字串的長度,其實未必需要使用字串複製的函數,直接使用記憶體複製,複製過程不用檢查字串結尾 0。
void *memcpy(void *dst, const void *src, size_t n)
跟 strncpy() 很像,但純粹是從 src 複製 n bytes 到 dst。如果 n 放 src 字串長度加 1,剛好就是你要的。

如果 src 跟 dst 記憶體空間有重複,可以使用
void *memmove(void *dst, const void *src, size_t n)

標準 C 的字串是以 0 為結尾,但事實上字串也可以用別的方式表示,常見的另一種方式是除了字串本身外,也紀錄字串長度。這樣很容易得知字串長度,不需要一個 byte 一個 byte 查到結尾 0 才知道字串長度。
int snprintf(dst, size, "%.*s", src_len, src)
  • 格式裡用「%.*s」:「*」對應的參數表示複製的字串長度,不管來源字串有無結尾 0
其它相關
  • void *memccpy(void *dst, const void *src, int c, size_t n)
  • void bcopy(const void *src, void *dst, size_t n) obsolete
  • stpcpy
  • stpncpy
  • strdup(const char *src)
  • strndup()
  • strdupa()
  • strndupa()
  • wcscpy
  • wcsncpy
  • strcat
  • strncat
  • string operations
    => strXXX() 系列 (以及 index, rindex)
    byte string operations
    => memXXX() 系列
    => bXXX() 系列 obsolete
     

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...