23

I'm attempting to remove a character from a string in C. The problem I am having with my code is that it removes the first instance of the character from the string but also wipes everything after that character in the string too. For example, removing 'l' from 'hello' prints 'he' rather than 'heo'

int i;
char str1[30] = "Hello", *ptr1, c = 'l';
ptr1 = str1;
for (i=0; i<strlen(str1); i++)
{
    if (*ptr1 == c) *ptr1 = 0;
    printf("%c\n", *ptr1);
    ptr1++;
}

I need to use pointers for this and would like to keep it as simple as possible since I'm a beginner in C. Thanks

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
boutrosc
  • 317
  • 1
  • 5
  • 11

7 Answers7

33

You can do it like this:

void remove_all_chars(char* str, char c) {
    char *pr = str, *pw = str;
    while (*pr) {
        *pw = *pr++;
        pw += (*pw != c);
    }
    *pw = '\0';
}

int main() {
    char str[] = "llHello, world!ll";
    remove_all_chars(str, 'l');
    printf("'%s'\n", str);
    return 0;
}

The idea is to keep a separate read and write pointers (pr for reading and pw for writing), always advance the reading pointer, and advance the writing pointer only when it's not pointing to a given character.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thank you for the simple answer and description, that solved it. Also thanks for everyone else's input. – boutrosc Mar 27 '12 at 18:42
  • Why http://melpon.org/wandbox/permlink/qZPdItEH7hjg4sl3 results in segmentation fault ? What's difference between `*pw=*ptr++;` and `*pw=(*ptr)++;` – Destructor Apr 27 '16 at 15:10
  • @Destructor `*pw=*ptr++` increments the pointer (correct), while `(*ptr)++` increments the character (incorrect). – Sergey Kalinichenko Apr 27 '16 at 15:21
4

If you remove the characters in place you will have to shift the rest of the string one place to the left every time you remove a character, this is not very efficient. The best way is to have a second array that takes the filtered string. For example you can change your code like this.

int i;
char str1[30] = "Hello", *ptr1, c = 'l';
char str2[30] = {0}, *ptr2;
ptr1 = str1;
ptr2 = str2;
for (i=0; i<strlen(str1); i++)
{
    if (*ptr1 != c) *ptr2++=*ptr1;
    ptr1++;
}
printf("%s\n", str2);
AliA
  • 690
  • 6
  • 8
  • 1
    Except that you should really not call `strlen()` in the condition of a loop like that, this is a good answer. Granted, that's a mistake inherited from the code in the question, but ... – Jonathan Leffler Jan 22 '14 at 01:59
  • 1
    @Jonathan Leffler, this answer makes some fundamental errors that prevent it from being a good answer. You do not have to shift the remains of the string to the left every time a character is removed. That would imply a nested loop, which the answer demonstrates is not required. Also, whether you copy the character from one string to another makes no difference, because it's all the same block of RAM. Indeed, it's probably more inefficient to use a second string, because you risk a cache miss by using a distant block of memory. – Donal Lafferty Oct 28 '14 at 15:35
2

The problem is that when you encounter the first character that matches c, you insert a null character right there. That means you're essentially cutting off the rest of the string.

What you need to do is when you find a matching character, move the following characters back one position. Then you need to insert the null character at the very end depending on how many characters you have removed.

Marlon
  • 19,924
  • 12
  • 70
  • 101
2
char str1[30] = "Hello", *prt1, c = 'l';
char str2[30], *prt2;
prt1 = str1;
prt2 = str2;
while(*prt1 != 0)
{
    if(*prt1 != c)
    {
         *prt2 = *prt1;
         prt2++;  
    }
    prt1++;
}
*prt2 = '\0';
ristonj
  • 1,590
  • 1
  • 12
  • 15
1

i know that it is a type of duplicate answer, but this code is function's version for solving the problem. I thought that as the questioner was a beginner, he might learn much from decomposed version of problem.

int del_x_char(char *p, int x)
{
    char *q;
    x=first_occurance(p, 'i')/*you can replace any character that you want delete with 'i'*/
    q=p+x;
    while(*q=*(q+1))
        q++;
    *q='\0';
    return 0;
}
int first_occurance(char *q, char phar)
{
    int i=0;
    while(*q)
    {   
        if(*q++==phar)
            return i;
        i++;
    }
    return -1;
}
eightnoteight
  • 234
  • 2
  • 11
0

just change

if (*ptr1 == c) *ptr1 = 0;

to

if (*ptr1 == c) continue;

as @ouah said, it breaks at the first NULL character..

tadeuzagallo
  • 2,422
  • 1
  • 18
  • 9
-1

C defines a string as "a contiguous sequence of characters terminated by and including the first null character"

ouah
  • 142,963
  • 15
  • 272
  • 331