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

    文章

    7604

    浏览量

    136713
  • 字符
    +关注

    关注

    0

    文章

    233

    浏览量

    25199
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73627
收藏 人收藏

    评论

    相关推荐

    基于Proteus和C语言实现

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

    C语言实现FFT算法

    C语言实现FFT算法 /*****************fft programe*********************/#include "typedef.h" #include "math.h" struct compx EE(struct compx
    发表于 10-30 13:39 6341次阅读

    DSP算法的c语言实现

    DSP算法的c语言实现,又需要的朋友下来看看。
    发表于 05-09 10:59 0次下载

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

    PID控制算法的C语言实现一 PID算法原理
    发表于 11-05 15:45 0次下载

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

    C++语言实现火车排序功能
    发表于 01-05 11:27 2次下载

    4个重要算法C语言实现源代码

    4个重要算法C语言实现源代码
    发表于 06-10 08:00 12次下载

    使用C语言实现静态网页的代码免费下载

    本文档的主要内容详细介绍的是使用C语言实现静态网页的代码免费下载。
    发表于 11-22 16:20 2次下载

    使用单片机实现8位数码管动态扫描显示的C语言实例免费下载

    本文档的主要内容详细介绍的是使用单片机实现8位数码管动态扫描显示的C语言实例免费下载。
    发表于 11-12 17:33 13次下载
    使用单片机<b class='flag-5'>实现</b>8位数码管<b class='flag-5'>动态</b>扫描显示的<b class='flag-5'>C</b><b class='flag-5'>语言实</b>例免费下载

    使用单片机实现数码管显示动态数据的C语言实例免费下载

    本文档的主要内容详细介绍的是使用单片机实现数码管显示动态数据的C语言实例免费下载。
    发表于 11-12 17:57 13次下载

    使用单片机实现数码管动态显示的C语言实例免费下载

    本文档的主要内容详细介绍的是使用单片机实现数码管动态显示的C语言实例免费下载。
    发表于 04-02 10:28 24次下载

    CRC校验算法原理及c语言实现

    CRC校验算法原理及c语言实现
    发表于 11-30 10:04 9次下载

    累加校验和C语言实现

    累加校验和C语言实现
    发表于 11-29 18:06 10次下载
    累加校验和<b class='flag-5'>C</b><b class='flag-5'>语言实现</b>

    怎么用C语言实现多态

    这里我想主要介绍下在C语言中是如何实现的面向对象。知道了C语言实现面向对象的方式,我们再联想下,C
    的头像 发表于 10-12 09:12 2044次阅读

    C语言实现Web参数传递

    电子发烧友网站提供《C语言实现Web参数传递.docx》资料免费下载
    发表于 03-24 09:14 2次下载

    使用C语言实现的CRC计算单元的例子

    使用C语言实现的CRC计算单元的例子
    的头像 发表于 05-16 16:16 963次阅读