利用C语言如何实现string,C语言如何实现动态扩容的string

又好久没更新了,最近程序喵工作实在是太忙,业余时间也在学习新知识酝酿大招,便于后期更新好文,最近先水几篇吧,大家有想了解的知识点可以在文末读者讨论中留言哈!

众所周知,C++ 中的string使用比较方便,关于C++ 中的string源码实现可以看我的这篇文章:源码分析C++的string的实现最近工作中使用C语言,但又苦于没有高效的字符串实现,字符串的拼接和裁剪都比较麻烦,而且每个字符串都需要申请内存,内存的申请和释放也很容易出bug,怎么高效的实现一个不需要处理内存问题并且可以动态扩容进行拼接和裁剪的string呢?

一个好的string应该有以下功能?

创建字符串

删除字符串

尾部追加字符串

头部插入字符串

从尾部删除N个字符

从头部删除N个字符

裁剪字符串

获取字符串长度

获取完整字符串

下面来看看各个功能的实现:首先定义一个string的句柄,相当于C++中的实例

struct c_string;typedef struct c_string c_string_t;

在内部string的实现如下:

// string的初始内存大小static const size_t c_string_min_size = 32;struct c_string {    char *str; // 字符串指针    size_t alloced; // 已分配的内存大小    size_t len; // 字符串的实际长度};

创建字符串:

c_string_t *c_string_create(void) {    c_string_t *cs;    cs = calloc(1, sizeof(*cs));    cs->str = malloc(c_string_min_size);    *cs->str = '\0';    // 初始分配内存大小是32,之后每次以2倍大小扩容    cs->alloced = c_string_min_size;     cs->len = 0;    return cs;}

销毁字符串:

void c_string_destroy(c_string_t *cs) {    if (cs == NULL) return;    free(cs->str);    free(cs);}

内部如何扩容呢:

static void c_string_ensure_space(c_string_t *cs, size_t add_len) {    if (cs == NULL || add_len == 0) return;    if (cs->alloced >= cs->len + add_len + 1) return;    while (cs->alloced len + add_len + 1) {        cs->alloced <<= 1; // 每次以2倍大小扩容        if (cs->alloced == 0) {            // 左移到最后可能会变为0,由于alloced是无符号型,减一则会变成UINT_MAX            cs->alloced--;        }    }    cs->str = realloc(cs->str, cs->alloced);}

在尾部追加字符串:

void c_string_append_str(c_string_t *cs, const char *str, size_t len) {    if (cs == NULL || str == NULL || *str == '\0') return;    if (len == 0) len = strlen(str);    c_string_ensure_space(cs, len); // 确保内部有足够的空间存储字符串    memmove(cs->str + cs->len, str, len);    cs->len += len;    cs->str[cs->len] = '\0';}

在尾部追加字符:

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

在尾部追加整数:

void c_string_append_int(c_string_t *cs, int val) {    char str[12];    if (cs == NULL) return;    snprintf(str, sizeof(str), "%d", val); // 整数转为字符串    c_string_append_str(cs, str, 0);}

在头部插入字符串:

void c_string_front_str(c_string_t *cs, const char *str, size_t len) {    if (cs == NULL || str == NULL || *str == '\0') return;    if (len == 0) len = strlen(str);    c_string_ensure_space(cs, len);    memmove(cs->str + len, cs->str, cs->len);    memmove(cs->str, str, len);    cs->len += len;    cs->str[cs->len] = '\0';}

在头部插入字符:

void c_string_front_char(c_string_t *cs, char c) {    if (cs == NULL) return;    c_string_ensure_space(cs, 1);    memmove(cs->str + 1, cs->str, cs->len);    cs->str[0] = c;    cs->len++;    cs->str[cs->len] = '\0';}

在头部插入整数:

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

清空字符串:

void c_string_clear(c_string_t *cs) {    if (cs == NULL) return;    c_string_truncate(cs, 0);}

裁剪字符串:

void c_string_truncate(c_string_t *cs, size_t len) {    if (cs == NULL || len >= cs->len) return;    cs->len = len;    cs->str[cs->len] = '\0';}

删除头部的N个字符:

void c_string_drop_begin(c_string_t *cs, size_t len) {    if (cs == NULL || len == 0) return;    if (len >= cs->len) {        c_string_clear(cs);        return;    }    cs->len -= len;    memmove(cs->str, cs->str + len, cs->len + 1);}

删除尾部的N个字符:

void c_string_drop_end(c_string_t *cs, size_t len) {    if (cs == NULL || len == 0) return;    if (len >= cs->len) {        c_string_clear(cs);        return;    }    cs->len -= len;    cs->str[cs->len] = '\0';}

获取字符串的长度:

size_t c_string_len(const c_string_t *cs) {    if (cs == NULL) return 0;    return cs->len;}

返回字符串指针,使用的是内部的内存:

const char *c_string_peek(const c_string_t *cs) {    if (cs == NULL) return NULL;    return cs->str;}

重新分配一块内存存储字符串返回:

char *c_string_dump(const c_string_t *cs, size_t *len) {    char *out;    if (cs == NULL) return NULL;    if (len != NULL) *len = cs->len;    out = malloc(cs->len + 1);    memcpy(out, cs->str, cs->len + 1);    return out;}

测试代码如下:

int main() {    c_string_t *cs = c_string_create();    c_string_append_str(cs, "123", 0);    c_string_append_char(cs, '4');    c_string_append_int(cs, 5);    printf("%s \n", c_string_peek(cs));    c_string_front_str(cs, "789", 0);    printf("%s \n", c_string_peek(cs));    c_string_drop_begin(cs, 2);    printf("%s \n", c_string_peek(cs));    c_string_drop_end(cs, 2);    printf("%s \n", c_string_peek(cs));    c_string_destroy(cs);    return 0;}

输出:

12345789123459123459123

完整代码如下:头文件:

#includestruct c_string;typedef struct c_string c_string_t;c_string_t *c_string_create(void);void c_string_destroy(c_string_t *cs);void c_string_append_str(c_string_t *cs, const char *str, size_t len);void c_string_append_char(c_string_t *cs, char c);void c_string_append_int(c_string_t *cs, int val);void c_string_front_str(c_string_t *cs, const char *str, size_t len);void c_string_front_char(c_string_t *cs, char c);void c_string_front_int(c_string_t *cs, int val);void c_string_clear(c_string_t *cs);void c_string_truncate(c_string_t *cs, size_t len);void c_string_drop_begin(c_string_t *cs, size_t len);void c_string_drop_end(c_string_t *cs, size_t len);size_t c_string_len(const c_string_t *cs);const char *c_string_peek(const c_string_t *cs);char *c_string_dump(const c_string_t *cs, size_t *len);

源文件:

#include#include#include#include#includestatic const size_t c_string_min_size = 32;struct c_string {    char *str;    size_t alloced;    size_t len;};c_string_t *c_string_create(void) {    c_string_t *cs;    cs = calloc(1, sizeof(*cs));    cs->str = malloc(c_string_min_size);    *cs->str = '\0';    cs->alloced = c_string_min_size;    cs->len = 0;    return cs;}void c_string_destroy(c_string_t *cs) {    if (cs == NULL) return;    free(cs->str);    free(cs);}static void c_string_ensure_space(c_string_t *cs, size_t add_len) {    if (cs == NULL || add_len == 0) return;    if (cs->alloced >= cs->len + add_len + 1) return;    while (cs->alloced len + add_len + 1) {        cs->alloced <<= 1;        if (cs->alloced == 0) {            cs->alloced--;        }    }    cs->str = realloc(cs->str, cs->alloced);}void c_string_append_str(c_string_t *cs, const char *str, size_t len) {    if (cs == NULL || str == NULL || *str == '\0') return;    if (len == 0) len = strlen(str);    c_string_ensure_space(cs, len);    memmove(cs->str + cs->len, str, len);    cs->len += len;    cs->str[cs->len] = '\0';}void c_string_append_char(c_string_t *cs, char c) {    if (cs == NULL) return;    c_string_ensure_space(cs, 1);    cs->str[cs->len] = c;    cs->len++;    cs->str[cs->len] = '\0';}void c_string_append_int(c_string_t *cs, int val) {    char str[12];    if (cs == NULL) return;    snprintf(str, sizeof(str), "%d", val);    c_string_append_str(cs, str, 0);}void c_string_front_str(c_string_t *cs, const char *str, size_t len) {    if (cs == NULL || str == NULL || *str == '\0') return;    if (len == 0) len = strlen(str);    c_string_ensure_space(cs, len);    memmove(cs->str + len, cs->str, cs->len);    memmove(cs->str, str, len);    cs->len += len;    cs->str[cs->len] = '\0';}void c_string_front_char(c_string_t *cs, char c) {    if (cs == NULL) return;    c_string_ensure_space(cs, 1);    memmove(cs->str + 1, cs->str, cs->len);    cs->str[0] = c;    cs->len++;    cs->str[cs->len] = '\0';}void c_string_front_int(c_string_t *cs, int val) {    char str[12];    if (cs == NULL) return;    snprintf(str, sizeof(str), "%d", val);    c_string_front_str(cs, str, 0);}void c_string_clear(c_string_t *cs) {    if (cs == NULL) return;    c_string_truncate(cs, 0);}void c_string_truncate(c_string_t *cs, size_t len) {    if (cs == NULL || len >= cs->len) return;    cs->len = len;    cs->str[cs->len] = '\0';}void c_string_drop_begin(c_string_t *cs, size_t len) {    if (cs == NULL || len == 0) return;    if (len >= cs->len) {        c_string_clear(cs);        return;    }    cs->len -= len;    /* +1 to move the NULL. */    memmove(cs->str, cs->str + len, cs->len + 1);}void c_string_drop_end(c_string_t *cs, size_t len) {    if (cs == NULL || len == 0) return;    if (len >= cs->len) {        c_string_clear(cs);        return;    }    cs->len -= len;    cs->str[cs->len] = '\0';}size_t c_string_len(const c_string_t *cs) {    if (cs == NULL) return 0;    return cs->len;}const char *c_string_peek(const c_string_t *cs) {    if (cs == NULL) return NULL;    return cs->str;}char *c_string_dump(const c_string_t *cs, size_t *len) {    char *out;    if (cs == NULL) return NULL;    if (len != NULL) *len = cs->len;    out = malloc(cs->len + 1);    memcpy(out, cs->str, cs->len + 1);    return out;}

往期推荐

FrcD6d5NkDZimOUPshaGRHXopBWHoK2cATPNq4OKfP+x5HMJAhACykzOizt5K68+R1NhSzjF838J+4XClPht6awmiKtHtOg

n33vZSq4WvlI2GOW+DUR1F9oME7Mw

VYr236asTuJI+IAg

lO25BOVigcBP2MmG7AxMlbZo+n4eOWNFqohRS76hgwixH61u3rWgG2bXR+ccSUjZgFU7QYi8XL8b0wikg1i3ljkJSJC4sGgN0vwteqq93kHcCi6rhuWDp0OY7VN8LmnouN6xMEntAx4dZ2cd5Ncp6C+ch+KRfenLTIYQNJpD2h0tbUuUyXa3UNqlYHOl6NwsSCU3vLw

nD60j5GSrngMHEzwbGUwHgAfJaaQD4vQkZmakrMglnVTQzhvf1XWAgGwshA18mD+Pz1Ul3shHgu+jHXqNSzf

r

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值