自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C語言如何實現(xiàn)動態(tài)擴容的string

開發(fā) 后端
眾所周知,C++ 中的string使用比較方便,關于C++ 中的string源碼實現(xiàn)可以看我的這篇文章:源碼分析C++的string的實現(xiàn)

[[435916]]

眾所周知,C++ 中的string使用比較方便,關于C++ 中的string源碼實現(xiàn)可以看我的這篇文章:源碼分析C++的string的實現(xiàn)

最近工作中使用C語言,但又苦于沒有高效的字符串實現(xiàn),字符串的拼接和裁剪都比較麻煩,而且每個字符串都需要申請內(nèi)存,內(nèi)存的申請和釋放也很容易出bug,怎么高效的實現(xiàn)一個不需要處理內(nèi)存問題并且可以動態(tài)擴容進行拼接和裁剪的string呢?

一個好的string應該有以下功能?

  •  創(chuàng)建字符串
  •  刪除字符串
  •  尾部追加字符串
  • 頭部插入字符串
  •  從尾部刪除N個字符
  •  從頭部刪除N個字符
  •  裁剪字符串
  •  獲取字符串長度
  •  獲取完整字符串

下面來看看各個功能的實現(xiàn):

首先定義一個string的句柄,相當于C++中的實例 

  1. struct c_string;  
  2. typedef struct c_string c_string_t; 

在內(nèi)部string的實現(xiàn)如下: 

  1. // string的初始內(nèi)存大小  
  2. static const size_t c_string_min_size = 32 
  3. struct c_string {  
  4.     char *str; // 字符串指針  
  5.     size_t alloced; // 已分配的內(nèi)存大小  
  6.     size_t len; // 字符串的實際長度  
  7. }; 

創(chuàng)建字符串: 

  1. c_string_t *c_string_create(void) {  
  2.     c_string_t *cs;  
  3.     cs = calloc(1, sizeof(*cs));  
  4.     cs->str = malloc(c_string_min_size);  
  5.     *cs->str = '\0' 
  6.     // 初始分配內(nèi)存大小是32,之后每次以2倍大小擴容  
  7.     cs->alloced = c_string_min_size;   
  8.     cs->len = 0
  9.     return cs;  

銷毀字符串: 

  1. void c_string_destroy(c_string_t *cs) {  
  2.     if (cs == NULL) return;  
  3.     free(cs->str);  
  4.     free(cs);  

內(nèi)部如何擴容呢: 

  1. static void c_string_ensure_space(c_string_t *cs, size_t add_len) {  
  2.     if (cs == NULL || add_len == 0) return;  
  3.     if (cs->alloced >= cs->len + add_len + 1) return;  
  4.     while (cs->alloced < cs->len + add_len + 1) {  
  5.         cs->alloced <<= 1; // 每次以2倍大小擴容  
  6.         if (cs->alloced == 0) {  
  7.             // 左移到最后可能會變?yōu)?,由于alloced是無符號型,減一則會變成UINT_MAX  
  8.             cs->alloced--;  
  9.         }  
  10.     }  
  11.     cs->str = realloc(cs->str, cs->alloced);  

在尾部追加字符串: 

  1. void c_string_append_str(c_string_t *cs, const char *str, size_t len) {  
  2.     if (cs == NULL || str == NULL || *str == '\0') return;  
  3.     if (len == 0) len = strlen(str);  
  4.     c_string_ensure_space(cs, len); // 確保內(nèi)部有足夠的空間存儲字符串  
  5.     memmove(cs->str + cs->len, str, len);  
  6.     cs->len += len;  
  7.     cs->str[cs->len] = '\0';  

在尾部追加字符: 

  1. void c_string_append_char(c_string_t *cs, char c) {  
  2.     if (cs == NULL) return;  
  3.     c_string_ensure_space(cs, 1);  
  4.     cs->str[cs->len] = c;  
  5.     cs->len++;  
  6.     cs->str[cs->len] = '\0';  

在尾部追加整數(shù): 

  1. void c_string_append_int(c_string_t *cs, int val) {  
  2.     char str[12];  
  3.     if (cs == NULL) return;  
  4.     snprintf(str, sizeof(str), "%d", val); // 整數(shù)轉為字符串  
  5.     c_string_append_str(cs, str, 0);  

在頭部插入字符串: 

  1. void c_string_front_str(c_string_t *cs, const char *str, size_t len) {  
  2.     if (cs == NULL || str == NULL || *str == '\0') return;  
  3.     if (len == 0) len = strlen(str);  
  4.     c_string_ensure_space(cs, len);  
  5.     memmove(cs->str + len, cs->str, cs->len);  
  6.     memmove(cs->str, str, len); 
  7.     cs->len += len;  
  8.     cs->str[cs->len] = '\0';  

在頭部插入字符: 

  1. void c_string_front_char(c_string_t *cs, char c) {  
  2.     if (cs == NULL) return;  
  3.     c_string_ensure_space(cs, 1);  
  4.     memmove(cs->str + 1, cs->str, cs->len);  
  5.     cs->str[0] = c;  
  6.     cs->len++;  
  7.     cs->str[cs->len] = '\0';  

在頭部插入整數(shù): 

  1. void c_string_front_int(c_string_t *cs, int val) {  
  2.     char str[12];  
  3.     if (cs == NULL) return;  
  4.     snprintf(str, sizeof(str), "%d", val);  
  5.     c_string_front_str(cs, str, 0);  

清空字符串: 

  1. void c_string_clear(c_string_t *cs) {  
  2.     if (cs == NULL) return;  
  3.     c_string_truncate(cs, 0);  

裁剪字符串: 

  1. void c_string_truncate(c_string_t *cs, size_t len) {  
  2.     if (cs == NULL || len >= cs->len) return;  
  3.     cs->lenlen = len;  
  4.     cs->str[cs->len] = '\0';  

刪除頭部的N個字符: 

  1. void c_string_drop_begin(c_string_t *cs, size_t len) {  
  2.     if (cs == NULL || len == 0) return;  
  3.     if (len >= cs->len) {  
  4.         c_string_clear(cs);  
  5.         return;  
  6.     }  
  7.     cs->len -len 
  8.     memmove(cs->str, cs->str + len, cs->len + 1);  

刪除尾部的N個字符: 

  1. void c_string_drop_end(c_string_t *cs, size_t len) {  
  2.     if (cs == NULL || len == 0) return;  
  3.     if (len >= cs->len) {  
  4.         c_string_clear(cs);  
  5.         return;  
  6.     }  
  7.     cs->len -len 
  8.     cs->str[cs->len] = '\0';  

獲取字符串的長度: 

  1. size_t c_string_len(const c_string_t *cs) {  
  2.     if (cs == NULL) return 0;  
  3.     return cs->len;  

返回字符串指針,使用的是內(nèi)部的內(nèi)存: 

  1. const char *c_string_peek(const c_string_t *cs) {  
  2.     if (cs == NULL) return NULL;  
  3.     return cs->str;  

重新分配一塊內(nèi)存存儲字符串返回: 

  1. char *c_string_dump(const c_string_t *cs, size_t *len) {  
  2.     char *out;  
  3.     if (cs == NULL) return NULL;  
  4.     if (len != NULL) *len = cs->len;  
  5.     out = malloc(cs->len + 1);  
  6.     memcpy(out, cs->str, cs->len + 1);  
  7.     return out; 
  8.  }

測試代碼如下: 

  1. int main() {  
  2.     c_string_t *cs = c_string_create();  
  3.     c_string_append_str(cs, "123", 0);  
  4.     c_string_append_char(cs, '4');  
  5.     c_string_append_int(cs, 5);  
  6.     printf("%s \n", c_string_peek(cs));  
  7.     c_string_front_str(cs, "789", 0);  
  8.     printf("%s \n", c_string_peek(cs));  
  9.     c_string_drop_begin(cs, 2);  
  10.     printf("%s \n", c_string_peek(cs));  
  11.     c_string_drop_end(cs, 2);  
  12.     printf("%s \n", c_string_peek(cs));  
  13.     c_string_destroy(cs);  
  14.     return 0;  

輸出: 

  1. 12345  
  2. 78912345  
  3. 912345  
  4. 9123 

完整代碼如下:頭文件: 

  1. #include <stddef.h>  
  2. struct c_string;  
  3. typedef struct c_string c_string_t;  
  4. c_string_t *c_string_create(void);  
  5. void c_string_destroy(c_string_t *cs);  
  6. void c_string_append_str(c_string_t *cs, const char *str, size_t len);  
  7. void c_string_append_char(c_string_t *cs, char c);  
  8. void c_string_append_int(c_string_t *cs, int val);  
  9. void c_string_front_str(c_string_t *cs, const char *str, size_t len);  
  10. void c_string_front_char(c_string_t *cs, char c);  
  11. void c_string_front_int(c_string_t *cs, int val);  
  12. void c_string_clear(c_string_t *cs);  
  13. void c_string_truncate(c_string_t *cs, size_t len);  
  14. void c_string_drop_begin(c_string_t *cs, size_t len);  
  15. void c_string_drop_end(c_string_t *cs, size_t len); 
  16. size_t c_string_len(const c_string_t *cs);  
  17. const char *c_string_peek(const c_string_t *cs);  
  18. char *c_string_dump(const c_string_t *cs, size_t *len); 

源文件: 

  1. #include <ctype.h>  
  2. #include <stdbool.h>  
  3. #include <stdlib.h>  
  4. #include <stdio.h>  
  5. #include <string.h>  
  6. static const size_t c_string_min_size = 32
  7. struct c_string {  
  8.     char *str;  
  9.     size_t alloced;  
  10.     size_t len; 
  11. };  
  12. c_string_t *c_string_create(void) {  
  13.     c_string_t *cs;  
  14.     cs = calloc(1, sizeof(*cs));  
  15.     cs->str = malloc(c_string_min_size);  
  16.     *cs->str = '\0' 
  17.     cs->alloced = c_string_min_size 
  18.     cs->len = 0 
  19.     return cs;  
  20.  
  21. void c_string_destroy(c_string_t *cs) {  
  22.     if (cs == NULL) return;  
  23.     free(cs->str);  
  24.     free(cs);  
  25.  
  26. static void c_string_ensure_space(c_string_t *cs, size_t add_len) {  
  27.     if (cs == NULL || add_len == 0) return;  
  28.     if (cs->alloced >= cs->len + add_len + 1) return;  
  29.     while (cs->alloced < cs->len + add_len + 1) {  
  30.         cs->alloced <<= 1;  
  31.         if (cs->alloced == 0) {  
  32.             cs->alloced--;  
  33.         }  
  34.     }  
  35.     cs->str = realloc(cs->str, cs->alloced);  
  36.  
  37. void c_string_append_str(c_string_t *cs, const char *str, size_t len) {  
  38.     if (cs == NULL || str == NULL || *str == '\0') return;  
  39.     if (len == 0) len = strlen(str);  
  40.     c_string_ensure_space(cs, len);  
  41.     memmove(cs->str + cs->len, str, len);  
  42.     cs->len += len;  
  43.     cs->str[cs->len] = '\0';  
  44.  
  45. void c_string_append_char(c_string_t *cs, char c) {  
  46.     if (cs == NULL) return;  
  47.     c_string_ensure_space(cs, 1);  
  48.     cs->str[cs->len] = c;  
  49.     cs->len++;  
  50.     cs->str[cs->len] = '\0';  
  51.  
  52. void c_string_append_int(c_string_t *cs, int val) { 
  53.     char str[12];  
  54.     if (cs == NULL) return;  
  55.     snprintf(str, sizeof(str), "%d", val);  
  56.     c_string_append_str(cs, str, 0);  
  57.  
  58. void c_string_front_str(c_string_t *cs, const char *str, size_t len) {  
  59.     if (cs == NULL || str == NULL || *str == '\0') return;  
  60.     if (len == 0) len = strlen(str);  
  61.     c_string_ensure_space(cs, len);  
  62.     memmove(cs->str + len, cs->str, cs->len);  
  63.     memmove(cs->str, str, len);  
  64.     cs->len += len;  
  65.     cs->str[cs->len] = '\0';  
  66.  
  67. void c_string_front_char(c_string_t *cs, char c) {  
  68.     if (cs == NULL) return;  
  69.     c_string_ensure_space(cs, 1);  
  70.     memmove(cs->str + 1, cs->str, cs->len);  
  71.     cs->str[0] = c;  
  72.     cs->len++;  
  73.     cs->str[cs->len] = '\0';  
  74.  
  75. void c_string_front_int(c_string_t *cs, int val) {  
  76.     char str[12]; 
  77.     if (cs == NULL) return;  
  78.     snprintf(str, sizeof(str), "%d", val);  
  79.     c_string_front_str(cs, str, 0);  
  80.  
  81. void c_string_clear(c_string_t *cs) {  
  82.     if (cs == NULL) return;  
  83.     c_string_truncate(cs, 0);  
  84.  
  85. void c_string_truncate(c_string_t *cs, size_t len) {  
  86.     if (cs == NULL || len >= cs->len) return;  
  87.     cs->lenlen = len;  
  88.     cs->str[cs->len] = '\0';  
  89.  
  90. void c_string_drop_begin(c_string_t *cs, size_t len) {  
  91.     if (cs == NULL || len == 0) return;  
  92.     if (len >= cs->len) {  
  93.         c_string_clear(cs);  
  94.         return;  
  95.     }  
  96.     cs->len -len 
  97.     /* +1 to move the NULL. */  
  98.     memmove(cs->str, cs->str + len, cs->len + 1);  
  99.  
  100. void c_string_drop_end(c_string_t *cs, size_t len) {  
  101.     if (cs == NULL || len == 0) return;   
  102.     if (len >= cs->len) {  
  103.         c_string_clear(cs);  
  104.         return;  
  105.     }  
  106.     cs->len -len 
  107.     cs->str[cs->len] = '\0';  
  108.  
  109. size_t c_string_len(const c_string_t *cs) {  
  110.     if (cs == NULL) return 0;  
  111.     return cs->len;  
  112.  
  113. const char *c_string_peek(const c_string_t *cs) {  
  114.     if (cs == NULL) return NULL;  
  115.     return cs->str;  
  116.  
  117. char *c_string_dump(const c_string_t *cs, size_t *len) {  
  118.     char *out;  
  119.     if (cs == NULL) return NULL;  
  120.     if (len != NULL) *len = cs->len;  
  121.     out = malloc(cs->len + 1);  
  122.     memcpy(out, cs->str, cs->len + 1);  
  123.     return out;  
  124.  

 

責任編輯:龐桂玉 來源: C語言與C++編程
相關推薦

2020-10-23 06:56:00

C語言動態(tài)字符串

2023-04-03 08:02:16

切片擴容GO

2022-10-21 09:01:41

StudentC++類型

2010-03-11 19:16:32

Python語言

2020-08-26 14:00:37

C++string語言

2022-01-13 10:30:21

C語言內(nèi)存動態(tài)

2023-10-26 11:03:50

C語言宏定義

2011-07-05 17:07:14

C語言

2010-07-07 11:09:36

UDPClient

2021-05-10 20:58:11

數(shù)據(jù)庫擴容用戶

2010-01-14 17:58:41

C++語言

2014-08-05 13:09:34

Objective-C動態(tài)特性

2010-01-04 19:14:46

Silverlight

2024-08-13 09:16:30

2010-12-01 15:28:19

ProbeVueJava

2010-01-28 15:31:34

學習C++語言

2020-06-19 12:59:33

動態(tài)腳本Java

2009-08-28 16:14:26

C#實現(xiàn)加載動態(tài)庫

2022-09-02 17:07:46

C語言main()

2021-06-26 07:29:42

RedisHashtable數(shù)據(jù)
點贊
收藏

51CTO技術棧公眾號