Wednesday, May 29, 2013

String Reversing with C

We need to write a C program which would reverse every word in a given sentence. For example if the given string is "India is my country", the resultant output would be "aidnI si ym yrtnuoc".

Going to solve the whole problem right now, let's try a small string reversing program which would reverse whole of a given string instead of reversing each word in it.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "Program" ;
 
  /* Print Before Reversing */
  printf("\n str : %s\n",str);

  /* reverse in Place */
  str_rev(str);

  /* Print AFter Reversing */
  printf("\n Reversed str : %s\n",str);
}

/* String Reversing Function.  It does
   not work on a copy of the string

*/
str_rev( char *str)
{
  int count = strlen(str);
  int j = 0, k=count-1, l = 0;
  char ch;
  while( l < count/2)
  {
      /* character swapping */
      ch = str[j];
      str[j] = str[k];
      str[k] = ch;
     
      /* Counters */
      j++; k--; l++;
    }
}


The Output :: "margorP"

Now check how the str_rev function works. To reverse a word "Program" to "margorP", we need a loop which would run from 0 index to the exactly middle of the string.

Word length : 7 [ index 0 to 6 ]
1st pass : swap between position 0 and 6 => mrograP
2nd pass : swap between position 1 and 5 => maogrrP
3rd pass : swap between position 2 and 4 => margorP

The character at position 3 does not need to be swapped with anything. See that we have already achieved the target, hence we need to stop here, if we go ahead, the swapping will again take place like this

4th pass : swap between position 3 and 3 => margorP
5th pass : swap between position 4 and 2 => maogrrP
6th pass : swap between position 5 and 1 => mrograP
7th pass : swap between position 6 and 0 => Program

The last 4 passes would get the original string "Program" back which we do not want. Hence, we need to run the main loop till half of the length of the string. The statement "while( l < count/2)" inside str_rev() function does just that. The function str_rev() takes a pointer to a string which means the string is updated in place. It does not work on a copy of the string.

Next, we would try to identify and print each word in a given string.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "  C   is   Nice   " ;
  int i,len, letter_found ;

  len = strlen(str);
  i = 0 ;
 
  while(1)
  {
    /* This Loop below only work if it
       is a non-whitespace character

    */
    letter_found = 0;

    while(str[i] && str[i]!=' ')
    {
      printf("[%c]",str[i]);
      i++;
     
      /* Set a flag that we found some letters */
      letter_found = 1;
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
    i++;
   
    /* Print a Newline after a word is printed */
    if(letter_found) printf("\n");

  }
  
}


The output of above program is :

[C]
[i][s]
[N][i][c][e]

The above program beautifully ignores all whitespaces and shows only the non-whitespace characters found inside the string. We need the inner loop to go through a single word and print it completely. After the inner loop ends, we check for string termination and if the string does not end here we again start at the beginning of outer loop. The outer loop while(1) keeps us going with printing every word and only when the string termination character '\0' is found, we break out.

Within the inner loop, we can copy every single word to another temp array and then reverse that temp array and print.

#include "stdio.h"
#include "string.h"
main()
{

  char str[35] = "  C   is   Nice   " ;
  char temp[35];
  int i, j, letter_found ;

  i = 0 ;
  /* Outer Loop Starts */ 
  while(1)
  {
   
    j = 0;
    letter_found = 0;

    /* This Loop below only work if it
       is a non-whitespace character

    */
   
    while(str[i] && str[i]!=' ')
    {
      /* Copy to temp Array */
      temp[j++] = str[i++];
     
      /* Set a flag that we found some letters */
      letter_found = 1;
    }

    /* terminate the "temp" string */
    temp[j] = 0;

    /* a word is found */
    if(letter_found)
    {

        /* Reverse the "temp" string */
        str_rev(temp);

        /* PRINT the "temp" string */
        printf("[%s]",temp);
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
   
    /* Counter */
    i++;

  }
  
}

/* Our old String Reversing function */
str_rev( char *str)
{

  int count = strlen(str);
  int j = 0, k=count-1, l = 0;
  char ch;
  while( l < count/2)
  {
      /* character swapping */
      ch = str[j];
      str[j] = str[k];
      str[k] = ch;
     
      /* Counters */
      j++; k--; l++;
    }
}



The output is given below :

[C][si][eciN]

The code above is quite self-explanatory. We put all the read characters in array "temp" and then calling our old function str_rev() on it. 


Next, the final goal, let's reverse all words within a given string. So, we won't take help of any temp array in this. To reverse a word, we need to know its start position and end position and then we would apply the logic we used in str_rev() earlier. Check out the implementation below ::

#include "stdio.h"
main()
{

  char str[35] = "    AB ABC     ABCD  ABCDE   " ;
  int i, j, k, l, letter_found, start_pos, end_pos ;

  i = 0 ;

  /* Outer Loop Starts */ 
  while(1)
  {
   
    letter_found = 0;

    /* This Loop below only work if it
       is a non-whitespace character

    */
   
    while(str[i] && str[i]!=' ')
    {
      if( letter_found == 0 )
      {
        /* Set a flag that we found some letters */
        letter_found = 1;
       
        /* Capture the start position */
        start_pos = i;
      }
      i++;
    }

    /* a word is found */
    if(letter_found)
    {

        /* Capture the end position */
        end_pos = i-1;

        /* NOW REVERSE */
        int count = end_pos - start_pos + 1;
        char ch;
        j = start_pos, k=end_pos; l = 0;

        while( l < count/2)
        {
          /* character swapping */
          ch = str[j];
          str[j] = str[k];
          str[k] = ch;
         
          /* Counters */
          j++; k--; l++;
        }
       
    }
   
    /* Break if string ends */
    if( str[i] == '\0' )
     break;
   
    /* Counter */
    i++;

  } /* Outer Loop Ends */

  /* Now PRINT The original String */
  printf("\n [%s]",str);
  
}


The output is shown below ::
[    BA CBA     DCBA  EDCBA   ]

The stating and trailing whitespaces are maintained as this reverses each word in a given string ignoring the whitespaces.

No comments: