Dlang 代码段错误分析及解决:字符串替换函数 replaceAll 中的内存泄漏问题

问题描述:

以下 Dlang 代码段中的 replaceAll 函数在执行字符串替换时发生了段错误,使用 gdb 调试后发现是由于在循环中错误地释放了原始字符串指针导致的。

import std.stdio;
import core.stdc.string;
import core.stdc.stdlib;
import core.stdc.ctype:tolower;

// 判断两个字符是否相等,根据 isCaseSensitive 参数决定是否区分大小写
bool charEqual(char a, char b, bool isCaseSensitive)
{
    if (isCaseSensitive)
    {
        return a == b;
    }
    else
    {
        return tolower(a) == tolower(b);
    }
}

// 在字符串 haystack 中查找第一次出现 needle 的位置,返回指向该位置的指针,如果找不到则返回 null
char* strstr(char* haystack, const char* needle, bool isCaseSensitive)
{
    size_t haystackLen = strlen(haystack);
    size_t needleLen = strlen(needle);
    if (needleLen > haystackLen)
    {
        return null;
    }
    for (size_t i = 0; i <= haystackLen - needleLen; i++)
    {
        bool found = true;
        for (size_t j = 0; j < needleLen; j++)
        {
            if (!charEqual(haystack[i + j], needle[j], isCaseSensitive))
            {
                found = false;
                break;
            }
        }
        if (found)
        {
            return haystack + i;
        }
    }
    return null;
}

// 将字符串 haystack 中的所有 needle 替换为 replace,并返回替换后的字符串,如果 haystack 中不包含 needle 则返回 haystack
char* replaceAll(char* haystack, const char* needle, const char* replace, bool isCaseSensitive)
{
    size_t needleLen = strlen(needle);
    size_t replaceLen = strlen(replace);
    char* result = haystack;
    char* p = strstr(result, needle, isCaseSensitive);
    while (p != null)
    {
        char* oldResult = result;
        size_t oldResultLen = strlen(oldResult);
        size_t prefixLen = p - oldResult;
        size_t suffixLen = oldResultLen - prefixLen - needleLen;
        size_t newResultLen = prefixLen + replaceLen + suffixLen;
        char* newResult = cast(char*)malloc(newResultLen + 1);
        memcpy(newResult, oldResult, prefixLen);
        memcpy(newResult + prefixLen, replace, replaceLen);
        memcpy(newResult + prefixLen + replaceLen, p + needleLen, suffixLen);
        newResult[newResultLen] = '\0';
        result = newResult;
        free(oldResult);
        p = strstr(result + prefixLen + replaceLen, needle, isCaseSensitive);
    }
    return result;
}

void main()
{
    char* allStr = "hello world World\0".dup.ptr;
    const char* searchStr = "World".ptr;
    const char* replaceStr = "china".ptr;
    bool isCaseSensitive = false;

    char* result = replaceAll(allStr, searchStr, replaceStr, isCaseSensitive);
    printf("%s",result);
    free(result);
}

错误分析:

在 replaceAll 函数中,当找到 needle 后,将原来的字符串 oldResult 释放了,然后将指针 result 指向新分配的字符串 newResult,但是在后面的循环中,又使用了原来的指针 result,这里就出现了问题。因为原来的指针已经被释放了,所以访问原来指针指向的内存就会出现段错误。

解决方法:

将指针 result 和指针 oldResult 分开,不要混用。在每次循环中,都使用新分配的指针 newResult 来存储结果,最后将新分配的指针返回即可。

修改后的代码:

char* replaceAll(char* haystack, const char* needle, const char* replace, bool isCaseSensitive)
{
    size_t needleLen = strlen(needle);
    size_t replaceLen = strlen(replace);
    char* result = haystack;
    char* p = strstr(result, needle, isCaseSensitive);
    while (p != null)
    {
        size_t prefixLen = p - result;
        size_t suffixLen = strlen(result + prefixLen + needleLen);
        size_t newResultLen = prefixLen + replaceLen + suffixLen;
        char* newResult = cast(char*)malloc(newResultLen + 1);
        memcpy(newResult, result, prefixLen);
        memcpy(newResult + prefixLen, replace, replaceLen);
        memcpy(newResult + prefixLen + replaceLen, result + prefixLen + needleLen, suffixLen);
        newResult[newResultLen] = '\0';
        free(result);
        result = newResult;
        p = strstr(result + prefixLen + replaceLen, needle, isCaseSensitive);
    }
    return result;
}

总结:

该段代码错误主要是由于错误地释放了内存导致的指针错误。在使用 malloc 分配内存后,必须使用 free 来释放内存,并且要确保指针指向的是有效的内存地址。在进行字符串操作时,尤其要注意内存管理,避免出现内存泄漏和段错误等问题。

Dlang 代码段错误分析及解决:字符串替换函数 replaceAll 中的内存泄漏问题

原文地址: https://www.cveoy.top/t/topic/ogul 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录