[{"data":1,"prerenderedAt":1059},["ShallowReactive",2],{"content:\u002F2023\u002Fc-strbuf":3,"surround:\u002F2023\u002Fc-strbuf":1048},{"id":4,"title":5,"body":6,"categories":1019,"date":1021,"description":1022,"draft":1023,"extension":1024,"image":1025,"meta":1026,"navigation":1028,"path":1029,"permalink":1030,"published":1030,"readingTime":1031,"recommend":1030,"references":1036,"seo":1039,"sitemap":1040,"stem":1041,"tags":1042,"type":1045,"updated":1046,"__hash__":1047},"content\u002Fposts\u002F2023\u002Fc-strbuf.md","简单实现C语言字符串缓冲区",{"type":7,"value":8,"toc":979},"minimark",[9,14,107,112,121,129,142,145,151,158,174,181,187,194,203,206,212,219,227,230,236,243,261,268,274,281,290,308,314,321,329,332,338,342,350,357,375,378,384,391,408,414,420,427,438,441,447,454,466,473,479,486,499,502,505,511,517,528,534,537,543,550,559,562,568,575,594,606,612,616,623,636,643,649,656,667,670,673,679,686,703,706,712,716,723,745,771,777,784,797,812,818,822,827,834,862,874,880,883,889,894,901,906,932,938,948,955,960,966,973],[10,11,13],"h2",{"id":12},"设计一个-c-语言的动态扩容缓冲区","设计一个 C 语言的动态扩容缓冲区",[15,16,17,25,30,41,46],"blockquote",{},[18,19,20,24],"p",{},[21,22,23],"strong",{},"知识要点","：字符串、面向对象的 C 语言设计、动态内存分配、Linux File API、getline。",[18,26,27],{},[21,28,29],{},"缓冲区类的定义",[31,32,38],"pre",{"className":33,"code":35,"language":36,"meta":37},[34],"language-c","struct strbuf {\n    int len;     \u002F\u002F当前缓冲区（字符串）长度\n    int alloc;   \u002F\u002F当前缓冲区（字符串）容量\n    char *buf;   \u002F\u002F缓冲区（字符串）\n};\n","c","",[39,40,35],"code",{"__ignoreMap":37},[18,42,43],{},[21,44,45],{},"HINT",[47,48,49,89],"ul",{},[50,51,52,56,57,61,62,66,67,70,71,75,76,79,80,83,84,88],"li",{},[39,53,55],{"className":54,"code":55,"language":36},[34],"strbuf","的成员",[39,58,60],{"className":59,"code":60,"language":36},[34],"len","代表的是",[39,63,65],{"className":64,"code":65,"language":36},[34],"buf","缓冲区的长度，每次我们将字符串追加入",[39,68,55],{"className":69,"code":55,"language":36},[34],"中，我们都应该使用 ",[39,72,74],{"className":73,"code":74,"language":36},[34],"strbuf_setlen()","去更新",[39,77,55],{"className":78,"code":55,"language":36},[34],"的长度",[39,81,60],{"className":82,"code":60,"language":36},[34],"，注意",[39,85,87],{"className":86,"code":87,"language":36},[34],"123\\0456","的长度不是 3，而是 7。",[50,90,91,56,94,61,98,101,102,106],{},[39,92,55],{"className":93,"code":55,"language":36},[34],[39,95,97],{"className":96,"code":97,"language":36},[34],"alloc",[39,99,65],{"className":100,"code":65,"language":36},[34],"缓冲区的容量，也就是我们每次动态分配的数组大小，每当我们需要向",[39,103,105],{"className":104,"code":105,"language":36},[34],"sb","内追加一个字符串，我们需要计算当前的字符串长度加上追加的字符串长度，如果超过了当前的容量，我们就需要把容量扩大一倍，然后将字符串添加进去。",[108,109,111],"h3",{"id":110},"part-2a","Part 2A",[15,113,114],{},[18,115,116,117,120],{},"实现字符串缓冲区类",[39,118,55],{"className":119,"code":55,"language":36},[34],"简单的初始化，填充，释放，交换，比较，清空等操作。",[122,123,125],"h4",{"id":124},"strbuf_init",[39,126,128],{"className":127,"code":128,"language":36},[34],"strbuf_init()",[15,130,131],{},[18,132,133,134,137,138,141],{},"初始化",[39,135,105],{"className":136,"code":105,"language":36},[34],"结构体，容量为",[39,139,97],{"className":140,"code":97,"language":36},[34],"。",[18,143,144],{},"初始化时要为缓冲区写入容量大小，在内存中申请空间，写入长度大小，并将缓冲区设置为空字符串。",[31,146,149],{"className":147,"code":148,"language":36,"meta":37},[34],"void strbuf_init(struct strbuf *sb, size_t alloc) {\n    sb->alloc = alloc;\n    sb->buf = (char *) malloc(alloc);\n    sb->buf[sb->len = 0] = '\\0';\n}\n",[39,150,148],{"__ignoreMap":37},[122,152,154],{"id":153},"strbuf_attach",[39,155,157],{"className":156,"code":157,"language":36},[34],"strbuf_attach()",[15,159,160],{},[18,161,162,163,166,167,170,171,141],{},"将字符串填充到",[39,164,105],{"className":165,"code":105,"language":36},[34],"中，长度为",[39,168,60],{"className":169,"code":60,"language":36},[34],", 容量为",[39,172,97],{"className":173,"code":97,"language":36},[34],[18,175,176,180],{},[39,177,179],{"className":178,"code":179,"language":36},[34],"字符串","已经有其对应的长度、容量、内容信息，直接将其对应填入缓冲区即可。",[31,182,185],{"className":183,"code":184,"language":36,"meta":37},[34],"void strbuf_attach(struct strbuf *sb, void *str, size_t len, size_t alloc) {\n    sb->len = len;\n    sb->alloc = alloc;\n    sb->buf = (char *) str;\n}\n",[39,186,184],{"__ignoreMap":37},[122,188,190],{"id":189},"strbuf_release",[39,191,193],{"className":192,"code":193,"language":36},[34],"strbuf_release()",[15,195,196],{},[18,197,198,199,202],{},"释放",[39,200,105],{"className":201,"code":105,"language":36},[34],"结构体的内存。",[18,204,205],{},"释放缓冲区内存，将容量大小、长度信息归零，并为缓冲区赋予空指针，防止重复释放内存时报错。",[31,207,210],{"className":208,"code":209,"language":36,"meta":37},[34],"void strbuf_release(struct strbuf *sb) {\n    free(sb->buf);\n    strbuf_attach(sb, NULL, 0, 0);\n}\n",[39,211,209],{"__ignoreMap":37},[122,213,215],{"id":214},"strbuf_swap",[39,216,218],{"className":217,"code":218,"language":36},[34],"strbuf_swap()",[15,220,221],{},[18,222,223,224,141],{},"交换两个",[39,225,55],{"className":226,"code":55,"language":36},[34],[18,228,229],{},"交换时，可以利用结构体浅拷贝特性，通过增加一个临时的缓冲区变量，实现两个缓冲区的交换。",[31,231,234],{"className":232,"code":233,"language":36,"meta":37},[34],"void strbuf_swap(struct strbuf *a, struct strbuf *b) {\n    struct strbuf tmp = *a;\n    *a = *b;\n    *b = tmp;\n}\n",[39,235,233],{"__ignoreMap":37},[122,237,239],{"id":238},"strbuf_detach",[39,240,242],{"className":241,"code":242,"language":36},[34],"strbuf_detach()",[15,244,245],{},[18,246,247,248,251,252,256,257,260],{},"将",[39,249,105],{"className":250,"code":105,"language":36},[34],"中的原始内存取出，并将",[39,253,255],{"className":254,"code":255,"language":36},[34],"sz","设置为其",[39,258,97],{"className":259,"code":97,"language":36},[34],"大小。",[18,262,263,264,267],{},"将缓冲区的容量信息赋给",[39,265,255],{"className":266,"code":255,"language":36},[34],"，并返回缓冲区的指针。",[31,269,272],{"className":270,"code":271,"language":36,"meta":37},[34],"char *strbuf_detach(struct strbuf *sb, size_t *sz) {\n    *sz = sb->alloc;\n    return sb->buf;\n}\n",[39,273,271],{"__ignoreMap":37},[122,275,277],{"id":276},"strbuf_cmp",[39,278,280],{"className":279,"code":280,"language":36},[34],"strbuf_cmp()",[15,282,283],{},[18,284,285,286,289],{},"比较两个",[39,287,55],{"className":288,"code":55,"language":36},[34],"的内存是否相同。",[18,291,292,293,297,298,302,303,307],{},"缓冲区中可能有",[39,294,296],{"className":295,"code":296,"language":36},[34],"'\\0'","存在，所以需要比较长度范围内的所有信息，不能使用",[39,299,301],{"className":300,"code":301,"language":36},[34],"strcmp()","。\n可以先比较长度，如果长度不同则返回长度的差，如果长度相同则使用",[39,304,306],{"className":305,"code":306,"language":36},[34],"memcmp()","比较长度内的信息。",[31,309,312],{"className":310,"code":311,"language":36,"meta":37},[34],"int strbuf_cmp(const struct strbuf *first, const struct strbuf *second) {\n    return first->len - second->len || memcmp(first->buf, second->buf, first->len);\n}\n",[39,313,311],{"__ignoreMap":37},[122,315,317],{"id":316},"strbuf_reset",[39,318,320],{"className":319,"code":320,"language":36},[34],"strbuf_reset()",[15,322,323],{},[18,324,325,326,141],{},"清空",[39,327,105],{"className":328,"code":105,"language":36},[34],[18,330,331],{},"清空缓冲区，则需要将长度归零，并将空字符串填入缓冲区。",[31,333,336],{"className":334,"code":335,"language":36,"meta":37},[34],"void strbuf_reset(struct strbuf *sb) {\n    sb->buf[sb->len = 0] = '\\0';\n}\n",[39,337,335],{"__ignoreMap":37},[108,339,341],{"id":340},"part-2b","Part 2B",[15,343,344],{},[18,345,116,346,349],{},[39,347,55],{"className":348,"code":55,"language":36},[34],"扩容，(追加|插入)字符，字符串等操作。",[122,351,353],{"id":352},"strbuf_grow",[39,354,356],{"className":355,"code":356,"language":36},[34],"strbuf_grow()",[15,358,359],{},[18,360,361,362,365,366,369,370,374],{},"确保在",[39,363,60],{"className":364,"code":60,"language":36},[34],"之后",[39,367,55],{"className":368,"code":55,"language":36},[34],"中至少有",[39,371,373],{"className":372,"code":373,"language":36},[34],"extra","个字节的空闲空间可用。",[18,376,377],{},"先计算可用空间，如果可用空间不足，则重新申请内存，将内存指针赋给缓冲区，并更新容量信息。",[31,379,382],{"className":380,"code":381,"language":36,"meta":37},[34],"void strbuf_grow(struct strbuf *sb, size_t extra) {\n    if (sb->alloc - sb->len \u003C extra)\n        sb->buf = (char *) realloc(sb->buf, sb->alloc += extra);\n}\n",[39,383,381],{"__ignoreMap":37},[122,385,387],{"id":386},"strbuf_add",[39,388,390],{"className":389,"code":390,"language":36},[34],"strbuf_add()",[15,392,393],{},[18,394,395,396,399,400,403,404,141],{},"向",[39,397,105],{"className":398,"code":105,"language":36},[34],"追加长度为",[39,401,60],{"className":402,"code":60,"language":36},[34],"的数据",[39,405,407],{"className":406,"code":407,"language":36},[34],"data",[18,409,410,411,141],{},"追加数据前，先保证容量足够，然后将追加内容拷贝进缓冲区，并更新长度、",[21,412,413],{},"字符串结束标志",[31,415,418],{"className":416,"code":417,"language":36,"meta":37},[34],"void strbuf_add(struct strbuf *sb, const void *data, size_t len) {\n    strbuf_grow(sb, len + 1);\n    memcpy(sb->buf + sb->len, data, len);\n    sb->buf[sb->len += len] = '\\0';\n}\n",[39,419,417],{"__ignoreMap":37},[122,421,423],{"id":422},"strbuf_addch",[39,424,426],{"className":425,"code":426,"language":36},[34],"strbuf_addch()",[15,428,429],{},[18,430,395,431,434,435,141],{},[39,432,105],{"className":433,"code":105,"language":36},[34],"追加一个字符",[39,436,36],{"className":437,"code":36,"language":36},[34],[18,439,440],{},"使用追加函数向缓冲区追加字符，长度为1。",[31,442,445],{"className":443,"code":444,"language":36,"meta":37},[34],"void strbuf_addch(struct strbuf *sb, int c) {\n    strbuf_add(sb, &c, 1);\n}\n",[39,446,444],{"__ignoreMap":37},[122,448,450],{"id":449},"strbuf_addstr",[39,451,453],{"className":452,"code":453,"language":36},[34],"strbuf_addstr()",[15,455,456],{},[18,457,395,458,461,462,141],{},[39,459,105],{"className":460,"code":105,"language":36},[34],"追加一个字符串",[39,463,465],{"className":464,"code":465,"language":36},[34],"s",[18,467,468,469,141],{},"使用追加函数向缓冲区追加字符串，长度为",[39,470,472],{"className":471,"code":472,"language":36},[34],"strlen(s)",[31,474,477],{"className":475,"code":476,"language":36,"meta":37},[34],"void strbuf_addstr(struct strbuf *sb, const char *s) {\n    strbuf_add(sb, s, strlen(s));\n}\n",[39,478,476],{"__ignoreMap":37},[122,480,482],{"id":481},"strbuf_addbuf",[39,483,485],{"className":484,"code":485,"language":36},[34],"strbuf_addbuf()",[15,487,488],{},[18,489,490,491,494,495,498],{},"向一个",[39,492,105],{"className":493,"code":105,"language":36},[34],"追加另一个",[39,496,55],{"className":497,"code":55,"language":36},[34],"的数据。",[18,500,501],{},"使用追加字符串函数向缓冲区追加另一个缓冲区的内容。",[18,503,504],{},"这种做法并不规范！标准做法是使用追加函数向缓冲区追加另一个缓冲区的内容，长度为缓冲区的长度。",[31,506,509],{"className":507,"code":508,"language":36,"meta":37},[34],"void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {\n    strbuf_addstr(sb, sb2->buf);\n}\n",[39,510,508],{"__ignoreMap":37},[122,512,514],{"id":513},"strbuf_setlen",[39,515,74],{"className":516,"code":74,"language":36},[34],[15,518,519],{},[18,520,521,522,79,525,141],{},"设置",[39,523,105],{"className":524,"code":105,"language":36},[34],[39,526,60],{"className":527,"code":60,"language":36},[34],[18,529,530,531,141],{},"如果设置的长度大于缓冲区容量，则先增加缓冲区容量。设置长度，并在对应位置增加字符串结束标志",[39,532,296],{"className":533,"code":296,"language":36},[34],[18,535,536],{},"这种做法并不规范！函数默认：设置的长度一定小于容量。所以不需要判断长度或者增加容量，遇到问题应该直接抛出错误。",[31,538,541],{"className":539,"code":540,"language":36,"meta":37},[34],"void strbuf_setlen(struct strbuf *sb, size_t len) {\n    if (len > sb->alloc) strbuf_grow(sb, len - sb->len + 1);\n    sb->buf[sb->len = len] = '\\0';\n}\n",[39,542,540],{"__ignoreMap":37},[122,544,546],{"id":545},"strbuf_avail",[39,547,549],{"className":548,"code":549,"language":36},[34],"strbuf_avail()",[15,551,552],{},[18,553,554,555,558],{},"计算",[39,556,105],{"className":557,"code":105,"language":36},[34],"目前仍可以向后追加的字符串长度。",[18,560,561],{},"返回缓冲区容量减去字符串长度再减一的值。",[31,563,566],{"className":564,"code":565,"language":36,"meta":37},[34],"size_t strbuf_avail(const struct strbuf *sb) {\n    return sb->alloc - sb->len - 1;\n}\n",[39,567,565],{"__ignoreMap":37},[122,569,571],{"id":570},"strbuf_insert",[39,572,574],{"className":573,"code":574,"language":36},[34],"strbuf_insert()",[15,576,577],{},[18,578,395,579,582,583,587,588,403,591,141],{},[39,580,105],{"className":581,"code":105,"language":36},[34],"内存坐标为",[39,584,586],{"className":585,"code":586,"language":36},[34],"pos","位置插入长度为",[39,589,60],{"className":590,"code":60,"language":36},[34],[39,592,407],{"className":593,"code":407,"language":36},[34],[18,595,596,597,601,602,605],{},"设置缓冲区长度为插入后的长度，将插入字符串处的缓冲区内容移动到插入内容结束的位置，并使用",[39,598,600],{"className":599,"code":600,"language":36},[34],"memcpy()","拷贝长度为",[39,603,60],{"className":604,"code":60,"language":36},[34],"的内容到插入的位置。",[31,607,610],{"className":608,"code":609,"language":36,"meta":37},[34],"void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) {\n    strbuf_setlen(sb, sb->len + len);\n    memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);\n    memcpy(sb->buf + pos, data, len);\n}\n",[39,611,609],{"__ignoreMap":37},[108,613,615],{"id":614},"part-2c","Part 2C",[122,617,619],{"id":618},"strbuf_rtrim",[39,620,622],{"className":621,"code":622,"language":36},[34],"strbuf_rtrim()",[15,624,625],{},[18,626,627,628,631,632,141],{},"去除",[39,629,105],{"className":630,"code":105,"language":36},[34],"缓冲区右端的所有空格和 ",[39,633,635],{"className":634,"code":635,"language":36},[34],"'\\t'",[18,637,638,639,642],{},"如果读到结尾处时空格或者制表符，则填充字符串结束标志",[39,640,296],{"className":641,"code":296,"language":36},[34],"，并减少长度，直到结尾处不是空格或者制表符。",[31,644,647],{"className":645,"code":646,"language":36,"meta":37},[34],"void strbuf_rtrim(struct strbuf *sb) {\n    while (sb->buf[sb->len - 1] == ' ' || sb->buf[sb->len - 1] == '\\t')\n        sb->buf[--sb->len] = '\\0';\n}\n",[39,648,646],{"__ignoreMap":37},[122,650,652],{"id":651},"strbuf_ltrim",[39,653,655],{"className":654,"code":655,"language":36},[34],"strbuf_ltrim()",[15,657,658],{},[18,659,627,660,663,664,141],{},[39,661,105],{"className":662,"code":105,"language":36},[34],"缓冲区左端的所有空格和 ",[39,665,635],{"className":666,"code":635,"language":36},[34],[18,668,669],{},"声明一个修剪位置变量为缓冲区内容开头的相对位置，如果读到修剪位置处时空格或者制表符，则增加修剪位置，直到修剪位置处不是空格或者制表符。",[18,671,672],{},"将修剪位置处开始，长度为缓冲区长度减去修剪位置+1的缓冲区内容移动到缓冲区内容开头，并将缓冲区长度减去修剪位置，就完成了缓冲区左端的修剪操作。",[31,674,677],{"className":675,"code":676,"language":36,"meta":37},[34],"void strbuf_ltrim(struct strbuf *sb) {\n    int trimpos = 0;\n    while (sb->buf[trimpos] == ' ' || sb->buf[trimpos] == '\\t') trimpos++;\n    memmove(sb->buf, sb->buf + trimpos, (sb->len -= trimpos) + 1);\n}\n",[39,678,676],{"__ignoreMap":37},[122,680,682],{"id":681},"strbuf_remove",[39,683,685],{"className":684,"code":685,"language":36},[34],"strbuf_remove()",[15,687,688],{},[18,689,690,691,694,695,698,699,702],{},"删除 ",[39,692,105],{"className":693,"code":105,"language":36},[34]," 缓冲区从 ",[39,696,586],{"className":697,"code":586,"language":36},[34]," 坐标长度为 ",[39,700,60],{"className":701,"code":60,"language":36},[34]," 的内容。",[18,704,705],{},"将删除坐标加删除长度处，长度为缓冲区长度减删除长度减相对删除位置+1的内容，移动到绝对删除位置处，并将缓冲区长度减去删除长度，便完成了删除缓冲区指定位置处指定长度内容的操作。",[31,707,710],{"className":708,"code":709,"language":36,"meta":37},[34],"void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) {\n    memmove(sb->buf + pos, sb->buf + pos + len, (sb->len -= len) - pos + 1);\n}\n",[39,711,709],{"__ignoreMap":37},[108,713,715],{"id":714},"part-2d","Part 2D",[122,717,719],{"id":718},"strbuf_read",[39,720,722],{"className":721,"code":722,"language":36},[34],"strbuf_read()",[15,724,725],{},[18,726,727,730,731,735,736,740,741,744],{},[39,728,105],{"className":729,"code":105,"language":36},[34],"增长",[39,732,734],{"className":733,"code":734,"language":36},[34],"hint ? hint : 8192","大小，然后将文件描述符为",[39,737,739],{"className":738,"code":739,"language":36},[34],"fd","的所有文件内容追加到",[39,742,105],{"className":743,"code":105,"language":36},[34],"中。",[18,746,747,748,751,752,756,757,761,762,766,767,770],{},"先使用",[39,749,356],{"className":750,"code":356,"language":36},[34],"增长内存空间，再使用",[39,753,755],{"className":754,"code":755,"language":36},[34],"fdopen()","读取文件到文件指针",[39,758,760],{"className":759,"code":760,"language":36},[34],"*fp","。使用",[39,763,765],{"className":764,"code":765,"language":36},[34],"fgetc()","逐字符读取，并使用",[39,768,426],{"className":769,"code":426,"language":36},[34],"将字符加入缓冲区，直到读到文件末尾结束，返回读取的文件长度。",[31,772,775],{"className":773,"code":774,"language":36,"meta":37},[34],"ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) {\n    strbuf_grow(sb, hint ? hint : 8192);\n    FILE *fp = fdopen(fd, \"r\");\n    for (char ch; (ch = fgetc(fp)) != EOF;) strbuf_addch(sb, ch);\n    return sb->len;\n}\n",[39,776,774],{"__ignoreMap":37},[122,778,780],{"id":779},"strbuf_getline",[39,781,783],{"className":782,"code":783,"language":36},[34],"strbuf_getline()",[15,785,786],{},[18,787,788,789,793,794,141],{},"将文件句柄为",[39,790,792],{"className":791,"code":792,"language":36},[34],"fp","的一行内容（抛弃换行符）读取到",[39,795,105],{"className":796,"code":105,"language":36},[34],[18,798,799,800,803,804,807,808,811],{},"使用",[39,801,765],{"className":802,"code":765,"language":36},[34],"逐字符读取文件指针",[39,805,760],{"className":806,"code":760,"language":36},[34],"，并使用",[39,809,426],{"className":810,"code":426,"language":36},[34],"将字符加入缓冲区，直到读到换行符或者文件末尾结束，返回读取的文件长度。",[31,813,816],{"className":814,"code":815,"language":36,"meta":37},[34],"int strbuf_getline(struct strbuf *sb, FILE *fp) {\n    for (char ch; (ch = fgetc(fp)) != '\\n' && ch != EOF;) strbuf_addch(sb, ch);\n    return sb->len;\n}\n",[39,817,815],{"__ignoreMap":37},[108,819,821],{"id":820},"challenge","CHALLENGE",[15,823,824],{},[18,825,826],{},"1.实现字符串切割（C 系字符串函数的一个痛点）。",[122,828,830],{"id":829},"strbuf_split_buf",[39,831,833],{"className":832,"code":833,"language":36},[34],"strbuf_split_buf()",[15,835,836],{},[18,837,838,839,842,843,847,848,852,853,857,858,141],{},"将长度为",[39,840,60],{"className":841,"code":60,"language":36},[34],"的字符串",[39,844,846],{"className":845,"code":846,"language":36},[34],"str","根据切割字符",[39,849,851],{"className":850,"code":851,"language":36},[34],"terminator","切成多个 strbuf,并从结果返回，max 可以用来限定最大切割数量。返回",[39,854,856],{"className":855,"code":856,"language":36},[34],"struct strbuf","的指针数组，数组的最后元素为",[39,859,861],{"className":860,"code":861,"language":36},[34],"NULL",[18,863,864,865,869,870,873],{},"刚开始，我尝试使用",[39,866,868],{"className":867,"code":868,"language":36},[34],"strtok()","实现，但是由于缓冲区内容含有",[39,871,296],{"className":872,"code":296,"language":36},[34],"，此后的内容被舍弃了，所以并没有达成目标。",[31,875,878],{"className":876,"code":877,"language":36,"meta":37},[34],"struct strbuf **strbuf_split_buf(const char *str, size_t len, int terminator, int max) {\n    struct strbuf **ret = (struct strbuf **) malloc(sizeof(struct strbuf *) * (max + 1));\n    char s[len + 1], delim[2] = {(char) terminator};\n    memcpy(s, str, len + 1);\n    char *token = strtok(s, delim);\n    for (int i = 0; token && i \u003C max; ret[++i] = NULL) {\n        ret[i] = (struct strbuf *) malloc(sizeof(struct strbuf));\n        strbuf_init(ret[i], 0);\n        strbuf_addstr(ret[i], token);\n        token = strtok(NULL, delim);\n    }\n    return ret;\n}\n",[39,879,877],{"__ignoreMap":37},[18,881,882],{},"后来，则标记字串的起始位置和结束位置，通过循环来逐字符判断，满足条件则切割，循环完毕即输出。",[31,884,887],{"className":885,"code":886,"language":36,"meta":37},[34],"struct strbuf **strbuf_split_buf(const char *str, size_t len, int terminator, int max) {\n    struct strbuf **ret = (struct strbuf **) malloc(sizeof(struct strbuf *) * (max + 1));\n    for (int pos = 0, flag = 0, n = 0; pos \u003C= len && n \u003C max; pos++) {\n        while (str[flag] == terminator) pos = flag++ + 2;\n        if (pos == len || pos > flag && str[pos] == terminator) {\n            ret[n] = (struct strbuf *) malloc(sizeof(struct strbuf));\n            strbuf_init(ret[n], 0);\n            strbuf_add(ret[n], str + flag, pos - flag);\n            \u002F\u002F printf(\"[%d]: %s (%d~%d, %d)\\n\", n, ret[n]->buf, flag, pos, pos - flag);\n            while (str[pos] == terminator) flag = pos++;\n            ret[++n] = NULL;\n        }\n    }\n    return ret;\n}\n",[39,888,886],{"__ignoreMap":37},[15,890,891],{},[18,892,893],{},"2.实现判断一个strbuf是否以指定字符串开头的功能（C系字符串函数的另一个痛点）。",[122,895,897],{"id":896},"strbuf_begin_judge",[39,898,900],{"className":899,"code":900,"language":36},[34],"strbuf_begin_judge()",[15,902,903],{},[18,904,905],{},"target_str：目标字符串，str：前缀字符串，strlen：target_str长度，前缀相同返回true失败返回false",[18,907,908,909,913,914,918,919,923,924,927,928,141],{},"前缀字符串为空则返回",[39,910,912],{"className":911,"code":912,"language":36},[34],"true","，否则使用",[39,915,917],{"className":916,"code":917,"language":36},[34],"strncmp()","对比目标字符串的前",[39,920,922],{"className":921,"code":922,"language":36},[34],"strlen","字节是否与前缀字符串相同，如果相同结果为0返回",[39,925,912],{"className":926,"code":912,"language":36},[34],"，否则返回",[39,929,931],{"className":930,"code":931,"language":36},[34],"false",[31,933,936],{"className":934,"code":935,"language":36,"meta":37},[34],"bool strbuf_begin_judge(char *target_str, const char *str, int strnlen) {\n    return str == NULL || !strncmp(target_str, str, strlen(str));\n}\n",[39,937,935],{"__ignoreMap":37},[15,939,940],{},[18,941,942,943,947],{},"3.获取字符串从坐标",[39,944,946],{"className":945,"code":946,"language":36},[34],"[begin, end)","的所有内容（可以分成引用和拷贝两个模式）。",[122,949,951],{"id":950},"strbuf_get_mid_buf",[39,952,954],{"className":953,"code":954,"language":36},[34],"strbuf_get_mid_buf()",[15,956,957],{},[18,958,959],{},"target_str：目标字符串，begin：开始下标，end：结束下标，len：target_buf的长度。参数不合法返回NULL。下标从0开始，[begin, end)区间。",[18,961,962,963,141],{},"如果参数不合法（起始大于结束、结束大于长度）返回",[39,964,861],{"className":965,"code":861,"language":36},[34],[18,967,968,969,972],{},"否则为字符串申请结束下标减开始下标+1的空间，将指定位置指定长度的字符串填入，并在末尾加上字符串结束标志",[39,970,296],{"className":971,"code":296,"language":36},[34],"，返回字符串。",[31,974,977],{"className":975,"code":976,"language":36,"meta":37},[34],"char *strbuf_get_mid_buf(char *target_buf, int begin, int end, int len) {\n    if (begin > end || end >= len) return NULL;\n    char *str = (char *) malloc(end - begin + 1);\n    memcpy(str, target_buf + begin, end - begin);\n    str[end - begin] = '\\0';\n    return str;\n}\n",[39,978,976],{"__ignoreMap":37},{"title":37,"searchDepth":980,"depth":980,"links":981},4,[982],{"id":12,"depth":983,"text":13,"children":984},2,[985,995,1005,1010,1014],{"id":110,"depth":986,"text":111,"children":987},3,[988,989,990,991,992,993,994],{"id":124,"depth":980,"text":128},{"id":153,"depth":980,"text":157},{"id":189,"depth":980,"text":193},{"id":214,"depth":980,"text":218},{"id":238,"depth":980,"text":242},{"id":276,"depth":980,"text":280},{"id":316,"depth":980,"text":320},{"id":340,"depth":986,"text":341,"children":996},[997,998,999,1000,1001,1002,1003,1004],{"id":352,"depth":980,"text":356},{"id":386,"depth":980,"text":390},{"id":422,"depth":980,"text":426},{"id":449,"depth":980,"text":453},{"id":481,"depth":980,"text":485},{"id":513,"depth":980,"text":74},{"id":545,"depth":980,"text":549},{"id":570,"depth":980,"text":574},{"id":614,"depth":986,"text":615,"children":1006},[1007,1008,1009],{"id":618,"depth":980,"text":622},{"id":651,"depth":980,"text":655},{"id":681,"depth":980,"text":685},{"id":714,"depth":986,"text":715,"children":1011},[1012,1013],{"id":718,"depth":980,"text":722},{"id":779,"depth":980,"text":783},{"id":820,"depth":986,"text":821,"children":1015},[1016,1017,1018],{"id":829,"depth":980,"text":833},{"id":896,"depth":980,"text":900},{"id":950,"depth":980,"text":954},[1020],"开发","2023-01-01 23:58:33","设计一个C语言的动态扩容缓冲区，是西邮 Linux 兴趣小组的 Lab 报告。",false,"md","https:\u002F\u002Fassets.zhilu.cyou\u002Fcover3\u002Fc-strbuf.jpg",{"slots":1027},{},true,"\u002F2023\u002Fc-strbuf",null,{"text":1032,"minutes":1033,"time":1034,"words":1035},"13 min read",12.725,763500,2545,[1037],{"link":1038,"title":13},"https:\u002F\u002Fplan.xiyoulinux.com\u002Fproject\u002Fstrbuf\u002F",{"title":5,"description":1022},{"loc":1029},"posts\u002F2023\u002Fc-strbuf",[1043,179,1044],"C语言","数据结构","tech","2023-07-30 11:45:33","O14EFB0b4PApW08YkX3qySNN9nwZ6x6MsCd5cMcPfU8",[1049,1054],{"title":1050,"path":1051,"stem":1052,"date":1053,"type":1045,"children":-1},"C语言字符串时间获取下一秒的思考","\u002F2022\u002Fc-next-sec","posts\u002F2022\u002Fc-next-sec","2022-12-18 19:53:37",{"title":1055,"path":1056,"stem":1057,"date":1058,"type":1045,"children":-1},"Linux QQ 崩溃解决办法","\u002F2023\u002Flinuxqq-crash","posts\u002F2023\u002Flinuxqq-crash","2023-03-16 21:02:22",1782091376939]