在C中过滤字符串中的字符

时间:2016-03-01 19:43:42

标签: c string filter malloc

下面是一个函数,它应该从字符串中过滤出给定的字符ch,并将过滤后的版本放在结果中。底部的puts语句最终会输出与原始字符串相同的字符串,而不管过滤后的字符是什么,结果最终为空。

void filter_ch_index(char string[], char result[], char ch) {
    result[0] = NUL ; // placeholder
    int i;
    for(i = 0; i < strlen(string); i++)
    {
        if(string[i] != ch)
        {
          result[i] = string[i];
        }
    }
    puts(result);
}

2 个答案:

答案 0 :(得分:1)

其中一个问题是你的复制逻辑。

如果字符不同,则不要将其复制到result,但无论如何都会增加i 。这会在result字符串中留下漏洞。要解决这个问题,可以使用指针(引用和增量)。

我看到的另一个问题是你如何调用这个功能。你为两者分配了足够的内存空间吗?

我会使用非常不安全的函数实现来展示你如何做到这一点。您应该修改函数以考虑字符串大小。

#include <stdio.h>

void filter(char *a, char *b, char c)
{
    char *aux = b;
    while(*a) {
        if(*a != c) *b++ = *a;
        a++;
    }
    *b = 0x0; // thx to @PaulRoub for pointing it out
    puts(aux);
}

int main(int argc, char *argv[])
{
    char buffer[100];

    if(argc < 3) {
        printf("Usage: %s <string> <character>\n", argv[0]);
        return 0;
    }

    filter(argv[1], buffer, argv[2][0]);
    return 0;
}

在上面的代码中,aux用作b起始地址的备份。 while循环将继续显示,而当前a字符不是\0(您可以将其视为while (*a != '\0'))。条件也非常简单。复制部分是我之前谈到的。

如果我们将某些内容复制到其中,我们只会增加b字符串,否则,它的引用会保持不变。该过程将继续,直到循环在\0字符串中找到a终止字符。

输出:

[ ~/src/test ] $ ./filter "Stack Overflow Questions" e
Stack Ovrflow Qustions
[ ~/src/test ] $ ./filter "Stack Overflow Questions" S
tack Overflow Questions
[ ~/src/test ] $ ./filter "Stack Overflow Questions" s
Stack Overflow Quetion
[ ~/src/test ] $ ./filter "aaa bbb ccc abc cba" a     
 bbb ccc bc cb
[ ~/src/test ] $ ./filter "aaa bbb ccc abc cba" b
aaa  ccc ac ca
[ ~/src/test ] $ ./filter "aaa bbb ccc abc cba" c
aaa bbb  ab ba
[ ~/src/test ] $  

答案 1 :(得分:1)

您需要两个索引,即您正在阅读的索引以及您要写入的索引:

void filter_ch_index(char string[], char result[], char ch)
{
    int j = 0;
    for (int i = 0; string[i] != '\0'; i++)
    {
        if (string[i] != ch)
            result[j++] = string[i];
    }
    result[j] = '\0'
    puts(result);
}

这假设result足够大。请注意,复制函数中参数的最常见顺序是“目标,来源”(请参阅​​strcpy()memmove(),...),但您的顺序是相反的。

请注意,使用原始for(i = 0; i < strlen(string); i++)是一个坏主意。在循环条件中使用strlen()将线性算法转换为二次算法,除非您有足够复杂的编译器来发现字符串的长度在循环的每次迭代中都不会改变。 (战争故事:一个又一个千年,有一个strstr()的实现,包括一个类似的循环条件。它在小字符串上工作正常 - 比如100字节以下;当用在20 KiB的字符串上时是一个灾难大多数平台都很好 - 这个没有。这个bug早就被修复了。)

请注意,您可以安全地修改源字符串;输出字符串永远不会长于源字符串。这可以避免缓冲区溢出,除非源字符串本身无效(不是以null结尾)。 void replace_ch(char *string, char ch)是界面。上面的函数可以用void filter_ch_index(const char string[], char result[], char ch)编写,const表示函数不会修改源字符串。