C语言如何实现动态扩容的string?_c++ string 扩容

文章详细介绍了如何用C语言实现一个可动态扩展的字符串类c_string,包括创建、销毁、追加字符串/字符、插入、清空、裁剪以及获取长度等操作。
摘要由CSDN通过智能技术生成

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

输出:

12345
78912345
912345
9123

完整代码如下:头文件:

#include <stddef.h>

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 <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

img-Mrv23iuN-1712864659091)]
[外链图片转存中…(img-RQl9b6s3-1712864659091)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-kKRQZOCj-1712864659092)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值