高效在哪里?
- 执行速度上比C++快;
- 占用内存最少,1个byte都不浪费;
- 执行过程中,没有多余的内存分配、拷贝操作;
先上效果图,代码在最后
/**
* @brief 分割字符串,并将其保存到pStrs。使用方法如下:
* int nStrs = Split("1,2,3,4", ",", nullptr);
* char** pStrs = (char**)malloc(nStrs); // 或 char pStrs[m][n]; 只要保证m*n>=nStrs即可
* nStrs = Split(str, div, pStrs);
* free(pStrs);
* @param[in] str 欲分割的字符串
* @param[in] div 分隔符
* @param[out] pStrs 存储子串,若为nullptr则函数返回pStrs所需大小
* @return 失败返回-1,当pStrs为nullptr返回所需内存大小,否则返回分割后的个数
* @author xktesla@2021-12-9
*/
int StrUtil::Split(const char* str, const char* div, char* pStrs[])
{
if (!div || !div[0]) { return -1; }
int divlen = strlen(div);
// 计算所需最小内存
auto getBytes = [&](int* pnStrs)->int {
*pnStrs = 0;
int nBytes = 0;
char* p0 = (char*)str;
for (char* p1 = strstr(p0, div); p1; p1 = strstr(p1 + divlen, div))
{
++(*pnStrs);
nBytes += (p1 - p0);
nBytes += sizeof(char*);
p0 = p1;
}
nBytes += strlen(p0) + 1 + sizeof(char*);
++(*pnStrs);
return nBytes;
};
int nStrs = 0;
int nBytes = getBytes(&nStrs);
if (!pStrs) { return nBytes; }
// 函数要求pStrs必须满足大于等于nBytes,否则以下逻辑将导致内存溢出
char* pBytes = (char*)pStrs;
memset(pBytes, 0, nBytes);
int iStrs = nStrs * sizeof(char*); // 第一个子串的地址索引
pStrs[0] = pBytes + iStrs;
strcpy(pStrs[0], str);
int len = strlen(str);
for (int i = nBytes, j = nBytes + 1, k = nStrs; i > iStrs && k > 1; --i)
{ // i记录当前位置,j记录上个子串起始位置,l记录当前子串长度,k记录当前子串索引
if (memcmp(&pBytes[i], div, divlen) == 0)
{
int l = j - i - divlen - 1;
j = j - (l + 1); // 重计算为当前子串即将存储的位置
pStrs[--k] = (char*)memmove(&pBytes[j], &pBytes[i + divlen], l);
memset(&pBytes[i], 0, j - i);
}
}
return nStrs;
}