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

如何实现基于栈存储输出的字符串分割函数,避免动态内存分配?

如何在C语言中实现无动态内存分配的栈上字符串分割函数?

我原本在循环内通过栈上的变长数组实现了字符串分割,代码如下:

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

void main()
{
  for (int i = 0; i < 1000; i++)
  {
    char *str, *delm;
    str = "The first part/the second part/still in the second part"; // str comes from within the loop
    delm = "/";

    // The function block
    size_t len = strlen(str);

    char *ptr;
    int pos;
    ptr = strstr(str, delm);
    if (ptr == NULL)
    {
      pos = -1;
    }
    else
    {
      pos = ptr - str;
    }

    if (pos > -1)
    {
      char first[pos + 1];
      strncpy(first, str, pos);
      first[pos] = 0;

      char second[len - pos + 1];
      strncpy(second, str + pos + 1, len - pos);
      second[len - pos] = 0;

      // end of the block

      printf("%s - %s\n", first, second);
    }
  }
}

由于这段分割逻辑经常使用,我想把它封装成类似下面的函数来提升可读性:

void split(const char *str, const char *delm, char *first, char *second){
    // the code
}

但这样的话,外部无法预知first和second的尺寸,只能用malloc或realloc动态分配,可能影响性能。我想知道有没有技巧能让函数的输出直接存储在栈上,无需动态内存分配?


方案1:让调用者预先分配栈空间并传入长度限制

修改函数签名,让调用者传入预先在栈上分配好的缓冲区,以及对应的最大长度,函数内部负责检查长度是否足够,避免缓冲区溢出。这种方式完全不需要动态内存,所有存储都在调用者的栈上。

示例代码:

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

// 返回值:成功分割返回0,分隔符不存在返回-1,缓冲区不足返回-2
int split(const char *str, const char *delm, char *first, size_t first_max_len, char *second, size_t second_max_len)
{
    char *ptr = strstr(str, delm);
    if (ptr == NULL)
    {
        return -1;
    }

    size_t first_len = ptr - str;
    if (first_len >= first_max_len)
    {
        return -2; // 缓冲区不够存第一部分
    }
    strncpy(first, str, first_len);
    first[first_len] = '\0';

    size_t second_len = strlen(ptr + 1);
    if (second_len >= second_max_len)
    {
        return -2; // 缓冲区不够存第二部分
    }
    strncpy(second, ptr + 1, second_len);
    second[second_len] = '\0';

    return 0;
}

int main()
{
    for (int i = 0; i < 1000; i++)
    {
        const char *str = "The first part/the second part/still in the second part";
        const char *delm = "/";
        char *ptr = strstr(str, delm);
        if (ptr != NULL)
        {
            // 在调用者栈上分配刚好足够的变长数组
            char first[ptr - str + 1];
            char second[strlen(str) - (ptr - str) + 1];
            if (split(str, delm, first, sizeof(first), second, sizeof(second)) == 0)
            {
                printf("%s - %s\n", first, second);
            }
        }
    }
    return 0;
}

优点:完全栈分配,性能无损耗;函数封装性好,调用者可以灵活控制缓冲区大小。
缺点:调用者需要先计算所需缓冲区大小,多了一步操作。

方案2:用宏封装分割逻辑(最贴合原代码写法)

直接把分割逻辑封装成宏,宏展开后会直接在调用者的栈帧中分配数组,相当于把代码块嵌入调用点,既实现了复用,又保留了栈分配的特性。

示例代码:

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

#define SPLIT(str, delm, first_var, second_var) \
    do { \
        const char *_split_str = (str); \
        const char *_split_delm = (delm); \
        size_t _split_len = strlen(_split_str); \
        char *_split_ptr = strstr(_split_str, _split_delm); \
        if (_split_ptr != NULL) { \
            int _split_pos = _split_ptr - _split_str; \
            char first_var[_split_pos + 1]; \
            char second_var[_split_len - _split_pos + 1]; \
            strncpy(first_var, _split_str, _split_pos); \
            first_var[_split_pos] = '\0'; \
            strncpy(second_var, _split_str + _split_pos + 1, _split_len - _split_pos); \
            second_var[_split_len - _split_pos] = '\0';
#define SPLIT_END \
        } \
    } while(0)

int main()
{
    for (int i = 0; i < 1000; i++)
    {
        const char *str = "The first part/the second part/still in the second part";
        const char *delm = "/";
        SPLIT(str, delm, first, second)
            printf("%s - %s\n", first, second);
        SPLIT_END
    }
    return 0;
}

优点:完全保留原代码的栈变长数组特性,无需额外计算,调用方式简洁;没有函数调用开销。
缺点:宏的调试难度略高;如果分割逻辑复杂,宏代码会显得臃肿。

方案3:C11及以上用结构体返回栈缓冲区指针(需调用者提前分配)

定义一个结构体存储两个指向栈缓冲区的指针,调用者预先在栈上分配好缓冲区,函数填充结构体中的指针和内容。本质和方案1类似,但用结构体打包参数,提升可读性。

示例代码:

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

typedef struct {
    char *first;
    char *second;
} SplitResult;

// 返回值:成功返回非空结构体,分隔符不存在返回空指针
SplitResult split(const char *str, const char *delm, char *first_buf, size_t first_buf_len, char *second_buf, size_t second_buf_len)
{
    SplitResult res = {NULL, NULL};
    char *ptr = strstr(str, delm);
    if (ptr == NULL)
    {
        return res;
    }

    size_t first_len = ptr - str;
    if (first_len >= first_buf_len)
    {
        return res;
    }
    strncpy(first_buf, str, first_len);
    first_buf[first_len] = '\0';
    res.first = first_buf;

    size_t second_len = strlen(ptr + 1);
    if (second_len >= second_buf_len)
    {
        return res;
    }
    strncpy(second_buf, ptr + 1, second_len);
    second_buf[second_len] = '\0';
    res.second = second_buf;

    return res;
}

int main()
{
    for (int i = 0; i < 1000; i++)
    {
        const char *str = "The first part/the second part/still in the second part";
        const char *delm = "/";
        char *ptr = strstr(str, delm);
        if (ptr != NULL)
        {
            char first[ptr - str + 1];
            char second[strlen(str) - (ptr - str) + 1];
            SplitResult res = split(str, delm, first, sizeof(first), second, sizeof(second));
            if (res.first != NULL && res.second != NULL)
            {
                printf("%s - %s\n", res.first, res.second);
            }
        }
    }
    return 0;
}

优点:用结构体打包返回结果,代码可读性更好;同样是纯栈分配。
缺点:需要C11或更高版本支持;调用者仍需提前分配缓冲区。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:01:15