0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

Wildesbeast 来源:网络整理 作者:佚名 2020-10-25 10:59 次阅读

众所周知,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 = ‘’; // 初始分配内存大小是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 《 cs-》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 == ‘’) 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] = ‘’;}

在尾部追加字符:

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] = ‘’;}

在尾部追加整数:

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 == ‘’) 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] = ‘’;}

在头部插入字符:

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] = ‘’;}

在头部插入整数:

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] = ‘’;}

删除头部的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] = ‘’;}

获取字符串的长度:

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 ”, c_string_peek(cs)); c_string_front_str(cs, “789”, 0); printf(“%s ”, c_string_peek(cs)); c_string_drop_begin(cs, 2); printf(“%s ”, c_string_peek(cs)); c_string_drop_end(cs, 2); printf(“%s ”, c_string_peek(cs)); c_string_destroy(cs); return 0;}

输出:

12345789123459123459123

完整代码如下:头文件:

#include struct 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 #include 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 = ‘’; 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 《 cs-》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 == ‘’) 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] = ‘’;}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] = ‘’;}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 == ‘’) 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] = ‘’;}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] = ‘’;}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] = ‘’;}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] = ‘’;}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;

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7511

    浏览量

    124043
  • 字符
    +关注

    关注

    0

    文章

    229

    浏览量

    24868
  • C++
    C++
    +关注

    关注

    21

    文章

    2061

    浏览量

    72846
收藏 人收藏

    评论

    相关推荐

    C语言实现数字信号处理算法

    C语言实现数字信号处理算法
    发表于 08-16 23:17

    CRC算法和c语言实现

    CRC算法和c语言实现
    发表于 08-20 19:21

    凹槽凸轮轮廓线的解析设计及C语言实现

    凹槽凸轮轮廓线的解析设计及C语言实现
    发表于 06-04 10:44

    C语言实现FFT(快速傅里叶变换)

    C语言实现FFT(快速傅里叶变换)
    发表于 10-25 21:33

    C++语言实现火车排序功能.doc

    C++语言实现火车排序功能.doc
    发表于 08-05 22:01

    如何用C语言实现OOP编程?

    老大看到OOP编程很好,就让我学,怎么用C语言实现OOP编程的,请大侠指点
    发表于 10-30 03:45

    PID控制算法的C语言实现(完整版)

    PID控制算法的C语言实现(完整版)
    发表于 02-06 17:08

    PID控制算法的C语言实现(完整版)

    PID控制算法的C语言实现(完整版)
    发表于 04-02 11:39

    PID控制算法的C语言实现(完整版)

    PID控制算法的C语言实现(完整版)
    发表于 05-01 11:03

    如何用C语言实现面向对象编程

    1 用C语言实现面向对象编程GOF的《设计模式》一书的副标题叫做“可复用面向对象软件的基础”,从标题就能看出面向对象是设计模式基本思想。由于C语言并不是面向对象的
    发表于 07-12 07:24

    基于Proteus和C语言实现

    基于Proteus和C语言实现一共四个题目,有没有人愿意尝试一下?
    发表于 07-14 06:20

    如何使用C语言实现模糊PID控制?

    如何使用C语言实现模糊PID控制?
    发表于 09-24 08:54

    C语言实现常用排序算法是什么?

    C语言实现常用排序算法是什么?
    发表于 10-19 06:41

    小白求助,求基于Proteus和C语言实现的程序和仿真

    小白求助,求基于Proteus和C语言实现的程序和仿真
    发表于 10-19 06:20

    如何利用c语言实现中文“大”字的显示?

    如何利用c语言实现中文“大”字的显示?
    发表于 11-02 06:25