代码之家  ›  专栏  ›  技术社区  ›  PoVa

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

  •  1
  • PoVa  · 技术社区  · 9 年前

    我正在编写一个算法,从动态大小的数组中删除所有引号,并在删除时减少其长度。以下是我目前的代码:

    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);
            }
        }
    }
    

    Example input: '1357', 'name', 'topic', '2'

    Expected output: 1357, name, topic, 2

    What I get: "1357, name, topic, 2''''''''"

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

    5 回复  |  直到 9 年前
        1
  •  3
  •   user2371524 user2371524    9 年前

    正如您所看到的,引号按预期移动到了末尾,但字符串没有按预期缩短。

    嗯,什么 得到 realloc() 做忘记缩短实际字符串:A 一串 \0 字节结束。

    例如,当您使用 printf() puts() \0 realloc()

    这似乎是完全偶然的: realloc() 没有给你一个新地址,旧的内容仍然存在。

    realloc()

    旁注:

    • 使用时 realloc() 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;
    }
    
        2
  •  2
  •   mch    9 年前

    void remove_quotations(char *str)
    {
        int j = 0;
        for (int i = 0; str[i]; i++) {
            if (str[i] != '\'') {
                str[j++] = str[i];
            }
        }
        str[j] = 0;
    }
    

    这就是你要做的一切。

    工作示例: http://ideone.com/TU5LOS

        3
  •  1
  •   Valy    9 年前

    我假设您使用这样的方法来检查字符串的内容:

    printf("%s\n", str);
    

    所以,问题是 printf \0 性格

    我会像这样更新你的函数:

    char* remove_quotations(char *str)
    {
        int len = strlen(str);
        char *str_temp;
    
        for (int i = 0; i < len; i++) {
            if (str[i] == '\'') {
                /* go until len so that you shift the '\0' one position to the left */
                for (int j = i; j < len; j++) {
                    str[j] = str[j + 1];
                }
                len--;
                /* no need to call realloc here every time */
            }
        }
    
        str_temp = realloc(str, len + 1);
        if (!str_temp) {
            printf("Memory allocation error!\n");
            free(str);
    
            return NULL;
        }
    
        return str_tmp;
    }
    
        4
  •  0
  •   unalignedmemoryaccess    9 年前

    0 在新字符串的末尾:

    for (int j = i; j < len - 1; j++) {
        str[j] = str[j + 1];
    }
    str = realloc(str, len);
    if (str) {
        str[j] = 0; //String ends with 0, so force 0 at the end of string.
    }
    

    关键是你必须手动 0 结尾的字符。

        5
  •  0
  •   Chirag    9 年前

    最后需要放置“\ 0”,

    放在下面一行,

    str[j]='\0';

    len--