我试图在C中编写一个字符串替换函数,它在char * ,它使用malloc()进行分配。 它有点不同,它会找到并替换字符串,而不是起始字符串中的字符。

如果搜索和替换字符串的长度相同(或者替换字符串比搜索字符串短),这很简单,因为我有足够的空间分配。 如果我尝试使用realloc() ,我会收到一个错误,告诉我我正在做一个双重自由 - 我不知道我是怎么回事,因为我只使用realloc()

也许一点点代码会有所帮助:

void strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while (find = strstr(find, search)) {

        if (delta > 0) {
            realloc(input, strlen(input) + delta);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) - (find - input));
        memmove(find, replace, replaceLen);
    }
}

该程序有效,直到我尝试在被替换的字符串将比初始字符串长的实例中realloc() (它仍然有点工作,它只是吐出错误以及结果)。

如果有帮助,调用代码如下所示:

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

void strrep(char *input, char *search, char *replace);

int main(void) {
    char *input = malloc(81);

    while ((fgets(input, 81, stdin)) != NULL) {
        strrep(input, "Noel", "Christmas");
    }
}

===============>>#1 票数:13 已采纳

作为一般规则,你应该做一个免费或realloc上的用户提供缓冲。 您不知道用户在哪里分配空间(在您的模块中,在另一个DLL中),因此您不能在用户缓冲区上使用任何分配函数。

如果你现在不能在你的函数中进行任何重新分配,你应该稍微改变它的行为,比如只做一次替换,这样用户就能计算得到的字符串最大长度并为你提供一个足够长的缓冲区。替换发生。

然后你可以创建另一个函数来进行多次替换,但是你必须为结果字符串分配整个空间并复制用户输入字符串。 然后,您必须提供删除分配的字符串的方法。

导致:

void  strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void  strrepmfree(char *input);

===============>>#2 票数:11

首先,抱歉,我迟到了。 这是我的第一个stackoverflow答案。 :)

正如已经指出的那样,当调用realloc()时,您可以将指针更改为正在重新分配的内存。 发生这种情况时,参数“string”变为无效。 即使您重新分配它,一旦该功能结束,更改将超出范围。

为了回答OP,realloc()返回一个指向新重新分配的内存的指针。 返回值需要存储在某处。 通常,你会这样做:

data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));

/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
   foo = bar;
   bar = NULL;
}
else
{
   fprintf(stderr, "Crap. Memory error.\n");
   free(foo);
   exit(-1);
}

正如TyBoer指出的那样,你们不能改变传入指针的值作为此函数的输入。 您可以指定所需的任何内容,但更改将在函数末尾超出范围。 在下面的块中,一旦函数完成,“input”可能是也可能不是无效指针:

void foobar(char *input, int newlength)
{
   /* Here, I ignore my own advice to save space. Check your return values! */
   input = realloc(input, newlength * sizeof(char));
}

Mark尝试通过返回新指针作为函数的输出来解决此问题。 如果你这样做,那么调用者的责任就是永远不再使用他用于输入的指针。 如果它与返回值匹配,那么你有两个指向同一点的指针,只需要在其中一个上调用free()。 如果它们不匹配,则输入指针现在指向该进程可能拥有或可能不拥有的内存。 取消引用它可能会导致分段错误。

您可以使用双指针作为输入,如下所示:

void foobar(char **input, int newlength)
{
   *input = realloc(*input, newlength * sizeof(char));
}

如果调用者在某处有输入指针的副本,那么该重复项现在仍可能无效。

我认为这里最干净的解决方案是避免在尝试修改函数调用者的输入时使用realloc()。 只需malloc()一个新缓冲区,返回该缓冲区,让调用者决定是否释放旧文本。 这有一个额外的好处,让调用者保持原始字符串!

===============>>#3 票数:6

只是在黑暗中拍摄,因为我还没有尝试过,但是当你重新分配时,它会像malloc一样返回指针。 因为realloc可以根据需要移动指针,如果不执行以下操作,则很可能在无效指针上操作:

input = realloc(input, strlen(input) + delta);

===============>>#4 票数:6

有人因为迟到党而道歉 - 两个半月前。 哦,我花了很多时间做软件考古学。

我很感兴趣,没有人明确评论原始设计中的内存泄漏,或者是一个一个错误。 并且它正在观察内存泄漏,它告诉我你为什么会得到双重自由错误(因为,确切地说,你正在多次释放相同的内存 - 而你是在践踏已经释放的内存之后这样做的)。

在进行分析之前,我会同意那些说你的界面不那么出色的人; 但是,如果您处理内存泄漏/践踏问题并记录了“必须分配的内存”要求,那么它可能是“OK”。

有什么问题? 好吧,你将缓冲区传递给realloc(),并且realloc()返回一个指向你应该使用的区域的新指针 - 并忽略该返回值。 因此,realloc()可能已经释放了原始内存,然后再次向它传递相同的指针,并且它会抱怨您释放相同的内存两次,因为您再次将原始值传递给它。 这不仅泄漏了记忆,而且意味着你继续使用原始空间 - 而John Downey在黑暗中的镜头指出你滥用realloc(),但并没有强调你这么做的严重程度。 还有一个off-by-one错误,因为你没有为终止字符串的NUL'\\ 0'分配足够的空间。

发生内存泄漏是因为您没有提供一种机制来告诉调用者字符串的最后一个值。 因为你不停地践踏原始字符串加上后面的空格,看起来代码工作正常,但是如果你的调用代码释放了空间,它也会得到一个双重自由错误,或者它可能会得到一个核心转储或等价物,因为存储器控制信息被完全扰乱。

您的代码也无法防止无限期增长 - 考虑将'Noel'替换为'Joyeux Noel'。 每次,你会添加7个字符,但你会在被替换的文本中找到另一个Noel,然后展开它,依此类推。 我的修复(下面)没有解决这个问题 - 简单的解决方案可能是检查搜索字符串是否出现在替换字符串中; 另一种方法是跳过替换字符串并继续搜索。 第二个问题需要解决一些非平凡的编码问题。

所以,我建议修改你的被调用函数是:

char *strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while ((find = strstr(find, search)) != 0) {
        if (delta > 0) {
            input = realloc(input, strlen(input) + delta + 1);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) + 1 - (find - input));
        memmove(find, replace, replaceLen);
    }

    return(input);
}

此代码不检测内存分配错误 - 如果realloc()失败,可能会崩溃(但如果没有,则会泄漏内存)。 有关内存管理问题的广泛讨论,请参阅Steve Maguire的“编写固体代码”一书。

===============>>#5 票数:4

注意,尝试编辑您的代码以摆脱html转义码。

好吧,虽然自从我使用C / C ++已经有一段时间了,但是如果在原始块之后内存中有空间,则realloc只会重新使用内存指针值。

例如,考虑一下:

(XXXXXXXXXX ..........)

如果你的指针指向第一个x,和。 意味着空闲内存位置,并且您将变量指向的内存大小增加5个字节,它将成功。 这当然是一个简化的例子,因为块被舍入到一定大小以进行对齐,但无论如何。

但是,如果您随后尝试将其增加10个字节,并且只有5个可用,则需要在内存中移动块并更新指针。

但是,在您的示例中,您正在向函数传递指向该字符的指针,而不是指向您的变量的指针,因此虽然内部的strrep函数可能能够调整正在使用的变量,但它是strrep函数的局部变量,您的调用代码将保留原始指针变量值。

但是,此指针值已被释放。

在您的情况下,输入是罪魁祸首。

但是,我会提出另一个建议。 在你的情况下,看起来输入变量确实是输入,如果是,它根本不应该被修改。

因此,我会尝试找到另一种方法来做你想做的事情而不改变输入 ,因为像这样的副作用很难追查。

===============>>#6 票数:3

这似乎有效;

char *strrep(char *string, const char *search, const char *replace) {
    char *p = strstr(string, search);

    if (p) {
        int occurrence = p - string;
        int stringlength = strlen(string);
        int searchlength = strlen(search);
        int replacelength = strlen(replace);

        if (replacelength > searchlength) {
            string = (char *) realloc(string, strlen(string) 
                + replacelength - searchlength + 1);
        }

        if (replacelength != searchlength) {
            memmove(string + occurrence + replacelength, 
                        string + occurrence + searchlength, 
                        stringlength - occurrence - searchlength + 1);
        }

        strncpy(string + occurrence, replace, replacelength);
    }

    return string;
}

叹了口气,无论如何都要发布代码而不吸吮?

===============>>#7 票数:3

realloc很奇怪,很复杂,只应该在每秒处理大量内存时使用。 ie - 它实际上使你的代码更快。

我见过代码在哪里

realloc(bytes, smallerSize);

使用并工作以调整缓冲区的大小,使其更小。 工作了大约一百万次,然后由于某种原因realloc决定,即使你缩短了缓冲区,它也会给你一个不错的新副本。 因此,在坏事发生后,你在一个随机的地方坠毁1/2秒。

始终使用realloc的返回值。

===============>>#8 票数:0

我的快速提示。

代替:
void strrep(char *input, char *search, char *replace)
尝试:
void strrep(char *&input, char *search, char *replace)

而不是在身体:
input = realloc(input, strlen(input) + delta);

通常阅读将函数参数作为值/引用和realloc()描述:)传递。

  ask by Matthew Schinckel translate from so

未解决问题?本站智能推荐:

关注微信公众号