替换字符串中的字符

时间:2014-11-29 12:59:35

标签: c string performance memory-management replace

我有一个替换字符串中的字符的功能,它完美地工作!
但是,唯一的问题是它需要另一个字符串作为缓冲区,修改后的文本将放在缓冲区中。

这对我来说是一场灾难,因为我的大部分工作都是关于I / O处理的。因此,如果我使用calloc分配1024个字节作为最大值来包含一行,我将不得不复制它以具有相同大小的修改版本(是的,在字符串替换时浪费了1024个字节)。

这是功能:

void replaceStr(buffer, haystack, needles, n_needles, rep)
    char *buffer;
    const char *haystack, **needles, *rep;
    const size_t n_needles;
{
    if (!buffer || !haystack || !needles || !rep)
        return;
    size_t rep_length = strlen(rep);
    char *found;
    for (int i = 0; i < n_needles; ++i) {
        const char *needle = needles[i];
        const size_t needle_length = strlen(needle);
        while ((found = strstr(haystack, needle))) {
            /* measure the length of what is before needle */
            size_t diff = found - haystack;
            /* copy that part until needle */
            strncpy(buffer, haystack, diff);
            /* copy needle (found == buffer + diff) */
            strcpy(buffer + diff, rep);
            /* adjust pointers */
            buffer += diff + rep_length;
            haystack = found + needle_length;
        }
        /* copy remaining string */
        strcpy(buffer, haystack);
    }
}

使用与缓冲区相同的字符串将导致:
  - 更快的代码(不需要调用calloc
  - 内存效率高的代码(再次,不需要调用calloc
  - 更好的代码。因为一行代码比三行多(一个用于分配,一个用于函数调用,一个用于释放)

我可能已经猜到的问题是:我如何使用与缓冲区相同的字符串?

1 个答案:

答案 0 :(得分:1)

除非您可以保证替换字符串rep始终与搜索字符串needle的大小完全相同,否则您可能会让您的情况变得更糟,而且更多很难找到原始字符串的原位替换,因为从算法上来说,你必须对整个字符串的内容进行混洗。

然后,您将替换常量时间O(1)附加到输出缓冲区,并在原始缓冲区中使用O(N)线性复杂性交换字节。

就地替换算法在您只是覆盖范围内的固定大小的元素时,或者如果您的算法涉及在读取指针后面跟踪的写入指针,产生的最终结果小于或等于达到原件的大小。在你的情况下,你处理可变大小的替换和读取和写入相同的重叠位置,这可能会导致更大的结果,并且当你真的想在内存中单独放置输出结果时为了提高效率,否则你将在同一个内存中处理大量的开销,试图重用它。

通过接受指向输出缓冲区的指针,您的函数签名就可以了。当然,如果每次调用它之前调用代码callocsfrees缓冲区,那么这显然会导致容易出现瓶颈的代码。调用代码应该为每个线程重用相同的缓冲区并将其传递给调用堆栈以避免重新创建它。

现在,如果您想优化调用代码以避免过多的callocsfrees,那么如果您无法提前有效地确定输出缓冲区大小的上限,那么这可能会非常棘手。在这种情况下,重用相同的缓冲区,但在遇到需要更大的新输入情况时(或每次只使用realloc),还要跟踪其大小和realloc。然后继续重复使用并冲洗并重复free完成后。