You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用malloc的情况下实现MicroJSON式字符串拷贝及数组赋值?

无malloc的C字符串拷贝实现及字符串数组赋值问题

背景

我在MicroJSON的仓库页面看到,它的代码可以将JSON解析到静态C结构体且无需使用malloc(3)。我查看了其源码片段(如下),但不确定是否理解正确:

char *lptr;
switch (cursor->type) {
        case t_integer:
            memcpy(lptr, &cursor->dflt.integer, sizeof(int));
}

我尝试实现无malloc的字符串拷贝,先后写出如下代码:

首次尝试

char json[] = "{\"name\": \"john\"}"
char *copy = NULL;
memcpy(copy, 9, 4); // john starts at 9 and has 4 characters length

二次尝试(可运行)

char *substring(const char *start, long len, char *destination) {
    strncpy(destination, start, len);
    destination[len] = '\0';
    return destination;
}

char key[5];
substring(9, 4, key);

问题咨询

  1. 如何正确实现无malloc的字符串拷贝?
  2. 能否在不使用malloc的情况下,将长字符串的不同部分作为项赋值给字符串数组?

问题解答

1. 正确实现无malloc的字符串拷贝

无malloc的核心是提前分配好足够的内存空间(比如栈上数组、静态数组或全局数组),绝对不能用空指针直接作为拷贝目标(你的首次尝试就犯了这个错误,copy是NULL,没有指向有效内存区域)。

你的二次尝试方向是对的,但存在参数传递错误:调用substring时传的9是数值,不是字符串指针,应该改成json + 9来指向"john"的起始位置。修正后的代码如下:

char *substring(const char *start, long len, char *destination) {
    // 先做合法性检查,避免非法内存访问
    if (destination == NULL || start == NULL) return NULL;
    // 已知长度的情况下,memcpy比strncpy效率更高
    memcpy(destination, start, len);
    // 手动添加字符串终止符,确保是合法的C字符串
    destination[len] = '\0';
    return destination;
}

char json[] = "{\"name\": \"john\"}";
char key[5];
// 指向json中"john"的起始索引位置
substring(json + 9, 4, key);

注意要点:

  • 必须保证destination指向的内存空间至少有len+1个字节(要预留存储终止符\0的位置),否则会触发缓冲区溢出。
  • 一定要手动添加\0:memcpy不会自动添加终止符,strncpy在拷贝长度耗尽时也不会添加,必须自行处理。

2. 无malloc实现长字符串不同部分赋值给字符串数组

完全可以实现,核心思路和字符串拷贝一致:提前为数组的每个元素分配固定大小的内存空间,再将长字符串的对应部分拷贝进去。

举个实际示例,从JSON字符串中提取多个字段存入字符串数组:

#include <stdio.h>
#include <string.h>

char *substring(const char *start, long len, char *destination) {
    if (destination == NULL || start == NULL) return NULL;
    memcpy(destination, start, len);
    destination[len] = '\0';
    return destination;
}

int main() {
    char json[] = "{\"name\": \"john\", \"age\": \"30\", \"city\": \"nyc\"}";
    // 提前定义字符串数组,每个元素分配足够空间(这里设为最多存10个字符+1个终止符)
    char str_array[3][11];

    // 提取"john"(起始索引9,长度4)
    substring(json + 9, 4, str_array[0]);
    // 提取"30"(起始索引20,长度2)
    substring(json + 20, 2, str_array[1]);
    // 提取"nyc"(起始索引32,长度3)
    substring(json + 32, 3, str_array[2]);

    // 打印结果
    for (int i = 0; i < 3; i++) {
        printf("str_array[%d] = %s\n", i, str_array[i]);
    }
    return 0;
}

如果字段长度不确定,可以:

  • 先解析出每个字段的长度,确保数组元素的空间足够覆盖(比如定义一个足够大的固定长度,比如256字节,适配业务场景即可)。
  • 若数组规模较大,优先使用全局数组或静态数组,避免栈空间溢出(栈空间通常较小,大数组放在全局区/静态区更安全)。

另外还有一种思路:不拷贝内容,直接用指针指向长字符串的对应位置。但这种方式要求原字符串的生命周期必须长于指针,且原字符串不能被修改(否则指针指向的内容会同步变化),同时只有当原字符串的目标片段本身以\0结尾时才适用,否则还是拷贝方式更安全。


内容的提问来源于stack exchange,提问作者Source

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:09:52