c - 从字符串中删除字符并在删除时动态调整其大小的算法

标签 c algorithm

我正在编写一种算法来从动态大小的数组中删除所有引号,并在删除后减少它的长度。到目前为止,这是我的代码:

void remove_quotations(char *str)
{
    int len = strlen(str);

    for (int i = 0; i < len; i++) {
        if (str[i] == '\'') {
            for (int j = i; j < len - 1; j++) {
                str[j] = str[j + 1];
            }
            len--;
            str = realloc(str, len);
        }
    }
}

示例输入:'1357'、'name'、'topic'、'2'

预期输出:1357,名称,主题,2

我得到的是:“1357,名称,主题,2''''''''”

如您所见,引号按预期移到了末尾,但字符串并没有像它应该的那样被缩短。

注意:我不是故意做任何错误检查。

最佳答案

So as you can see the quotation marks get moved to the end as expected, but the string doesn't get shortened like it should.

好吧,得到 缩短的是分配给您的字符串的区域,这就是realloc() 所做的。您忘记缩短实际的字符串:字符串 的末尾总是有一个 \0 字节。

因此,您的程序会导致未定义的行为,例如使用 printf()puts() 输出此字符串——这些函数将读取直到找到 \0 终止符,并且它不在其中您在 realloc() 之后可以合法访问的区域。

这似乎有效的事实纯属偶然:realloc() 没有给你一个新地址,旧内容仍然存在。

您的代码中还有另一个错误:如果 realloc() 给您一个不同的地址,它将不起作用,因为调用代码无法取回指针。

旁注:

  • 在使用realloc() 时,将结果分配给一个临时变量。如果返回 NULL,则必须 free() 原始变量。

  • 您只需要在循环后一次调用realloc()


供引用,固定和注释版本:

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

char *remove_quotations(char *str)
{
    // always use the correct type, strlen returns size_t:
    // (int would only be a problem here for **huge** strings, still it's better
    //  getting used to ALWAYS use size_t for sizes.)
    size_t len = strlen(str);

    for (size_t i = 0; i < len; ++i)
    {
        if (str[i] == '\'')
        {
            // move following bytes *including* the final 0 terminator:
            memmove(str+i, str+i+1, len-i);
            --len;
        }
    }

    // include space for 0 terminator when shortening:
    char *tmp = realloc(str, len+1);
    if (!tmp)
    {
        free(str);
        return 0;
    }
    return tmp;
}

int main(void)
{
    char test[] = "'1357', 'name', 'topic', '2'";
    char *foo = malloc(strlen(test)+1);
    strcpy(foo, test);
    foo = remove_quotations(foo);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}

这个版本仍然使用您原来的结构,即在遇到的每个 ' 上移动字符串的其余部分。这并不过分有效,请参阅 mch's answer以获得更好的方法。


为了完整起见,您可以只返回原始字符串的副本,如下所示:

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

char *remove_quotations(const char *str)
{
    size_t len = strlen(str);
    char *dst = malloc(len+1);
    const char *r = str;
    char *w = dst;

    while (*r)
    {
        if (*r == '\'') --len;
        else *w++ = *r;
        ++r;
    }
    *w = 0;

    char *tmp = realloc(dst, len+1);
    if (!tmp)
    {
        free(dst);
        return 0;
    }
    return tmp;
}

int main(void)
{
    const char *test = "'1357', 'name', 'topic', '2'";
    char *foo = remove_quotations(test);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}

关于c - 从字符串中删除字符并在删除时动态调整其大小的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44823539/

相关文章:

c - 使用ffmpeg c连接视频和音频时如何计算pts和dts

c - 在C中使用OpenGL 3.0+绘制多条线

algorithm - BST遍历预序

algorithm - 通过一次更改、插入或删除一个字符将一个单词转换为另一个单词

获取页面 0x83 的 scsi id 的算法

algorithm - 难以理解彼得森的算法

python - 仅使用一个辅助数组实现合并排序(而不是递归地创建新数组)

c - 使用 pthread 时如何检查线程是否终止?

c - 在 Linux 中的特定 CPU 上运行进程? (不能用命令行指定)

c - 在 C 中使用指针提取数组的一部分