Dlang 代码段错误分析及解决:字符串替换函数 replaceAll 中的内存泄漏问题
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 来释放内存,并且要确保指针指向的是有效的内存地址。在进行字符串操作时,尤其要注意内存管理,避免出现内存泄漏和段错误等问题。
原文地址: https://www.cveoy.top/t/topic/ogul 著作权归作者所有。请勿转载和采集!