-1

I tried to add values from user and store in char k but the for-loop is going infinite, i wonder what is wrong with the loop.

#include <stdio.h>
#include <math.h>

void main() {

  char k[5];
  for(int i=0;i<5;i++){

    printf("enter char");
    scanf("%s",&k[i]);
   
  }    
}
Siddhant
  • 626
  • 1
  • 7
  • 20
Indratej Reddy
  • 165
  • 1
  • 7
  • I don't recommend that you use `scanf` for line-based input. The function `fgets` is better for that purpose. See this guide for more information: [A beginners' guide away from scanf()](http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html) – Andreas Wenzel Aug 29 '21 at 11:13
  • i tried but i getting garbage value at the end of the string how do i remove it char k[5]; k[5]="\0"; for(int i=0;i<5;i++){ printf("enter char"); scanf(" %c",&k[i]); } printf("%s",k); } – Indratej Reddy Aug 29 '21 at 11:21
  • 2
    When describing a problem with software, always provide sample input, the output observed for that input, and the output expected for that input. There is no infinite loop in your code. It will call `scanf` five times. `scanf` will complete as soon as it receives some non-space characters followed by a space character. If you are not entering any non-space characters, such as just pressing return/enter without typing anything, then `scanf` will continue scanning. – Eric Postpischil Aug 29 '21 at 11:22
  • @IndratejReddy: The function `printf` with the `%s` format specifier requires a null-terminated character sequence. However, the character sequence you are passing to `printf` is not null-terminated. – Andreas Wenzel Aug 29 '21 at 11:24
  • how can i make it null terminated? – Indratej Reddy Aug 29 '21 at 11:26
  • If you want to make it null-terminated, you must first have room for the null terminating character. If you want to read 5 characters from the user, then you will require 6 characters in the array: 5 characters for user input and 1 character for the null terminating character. In that case, you must change `char k[5];` to `char k[6];`. Now you can write `k[5] = '\0';` after the loop, before the `printf` statement, to add the null terminator. – Andreas Wenzel Aug 29 '21 at 11:31
  • yes it worked but for k[5] , can u please explain me why that space for " %c" is changing the game? – Indratej Reddy Aug 29 '21 at 11:31
  • @IndratejReddy: Do you not understand the difference between `"%s"` and `"%c"` or do you not understand the difference between `" %c"` and `"%c"`? Or is it both that you don't understand? – Andreas Wenzel Aug 29 '21 at 11:33
  • Andreas, if i'm not using space before %c like scanf("%c"); the code is not working the way it should but if i use scanf(" %c"); the code is working fine, i wonder why space is changing the whole game and also k[5] = "\0"; for double quotes it is not working but for single quote like k[5] = '\0' it is working – Indratej Reddy Aug 29 '21 at 11:37
  • @IndratejReddy: The double quotes `"` define a string literal, which is a pointer (memory address) to a (read-only) zero-terminated string, whereas the single quotes `'` define a character literal, which represents the value of a single character, and is not a pointer. – Andreas Wenzel Aug 29 '21 at 11:40
  • 2
    @IndratejReddy: When using `"%c"`, `scanf` will extract the first character it sees on the input stream, which may be a newline character. However, if you use `" %c"` instead, then `scanf` will first extract and discard all whitespace characters (spaces, tabs, newline characters, etc.) from the stream before it extracts and writes the character to the variable you specified. Therefore, it will never write a whitespace character into that variable. – Andreas Wenzel Aug 29 '21 at 11:43
  • oh, thank u so much Andreas for ur explaination it really helped me to understand :) God bless u, how can i be in touch with u sir ur awesome – Indratej Reddy Aug 29 '21 at 11:56

2 Answers2

2

The cause of the problem could be that you are using scanf with %s which is for getting a "string - null terminated characters ". I suggest that you try using scanf with "% c" if you are only getting one character as input. note that the space is not a mistake it's there in order to say ignore any white spaces, if you want to take in whitespace delete the space before the c.

Saleh
  • 45
  • 1
  • 7
1

As already pointed out in the comments section, the problem is that the line

scanf("%s",&k[i]);

is wrong. When using scanf with the %s format specifier, it will read a whole word of input and write that word into the character array k (causing a buffer overflow in your case).

If you want to only read a single character, you should use the %c format specifier instead of %s.

However, using "%c" has the problem that it will always read the first character on the input stream, which could be a newline character. If you don't want scanf to write newline characters into your variable, you can use the format string " %c" instead. This will cause scanf to first extract and discard all whitespace characters (spaces, tabs, newlines, etc.) from the input stream before extracting and writing the character to your variable. That way, scanf will never write a newline character to your variable.

The solution described above describes how to solve your problem with scanf. However, for line-based input, using scanf is generally not recommended. See this guide for some alternatives:

A beginners' guide away from scanf()

One reason why using scanf is bad is for example the following:

Let's say that you want to input two characters from the user. Using scanf, your code might look like this:

char first, second;

printf( "Please enter the first character: " );
scanf( " %c", &first );
printf( "Please enter the second character: " );
scanf( " %c", &second );

If the user responds to the first prompt by entering several characters before pressing ENTER, then scanf will accept this input as valid and return the first character the user entered. The second call to scanf will return the second character the user entered. It will not wait for the user to enter a new line of input. In other words, scanf will take the user's response to the first prompt as an answer to the second prompt.

This example shows that scanf is not designed for reliably taking line-based input from the user. Therefore, I recommend that you use the function fgets instead. That way, you can for example reject user input if the user enters more than one character per response line.

In your case, I would recommend creating a function get_char_from_user which uses fgets instead of scanf, for example like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt )
{
    for (;;) //infinite loop
    {
        char buffer[1024], *p;

        //prompt user for input
        fputs( prompt, stdout );

        //attempt to read exactly one line of input
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            printf( "Error reading input from user!\n" );
            exit( EXIT_FAILURE );
        }

        //find the newline character, if it exists
        p = strchr( buffer, '\n' );

        //make sure that entire line was read into buffer
        if ( p == NULL && !feof(stdin) )
        {
            int c;

            printf( "The line was too long to fit buffer.\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    printf( "Unrecoverable error when reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //remove the newline character from string
        *p = '\0';

        //verify that exactly one character was entered
        if ( strlen( buffer ) != 1 )
        {
            printf( "Error: Please enter exactly one character!\n" );
            continue;
        }

        return buffer[0];
    }
}

Using this function, the example above which reads two characters from the user can be changed to the following:

char first, second;

first  = get_char_from_user( "Please enter the first character: " );
second = get_char_from_user( "Please enter the second character: " );

Now, the code is both simpler and has much better input validation.

However, in the case of your original code, it would be nice to be able to write code in such as way as that it allows you to write prompts such as

Please enter the first character:
Please enter the second character:
Please enter the third character:
Please enter the fourth character:
Please enter the fifth character:

in a loop. This would require changing the prompt parameter of the get_char_from_user to a printf format string. Afterwards, you would be able to write code like this:

int main()
{
    const char * const nth_strings[] =
        { "first", "second", "third", "fourth", "fifth" };

    char k[5];

    for ( int i = 0; i < 5; i++ )
    {
        k[i] = get_char_from_user(
            "Please enter the %s character: ",
            nth_strings[i]
        );
    }

    printf( "You entered the following characters:\n" );
    for ( int i = 0; i < 5; i++ )
    {
        putchar( k[i] );
    }
}

This is possible, by making the function get_char_from_user a variadic function, like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt, ... )
{
    for (;;) //infinite loop
    {
        char buffer[1024], *p;
        va_list vl;

        //prompt user for input
        va_start( vl, prompt );
        vprintf( prompt, vl );
        va_end( vl );

        //attempt to read exactly one line of input
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            printf( "Error reading input from user!\n" );
            exit( EXIT_FAILURE );
        }

        //find the newline character, if it exists
        p = strchr( buffer, '\n' );

        //make sure that entire line was read into buffer
        if ( p == NULL && !feof(stdin) )
        {
            int c;

            printf( "The line was too long to fit buffer.\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    printf( "Unrecoverable error when reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //remove the newline character from string
        *p = '\0';

        //verify that exactly one character was entered
        if ( strlen( buffer ) != 1 )
        {
            printf( "Error: Please enter exactly one character!\n" );
            continue;
        }

        return buffer[0];
    }
}

If you combine the last two code blocks (the function main and the function get_char_from_user) into one program, you will get the following interaction between the program and user:

Please enter the first character: Hello
Error: Please enter exactly one character!
Please enter the first character: H
Please enter the second character: e
Please enter the third character: l
Please enter the fourth character: l
Please enter the fifth character: o
You entered the following characters:
Hello

As you can see, the program rejected the input when entering several characters at once, in the same line, and prompted the user a second time.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39