1

I wrote a program to replace a letter in a string. Although it has no error, the output is not as expected. Please help me with it.

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<string.h>
void replace(char s,char d);
char a[100];
int main()
{
    char b,r;
    printf("enter the string\n:");
    gets(a);
    printf("enter the the letter to be replaced\n:");
    scanf("%c", &b);
    printf("enter the letter to be replaced with\n:");
    scanf("%c", &r);
    replace(b,r);
}
void replace(char s, char d)
{
    int i,f=0;
    for (i = 0; a[i] != '\0'; i++)
    {
        if (a[i] == s)
        {
            a[i] = d;
            f = 1;
        }
    }
    if (f == 0)
    {
        printf("letter not found");
    }
}

Output

enter the string
:hello every one
enter the the letter to be replaced 
:e
enter the letter to be replaced with
:letter not found

I wanted to replace e with o but I am not able to give the input for word to be replaced

UPDATE Use this loop to get rid of the input buffer problem when using scanf but I am not sure how to implement it on my program need help

void
clear(void)
    {    
    while ( getchar() != '\n' )
        ;
    }
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
steven thomas
  • 61
  • 1
  • 11
  • 2
    `scanf("%c", &r)` is actually called with stdin pointing to the newline. Look at http://stackoverflow.com/q/7898215/1084879 for more information on how to read till the end of the line correctly. – zapstar Oct 17 '16 at 04:26
  • @zapstar I got it , it said to write a loop with while `void clear (void) { while ( getchar() != '\n' ); }` how to implement it to my program – steven thomas Oct 17 '16 at 04:57
  • I don't know if this works on Windows. Usually I use `scanf("%c%*c", &r)` instead. – zapstar Oct 17 '16 at 05:06
  • @zapstar can you explain me how it works I didn't understand `*c` what this helps – steven thomas Oct 17 '16 at 05:13
  • Please note that [`gets()` is too dangerous to be used — ever!](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) – Jonathan Leffler Oct 17 '16 at 05:20
  • You can use `" ^c"` in place of `"%c"` in the `scanf()` calls. The leading blank skips white space, including newlines, and gets a non-white space character, which is probably what you wanted. You could also type `eo` as a response to the first prompt and it would at least get the right information into your variables. – Jonathan Leffler Oct 17 '16 at 05:22
  • 1
    The idea behind `"%c%*c"` is that it reads two characters, assigns the first to `r` (in the call where it is illustrated), and suppresses the second assignment. If there is a newline after the letter, the newline is consumed. However, if the user typed `eo` on the line, then the `e` is returned, the `o` is consumed and the newline is still in the way to mess up the rest. There's no way to know whether the `%*c` successfully consumed a character (but there aren't many ways for it to fail, either). – Jonathan Leffler Oct 17 '16 at 05:24
  • @JonathanLeffler thankyou for the explanation – steven thomas Oct 17 '16 at 05:35
  • If you set a breakpoint at the top of main and hold your mouse over the variables as you step through the code with F10, it will tell you what each variable holds and it would have shown you that scanf was not working how you expected. Just an fyi for next time. – Millie Smith Oct 17 '16 at 06:03

1 Answers1

2

The scanf() function skips over initial whitespace characters when you read in strings using the %s specifier, but it does not do this when your read chars with the %c specifier. The gets() function that you use (which you should never ever ever use ever) reads through the newline, and discards it. So your first call to scanf() has a clean input stream. When you call scanf() the first time, a value is read into the variable b, but the trailing newline is left behind in the input stream. Then, when you try to read the next value, scanf() picks up this newline, instead of the value that you want to enter.

One fix for this is to discard any unwanted characters from the input stream like this:

while (getchar() != '\n')
    continue;              // discard unwanted characters

You can also test for the EOF character in the conditional expression if you really want to be careful. One virtue of this approach is that, no matter how many characters the user enters at your second prompt, only the first is taken, and the remaining characters through the newline are discarded. Since there is nothing left in the input stream, scanf() has to wait for the user to enter something at your third prompt. You should place this code after each call to scanf() to make sure that the input stream is clear.

Now, gets() is a terrible and unsafe function begging for buffer overflows, because it doesn't check to see if there is enough memory allocated for the string it is getting. Instead, use fgets(). This function takes an argument that specifies the maximum number of characters to read, including the null-terminator. fgets() also reads the newline character into the string, so you have to dispose of that yourself if you don't want it. Here are the modifications you need to make:

int i = 0;
...
char b,r;
printf("enter the string\n:");
fgets(a, 100, stdin);

while(a[i] != '\n' && a[i] != '\0')  // remove newline
    ++i;
a[i] = '\0';

printf("enter the the letter to be replaced\n:");
scanf("%c", &b);
while (getchar() != '\n')
    continue;              // discard unwanted characters

printf("enter the letter to be replaced with\n:");
scanf("%c", &r);
while (getchar() != '\n')
    continue;              // discard unwanted characters

replace(b,r);
printf("%s\n", a);
...

I added a final printf() to display the changed string.

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
  • what does continue means ? same as i++ then break ?-@DavidBowling – steven thomas Oct 17 '16 at 05:32
  • @steventhomas: time to find your C book, or manual. `continue` is a standard C statement that goes to the next iteration of the loop, executing the third part of a `for` loop and then going (back) to the condition. (So, in `for (i = 0; i < 10; i++)`, a `continue;` executes the `i++` before reevaluating the `i < 10` condition. In a `while (i < 10)`, it simply jumps to the condition; in a `do { … } while (i < 10);` it jumps to the condition. – Jonathan Leffler Oct 17 '16 at 05:35
  • The `continue` statement just jumps to the end of the loop body. It isn't really needed here, the loop would continue anyway, but it is a way of explicitly stating what is happening. I could have just used a semicolon instead of `continue;`, but an empty loop body isn't very descriptive. – ad absurdum Oct 17 '16 at 05:36