Thread: Remove all occurrences of character from string

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    10

    Remove all occurrences of character from string

    I'm new to C but not programming. I've done this in java before and it couldn't have been easier.

    I'm not sure what I don't get about C Strings thats messing this up for me. I've tried a few different ways but I feel this is closest to being correct yet doesn't run.

    Also the original string in this is not suppose to be modified so do I need to create a new variable using strcpy first before sending it to the function?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    
    
    int main (int argc, const char * argv[]) {
    	
    	
    	char* str = malloc(100); 
    	char* removeChar(char* s, char c);
    	char remove;
    
    
    	printf("Enter a string\n");
    	scanf("%s", str);
    	printf("You entered %s \n", str);
    
    
    	
    	remove = 'o';
    
    
    	removeChar(str, remove);
    	
    	printf("New Sting: %s\n", str);
    }
    
    
    char* removeChar(char* str, char c){
    	
    	char *dst;
    	int i;
    	
    	for ( i = 0; i < strlen(str) && *str != 0; i++, str++ ){
            if ( *str != c )
                *dst++ = *str;
        }
    	
    	return *str;
    }
    Thanks!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Scotty33
    Also the original string in this is not suppose to be modified so do I need to create a new variable using strcpy first before sending it to the function?
    Yes, since you want to operate on a copy of the original string. Note that strcpy alone is not good enough; you need to allocate space for the new string.

    Also, remember to free what you malloc. Since you are using malloc(100), you might want to consider just using a char[100] instead.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > i < strlen(str) && *str != 0
    This is a redundant test, since both become false at the same time.
    It's easiest if you just test *str to detect the end of the string, since you're incrementing the pointer anyway.

    The bit you're missing is *dst = '\0' to mark the end of the new string.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2011
    Posts
    10
    I updated my code but still no luck.
    When I run it I can put in the string then it fails...

    Code:
    Enter a stringthis has zero os in it
    You entered this 
    Segmentation fault
    logout

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    
    
    int main (int argc, const char * argv[]) {
    	
    	
    	char* str = malloc(100); 
    	char* removeChar(char* s, char c);
    	char remove;
    	char* str2 = malloc(strlen(str) + 1);
    
    
    	printf("Enter a string\n");
    	scanf("%s", str);
    	printf("You entered %s \n", str);
    	
    	remove = 'o';
    
    
    	removeChar(str, 'o');
    	
    	printf("New Sting: %s\n", str);
    	
    	free(str);
    	free(str2);
    	free(removeChar);
    }
    
    
    char* removeChar(char* str, char c){
    	
    	char *dst;
    	
    	while (*str != 0) {
            if ( *str != c )
                *dst++ = *str;
        }
    	
    	*dst = '\0';
    	
    	return *str;
    }
    When I compile it I get one warning "warning: return makes pointer from integer without a cast"

    I guess I'm not getting what I'm doing wrong, is it in the pointers?

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    This:
    Code:
    #include <strings.h>
    should be:
    Code:
    #include <string.h>
    You should not be calling strlen(str) until after you have read into str.

    This does not make sense because removeChar is a function:
    Code:
    free(removeChar);
    I suggest that you move the forward declaration of removeChar to before the definition of the main function.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    char* removeChar(char* str, char c){
    	
        char *dst;
    	
        while (*str != 0) {
            if ( *str != c )
                *dst++ = *str;
        }
    	
        *dst = '\0';
    	
        return *str;
    }
    1. dst does not point anywhere valid. At the start of the function, the value (address) in the area occupied by the pointer is random. When you start accessing this location, you are writing to a random location. Do you mean to set it to point to str?
    2. Note that you are not incrementing str at all in that loop.
    3. The function is supposed to return a char* value. *str is a single character. str is a char*. So, which one would you need to be returning? This is what is causing your warning "return makes pointer from integer without a cast" since it is attempting to take a char and make it a pointer to char during the return.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    A different take on it, only superficially tested.

    Code:
    int main(void) {
    
       int i=0, gap;
       char myarray[80];
    
       scanf("%[^\n]",myarray);
       while (myarray[i]!='\0') {
    	   printf("\n text %3d: %c",i,myarray[i]);
    	   ++i;
       }
       printf("\n\n");
       gap=i=0;
       while(myarray[i]) {
          if(myarray[i]== 'o') {
             gap++;
             ++i;
          }
          myarray[i-gap] = myarray[i];
          ++i;
       
       }
       myarray[i-gap]='\0';
       printf("%s", myarray);
       putchar('\n');
       return 0;
    Uses the code from the last reply (scanf() is lousy for user input), but the shifting of the letters is there.

  8. #8
    Registered User
    Join Date
    Sep 2011
    Posts
    10
    I got it working, thanks for the help guys!

    Just a few dumb logic / syntax errors and its all good.

    Code:
    #include <stdio.h>#include <stdlib.h>
    #include <string.h>
    
    
    void delChar(char* s, char c);	
    
    
    int main (){
    	
    	
    	char* str = malloc(100); 
    
    
    
    
    	printf("Enter a string\n");
    	fgets(str,100,stdin);
    	printf("You entered %s\n", str);
    	
    	char* str2 = malloc(strlen(str) +1);
    	strcpy(str2, str);
    	
    	printf("String 1 Copy: %s\n", str2);
    		
    	delChar(str2, 'o');
    	
    	printf("New String: %s\n", str2);
    	
    	free(str);
    	free(str2);
    	
    	return 0;
    }
    
    
    void delChar(char* str, char c){
    	
    	printf("You are in removeChar\n");
    	int index;
    	int length = strlen(str);
    		
    	for(index = 0; index < length; index++){
    		if(c == str[index]){
    			for (int i = index; i < length - 1; i++) {
    				str[i] = str[i+1];
    			}
    			length--;
    			index--;
    		}
    	}
    }

  9. #9
    Registered User
    Join Date
    Sep 2011
    Location
    Stockholm, Sweden
    Posts
    131
    If you want to optimize your delChar-function, you could create a new string and only copy the valid characters to it, instead of shifting the entire original string on every occurrence of character to remove.

    Code:
    void delChar(const char *, char *, char);  
      
    int main ()
    {
        char str[100], str2[100]; /* No need to malloc the memory in this case */
     
        printf("Enter a string\n");
        fgets(str,100,stdin);
        printf("You entered %s\n", str);
             
        delChar(str, str2, 'o');
         
        printf("New String: %s\nOld string: %s\n", str2, str);
      
        return 0;
    }
    
    
    void delChar(const char *src, char *dst, char c)
    {    
        while (*(src) != '\0') {
            if (*(src) != c)
                *(dst++) = *(src);    
            src++;
        }
        *(dst) = '\0';
    }

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by iceaway
    If you want to optimize your delChar-function, you could create a new string and only copy the valid characters to it, instead of shifting the entire original string on every occurrence of character to remove.
    Actually, only the remaining substring is shifted, but yes, it can be expensive. However, it is possible to perform the deletion efficiently in-place. I believe Adak's post #7 demonstrates this, though I find it easier to maintain two pointers: one for the current destination, the other for the current source character that is not to be deleted. The loop terminates when the second pointer reaches the end of the string, upon which a null character is written at where the destination pointer points to.

    EDIT:
    Looking carefully at iceaway's example, I think it implements precisely what I described, except that iceaway was not aware that the algorithm would work in-place.
    Last edited by laserlight; 09-27-2011 at 02:34 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    @iceaway:

    In my program, (#7), there is no shuffle of the char's every time that a char needs to be deleted.

    Look closely, and you'll see that it goes through the string just ONCE, and moves each char that needs to be moved, to it's final position, in a single move.

    I believe Laserlight's idea would be the most efficient, since it does no subtraction (like mine does), and is in place. Your program and mine would be VERY close. Naive programs that shuffle the entire string every time another char is deleted, would be a woeful last place.
    Last edited by Adak; 09-27-2011 at 03:52 AM.

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Adak
    There is no algorithm which is more efficient. Although an indexed auxiliary array would be about even, as would your algorithm.
    iceaway's algorithm is the same as yours. It is merely a different implementation that was used with a separate destination array instead of in-place.

    Looking at Scotty33's code from post #4, I think Scotty33 was very much on track. Compare this:
    Code:
    char* removeChar(char* str, char c){
         
        char *dst;
         
        while (*str != 0) {
            if ( *str != c )
                *dst++ = *str;
        }
         
        *dst = '\0';
         
        return *str;
    }
    with a corrected version:
    Code:
    char *removeChar(char *str, char c) {
        const char *src = str;
        char *dst = str;
    
        while (*src != '\0') {
            if (*src != c) {
                *dst++ = *src;
            }
            ++src;
        }
        *dst = '\0';
    
        return str;
    }
    Oh, but since the original string was not supposed to be modified anyway, iceaway's use of a separate array is certainly not wrong.
    Last edited by laserlight; 09-27-2011 at 04:01 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    That's why I changed my post. Since Scotty33 said he was copying the string first, I didn't worry about changing one of them.

    Copying only the chars to be kept into another array, streamlines the whole job, removing one separate copy completely. Iceaway takes the lead!

    Yes, Scotty was close. His algorithm is also a smart one.

  14. #14
    Registered User
    Join Date
    Sep 2011
    Location
    Stockholm, Sweden
    Posts
    131
    As you already stated, I took into account the fact that the original string should not be modified, which eliminated the method of doing it in-place. Interesting discussion nevertheless, I have an unhealthy passion for learning how to do the same thing in many different ways :-)

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Yes, very smartly done. You da winner!

    Great attitude to take.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 12
    Last Post: 03-07-2011, 01:24 AM
  2. Counting occurrences of a word in a string
    By mrodgers in forum C Programming
    Replies: 3
    Last Post: 03-14-2010, 11:31 AM
  3. Remove character from string
    By nooksooncau in forum C Programming
    Replies: 11
    Last Post: 06-05-2006, 09:37 AM
  4. how to remove a character from a string
    By lonbgeach in forum C Programming
    Replies: 11
    Last Post: 04-08-2004, 08:52 PM
  5. Remove a character from a string?
    By trenzterra in forum C++ Programming
    Replies: 9
    Last Post: 11-29-2002, 06:57 PM