设计一个C语言的动态扩容缓冲区
struct strbuf {
int len; //当前缓冲区(字符串)长度
int alloc; //当前缓冲区(字符串)容量
char *buf; //缓冲区(字符串)
}
#include "strbuf.h"
/*struct strbuf {
int len; //当前缓冲区(字符串)长度
int alloc; //当前缓冲区(字符串)容量
char *buf; //缓冲区(字符串)
};*/
//初始化sb结构体,容量为alloc
void strbuf_init(struct strbuf* sb, size_t alloc)
{
sb->len = 0;
sb->alloc = alloc;
sb->buf = (char*)malloc(sizeof(char) * alloc);
}
//将字符串填充到sb中,长度为len,容量为alloc
void strbuf_attach(struct strbuf* sb, void* str, size_t len, size_t alloc)
{
sb->len = len;
sb->alloc = alloc;
sb->buf = (char*)str;
}
//释放sb结构体的内存
void strbuf_release(struct strbuf* sb)
{
free(sb->buf);
sb->buf = NULL;
}
//交换两个strbuf
void strbuf_swap(struct strbuf* a, struct strbuf* b)
{
int t1, t2;
char* t3;
t1 = a->len;
a->len = b->len;
b->len = t1;
t2 = a->alloc;
a->alloc = b->alloc;
b->alloc = t2;
t3 = a->buf;
a->buf = b->buf;
b->buf = t3;
}
//将sb中的原始内存取出,并将sz设置为其alloc大小
char* strbuf_detach(struct strbuf* sb, size_t* sz)
{
*sz = sb->alloc;
char* p;
p = sb->buf;
return p;
}
//比较两个strbuf的内存是否相同
int strbuf_cmp(const struct strbuf* first, const struct strbuf* second)
{
if (first->len > second->len || first->len < second->len)
return 1;
else
return 0;
}
//清空sb
void strbuf_reset(struct strbuf* sb)
{
int i;
for (i = 0; i < sb->len; i++)
{
*((sb->buf) + i) = '\0';
}
sb->len = 0;
}
//part 2B
//确保在len之后strbuf中至少有extra个空字节的空闲空间可用
void strbuf_grow(struct strbuf* sb, size_t extra)
{
sb->buf = (char*)realloc(sb->buf, sb->len + extra);
sb->alloc = sb->len + extra;
}
//向sb追加长度为len的数据data
void strbuf_add(struct strbuf* sb, const void* data, size_t len)
{
if (sb->len + len > sb->alloc)
{
strbuf_grow(sb, len + 1);
}
for (int i = 0; i < len; i++)
{
*(sb->buf + (sb->len + i)) = *((char*)data + i);
}
sb->len += len;
*(sb->buf + (sb->len)) = '\0';
}
//向sb追加一个字符c
void strbuf_addch(struct strbuf* sb, int c)
{
if (sb->len + 2 > sb->alloc)
{
strbuf_grow(sb, 2);
}
sb->len += 1;
*(sb->buf + (sb->len - 1)) = c;
*(sb->buf + (sb->len)) = '\0';
}
//向sb追加一个字符串s
void strbuf_addstr(struct strbuf* sb, const char* s)
{
int a = strlen(s);
if (s == NULL)
{
return;
}
if (sb->len + a >= sb->alloc)
{
strbuf_grow(sb, a + 1);
}
memcpy(sb->buf + sb->len, s, a);//memcpy(目标空间地址,传递数据地址,拷贝数据的字节数)拷贝数据到目标地址
sb->len += a;
sb->buf[sb->len] = '\0';
}
//向一个sb追加另一个strbuf的数据
void strbuf_addbuf(struct strbuf* sb, const struct strbuf* sb2)
{
strbuf_add(sb, sb2->buf, sb2->len);
}
//设置sb的长度len
void strbuf_setlen(struct strbuf* sb, size_t len)
{
sb->len = len;
sb->buf[sb->len] = '\0';
}
//计算sb仍可以向后追加的字符串长度
size_t strbuf_avail(const struct strbuf* sb)
{
return sb->alloc - sb->len - 1;
}
//向sb内存坐标为pos位置插入长度为len的数据data
void strbuf_insert(struct strbuf* sb, size_t pos, const void* data, size_t len)
{
int new_len = len + sb->len;
int new_alloc = sb->alloc;
if (new_alloc < sizeof(char) * new_len)
{
strbuf_grow(sb, sizeof(char*) * len);
}
for (int i = sb->len; i >= pos; i--)
{
sb->buf[i + len] = sb->buf[i];
}
for (int k = pos, j = 0; j < len; k++, j++)
{
sb->buf[k] = *((char*)data + j);
}
sb->len = new_len;
}
//Part 2C
//去除sb缓冲区左端的所有空格,tab,'\t'
void strbuf_ltrim(struct strbuf* sb)
{
for (int i = sb->len; i > 0; i--)
if (sb->buf[0] == ' ' || sb->buf[0] == '\t')
{
memmove(sb->buf, sb->buf + 1, sb->len - 1);//memmove(目标地址,源地址,要拷贝的内容大小)移动内存块
sb->len--;
}
}
//去除sb缓存区右端的所有空格,tab,'\t'
void strbuf_rtrim(struct strbuf* sb)
{
for (int i = sb->len; i > 0; i--)
if (*(sb->buf + (sb->len - 1)) == ' ' || *(sb->buf + (sb->len - 1)) == '\t')
{
*(sb->buf + (sb->len - 1)) = '\0';
sb->len--;
}
}
//删除sb缓冲区从pos坐标长度为len的内容
void strbuf_remove(struct strbuf* sb, size_t pos, size_t len)
{
memmove(sb->buf + pos, sb->buf + pos + len, sb->len - pos - len);
sb->len -= len;
}
//PART 2D
//sb增长hint?hint:8192大小,然后将文件描述符为fd的所有文件内容追加到sb中
ssize_t strbuf_read(struct strbuf* sb, int fd, size_t hint)
{
char c;
FILE* pf = fdopen(fd, "r");
int k = 0;
sb->buf = (char*)realloc(sb->buf, sizeof(char) * (sb->alloc += (hint ? hint : 8192)));
sb->alloc += (hint ? hint : 8192);
while ((c = fgetc(pf)) != -1)
{
sb->buf[sb->len++] = c;
k++;
}
if (k != 0)
sb->buf[sb->len] = '\0';
return 1;
}
//将文件句柄为fp的一行内容(抛弃换行符)读取到sb
int strbuf_getline(struct strbuf* sb, FILE* fp)
{
char c;
int k = 0;
while ((c = fgetc(fp)) != EOF)
{
if (c == '\n' || feof(fp) != 0)
break;
strbuf_grow(sb, 2);
sb->buf[sb->len] = c;
sb->len++;
k++;
}
if (k != 0)
*(sb->buf + (sb->len)) = '\0';
return 0;
}
//challenge
//实现判断一个strbuf是否以指定字符串开头的功能
bool strbuf_begin_judge(char* target_str, const char* str, int strnlen)
{
if (strnlen == 0)
return true;
int len = strlen(str);
int i = memcmp(target_str, str, len);
if (i == 0)
return true;
else
return false;
}
//获取字符串从坐标[begin,end)的所有内容
char* strbuf_get_mid_buf(char* target_buf, int begin, int end, int len)
{
if (len <= 0)
return NULL;
int lang = end - begin;
char* p = (char*)malloc(sizeof(char) * (lang + 1));
memcpy(p, target_buf + begin, lang + 1);//memcpy(目标地址,源地址,数据长度)用于内存复制函数
p[lang] = '\0';
return p;
}
//实现字符串的切割
struct strbuf** strbuf_split_buf(const char* str, size_t len, int terminator, int max)
{
if (str == NULL)
return 0;
char s[2] = { 0 };
s[0] = (char)terminator;
s[1] = '\0';
int k = 0;
struct strbuf** p = NULL;
p = (struct strbuf**)realloc(p, sizeof(struct strbuf*) * (k + 1));
char* temp = (char*)malloc(sizeof(char) * (len + 1));
memcpy(temp, str, len + 1);
for (int i = 0; i < len; i++)
{
if (temp[i] == '\0')
temp[i] = '?';
}
char* arr = strtok(temp, s);//strtok(被分解的字符串,分隔符)字符分割函数
while (arr != NULL && k < max)
{
int lang = strlen(arr);
for (int i = 0; i < lang; i++)
{
if (arr[i] == '?')
arr[i] = '\0';
}
struct strbuf* ps = (struct strbuf*)malloc(sizeof(struct strbuf));
strbuf_init(ps, lang + 1);
strbuf_add(ps, arr, lang);
p = (struct strbuf**)realloc(p, sizeof(struct strbuf*) * (k + 2));
p[k++] = ps;
arr = strtok(NULL, s);
p = (struct strbuf**)realloc(p, sizeof(struct strbuf*) * (k + 2));
}
free(temp);
p[k] = NULL;
return p;
}