Thread: A little help with string manipulation

  1. #1
    Registered User
    Join Date
    Nov 2005
    Posts
    18

    A little help with string manipulation

    Basically, what I'm trying to do is take a line of text from the user as input, then spew it back, but with "I am" replaced with "You are". There are a few printf's in here that are just there to show me what my own program is doing, for debugging purposes, but I can't seem to get this code working with more than one "I am" in the input, even though it should. I know there are some things I could be doing more efficiently, so if you see them, please point them out.

    Please have a look and tell me what you think I should change. Thanks in advance

    Code:
    #include <stdio.h>
    #include <string.h>
    
    char    recent[99];
    
    int main(void) {
        int     i, q[3], w = 0, x, b[3];
        
        /* Set arrays to zero */
        for (i = 0; i <= 99; ++i) {
            recent[i] = -1;
        }
        for (i = 0; i <= 3; ++i) {
            q[i] = -1;
            b[i] = 0;
        }
        
        /* Get a string from the user, then check for 'I' */
        fgets(recent, 100, stdin);
        recent[(strlen(recent) - 1)] == '\0';
        for (i = 0; i <= 99; ++i) {
            if (recent[i] == 'I') {
                q[w] = i;
                ++w;
            }
        }
        
        /* Check to see if 'I' is followed by ' am' */
        for (i = 0; i <= 3; ++i) {
            if (recent[(q[i] + 1)] == ' ') {
                if (recent[(q[i] + 2)] == 'a') {
                    if (recent[(q[i] + 3)] == 'm') {
                        printf("\nq[%i] is an \"I am\" statement.", i);
                        b[i] = 1;
                    }
                }
            }
        }
        
        /* Replace 'I am' with 'You are' */
        for (i = 0; i <= 3; ++i) {
            if (b[i] == 1) {
                for (x = 99; x >= q[i]; --x) {
                    recent[(x + 3)] = recent[x];
                }
                recent[(q[i])] = 'Y';
                recent[(q[i] + 1)] = 'o';
                recent[(q[i] + 2)] = 'u';
                recent[(q[i] + 3)] = ' ';
                recent[(q[i] + 4)] = 'a';
                recent[(q[i] + 5)] = 'r';
                recent[(q[i] + 6)] = 'e';
            }
        }
        
        printf("\n\nq[0] = %i\nq[1] = %i\nq[2] = %i\nq[3] = %i\n", q[0], q[1], q[2], q[3]);
        printf("\n\nb[0] = %i\nb[1] = %i\nb[2] = %i\nb[3] = %i\n", b[0], b[1], b[2], b[3]);
        
        /* Print final text */
        printf("\n%s\n", recent);
        
        /* System pauses */
        printf("\n");
        system("PAUSE");
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    use strstr() function to check for string "I am".
    Code:
    char* ptr;
    while( (ptr = strstr(recent,"I am")) != NULL)
    {
       // replace stirng here
       char tmp[100];
       // copy string starting after "I am"
       strcpy(tmp,ptr + 4);
       // truncate remainder of string in original buffer
       *ptr = 0;
       // add "You are"
       strcat(recent,"You are");
       // add back original string
       strcat(recent,temp);
    }

    also this line needs assignment operator '=', not logical operator "=="
    Code:
    recent[(strlen(recent) - 1)] == '\0';
    Last edited by Ancient Dragon; 11-04-2005 at 05:41 AM.

  3. #3
    Registered User
    Join Date
    Nov 2005
    Posts
    18
    Thank you. I will make these adjustments and see if I can get the code to work fully now

    EDIT: Yep, it works. Thanks for that. I'm gonna change it a little so that if the "You are" doesn't start the scentence, it's not uppercase. I'll post the code here when I'm done, just for future refference

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
        int     i;
        char    recent[99], temp[99];
        char*   ptr;
        
        /* Set arrays to zero */
        for (i = 0; i <= 99; ++i) {
            recent[i] = 0;
            temp[i] = 0;
        }
        
        /* Get a string from the user and strip newline */
        fgets(recent, 100, stdin);
        recent[(strlen(recent) - 1)] = '\0';
        
        /* Find "I am" and replace with "You are" */
        while ((ptr = strstr(recent, "I am")) != NULL) {
            strcpy(temp, ptr + 4);
            *ptr = 0;
            strcat(recent, "you are");
            strcat(recent, temp);
        }
        
        /* Check if "y" begins scentence */
        if (recent[0] == 'y') {
            recent[0] = 'Y';
        }
        
        /* Print final text */
        printf("\n%s\n", recent);
        
        /* System pauses */
        printf("\n");
        system("PAUSE");
        return 0;
    }

    Thanks again. The strstr() function wasn't under the strings tutorial, so I had no idea it existed, but I've had a bit of a muck around with it now.
    Last edited by InvertedSaint; 11-04-2005 at 06:23 AM.

  4. #4
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    here is another example of how to do it without using a temporary variable. just shift all characters right (or left) to expand (or contract) the string, making more (or less) space to add the new string
    Code:
    int main()
    {
      char recent[100] = "Hello I am the one I am the two";
      char* search_string = "I am";
      char* replace_string = "you are";
      char* ptr;
      int delta_len = strlen(replace_string) - strlen(search_string);
      while ((ptr = strstr(recent, search_string)) != NULL) {
    	    // width the string by 1 character.  This could either
    	    // make the string longer or shorted, dependong on the
    	    // size of each of the two strings
            memmove(ptr+delta_len,ptr,strlen(ptr)+1);
    		// copy new text
            memcpy(ptr,replace_string,strlen(replace_string));
        }
    	return 0;
    }

  5. #5
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    AD: you've got some issues when the replacement string is shorter that the search string.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You've also got issues in that memmove doesn't allocate any space, so your "making it longer" doesn't really do that. All you do is move stuff around. You're screwed if your initial buffer isn't big enough to handle all of the replacements.


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    Quote Originally Posted by quzah
    You've also got issues in that memmove doesn't allocate any space, so your "making it longer" doesn't really do that. All you do is move stuff around. You're screwed if your initial buffer isn't big enough to handle all of the replacements.


    Quzah.
    yes, its true that memmove doesn't allocate space, but it doesn't have to. The space is already allocated. The algorithm is making the null-terminated string longer, not changing the size of the buffer. The danger with memmove(), memcpy(), strcpy() and most other C string handling fucntions is that they make no sanity checks for buffer overflow, which is why I always make the destination buffer somewhat larger than actually needed. You will notice in the posted program the destination buffer is 100 bytes, sufficent size for the strings in the OPs program. Adjust the size of the destination buffer as needed to accommodate larger strings.

    Dave: It worked ok on the strings I tested. Just make the replacement string shorter than the search string. I didn't notice any problems with the end result, but there might be with some other strings or when the search string appears at the beginning of the buffer.

    And for the benefit of new programmers, neither altorithm I posted works with string literals because the length of those strings cannot be changed.
    Last edited by Ancient Dragon; 11-04-2005 at 11:05 AM.

  8. #8
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    #if 0
       char recent[100] = "Hello I am the one I am the two";
       char* search_string = "I am";
       char* replace_string = "you are";
    #else
       char recent[100] = "Hello you are the one you are the two";
       char* search_string = "you are";
       char* replace_string = "I am";
    #endif
       char* ptr;
       int delta_len = strlen(replace_string) - strlen(search_string);
       puts(recent);
       while ( (ptr = strstr(recent, search_string)) != NULL )
       {
          // width the string by 1 character.  This could either
          // make the string longer or shorted, dependong on the
          // size of each of the two strings
          memmove(ptr+delta_len,ptr,strlen(ptr)+1);
          // copy new text
          memcpy(ptr,replace_string,strlen(replace_string));
       }
       puts(recent);
       return 0;
    }
    
    /* my output
    Hello you are the one you are the two
    HelyouI am the oyouI am the two
    */
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  9. #9
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    this will fix it
    Code:
       while ( (ptr = strstr(recent, search_string)) != NULL )
       {
          // width the string by 1 character.  This could either
          // make the string longer or shorted, dependong on the
          // size of each of the two strings
    	   if(delta_len > 0)
    	   {
    			memmove(ptr+delta_len,ptr,strlen(ptr)+1);
    			// copy new text
    			memcpy(ptr,replace_string,strlen(replace_string));
    	   }
    	   else
    	   {
    			memmove(ptr,ptr-delta_len,strlen(ptr-delta_len)+1);
    			// copy new text
    			memcpy(ptr,replace_string,strlen(replace_string));
    
    	   }
       }

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    int main(void) {
        int     i;
        char    recent[99], temp[99];
        char*   ptr;
        
        /* Set arrays to zero */
        for (i = 0; i <= 99; ++i) {
            recent[i] = 0;
            temp[i] = 0;
        }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Is it better to use memcpy over memmove when the buffers will not overlap? Is memcpy faster?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  12. #12
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    if you know the buffers do not overlap then memcpy is ok, and faster too.

    This is also a lot faster way to clear buffers because it does not involve c loops. As noted by someone else a while back this is not such a good thing to do with integer or float arrays.
    Code:
    int main(void) {
        int     i;
        char    recent[99], temp[99];
        char*   ptr;
        memset(recent,0,sizeof(recent));
        memset(temp,0,sieof(temp));

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    That's what I thought (about memcpy). Thanks.

    this is not such a good thing to do with integer or float arrays.
    I think it's okay if you're setting it to zero. Isn't it?

    BTW, you have sieof instead of sizeof.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Couldn't you just go like this?
    Code:
    char recent[99] = {0};
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  15. #15
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by dwks
    I think it's okay if you're setting it to zero. Isn't it?
    http://www.eskimo.com/~scs/C-faq/q7.31.html
    The zero fill is all-bits-zero, and does not therefore guarantee useful null pointer values or floating-point zero values.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ ini file reader problems
    By guitarist809 in forum C++ Programming
    Replies: 7
    Last Post: 09-04-2008, 06:02 AM
  2. Compile Error that i dont understand
    By bobthebullet990 in forum C++ Programming
    Replies: 5
    Last Post: 05-05-2006, 09:19 AM
  3. Replies: 4
    Last Post: 03-03-2006, 02:11 AM
  4. Linked List Help
    By CJ7Mudrover in forum C Programming
    Replies: 9
    Last Post: 03-10-2004, 10:33 PM
  5. string manipulation
    By SPEKTRUM in forum Linux Programming
    Replies: 3
    Last Post: 01-26-2002, 11:41 AM