I am very new to the C programming language and I am trying to make a login thing, the problem that I am having is that I can't get the user_len to compare in my while statement.
Thank you for any and all feedback
EDIT:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct User_name{
int user_id;
char username[20];
char password[30];
} User_data;
//make all the variable
int i;
int user_len;
int pass_len;
//prototype function
char user ();
int user_name();
int main() {
//get username
user_name (User_data.username);
}
int user_name() {
while(user_len > 20) {
printf("Enter your username:\n");
scanf("%s",User_data.username);
user_len = strlen(User_data.username);
if (user_len > 20) {
printf("\nusername is too long please enter again:%d\n",user_len);
} else {
printf("Username is: %s\n",User_data.username);
}
}
return(user_len);
}
The content of the while loop will never be executed, because the condition in the line
while(user_len > 20) {
will be false at the start of the program, because user_len will have the value 0.
Also, the lines
char user ();
int user_name();
are not prototype declarations. They are forward declarations of functions that take an unspecified number of arguments. If you want to declare that they take no arguments, then you should change them to:
char user( void );
int user_name( void );
See the following question for more information:
Warning/error "function declaration isn't a prototype"
The following code has a serious problem:
printf("Enter your username:\n");
scanf("%s",User_data.username);
user_len = strlen(User_data.username);
if (user_len > 20) {
printf("\nusername is too long please enter again:%d\n",user_len);
} else {
printf("Username is: %s\n",User_data.username);
}
There is no point in checking for a buffer overflow after the buffer overflow has already occurred. The buffer overflow must be prevented in the first place, in order to prevent your program from invoking undefined behavior (i.e. to prevent your program from possibly crashing).
The easiest way to prevent the buffer overflow would be to change the scanf format string from "%s" to "%19s", which would limit the number of matched characters to 19, so that it will not write more than 20 characters to User_data.username (including the terminating null character).
However, this solution is not ideal, as it is possible that scanf will leave non-whitespace characters from that line on the input stream (this is also possible when using "%s"). These non-whitespace characters will likely cause trouble in the next loop iteration when scanf is called.
For this reason, it would probably be best if you used the function fgets instead of scanf. The function fgets has the advantage that it will always read exactly one line at a time (provided that the supplied input buffer is large enough to store the whole line), which is not necessarily the case with scanf.
Here is my solution to the problem, which uses fgets instead of scanf:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct User_name
{
int user_id;
char username[20];
char password[30];
} User_data;
//make all the variable
int i;
int user_len;
int pass_len;
//prototype function
int user_name( void );
int main( void )
{
//get username
user_name();
}
int user_name( void )
{
while( true )
{
char line[100];
char *p;
//prompt user for input
printf( "Enter your username: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
printf( "Error reading input!\n" );
exit( EXIT_FAILURE );
}
//find newline character
p = strchr( line, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( p == NULL )
{
//a missing newline character is ok on end-of-file condition
if ( !feof( stdin ) )
{
int c;
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Error reading from input\n" );
return false;
}
} while ( c != '\n' );
goto line_too_long;
}
}
else
{
//remove newline character by overwriting it with null character
*p = '\0';
}
//find length of string
user_len = strlen( line );
//check if length is acceptable
if ( user_len >= 20 )
{
goto line_too_long;
}
//username is ok, so copy it
strcpy( User_data.username, line );
//break out of infinite loop
break;
line_too_long:
printf( "Line was too long, try again!\n" );
}
//print username
printf( "Username is: %s\n", User_data.username );
return user_len;
}
This program has the following behavior:
Enter your username: ThisIsAVeryLongUserName
Line was too long, try again!
Enter your username: ShortUserName
Username is: ShortUserName
Note that this program uses one goto label and two goto statements. Normally it is a good idea to try to not use goto, but to use normal control flow statements instead. However, in this case, I believe that using goto was appropriate. The alternative would have been to duplicate the line printf( "Line was too long, try again!\n" ); and use a continue statement in two places in the program. I believe that it is better to handle this error in one place in the program (though I understand that this topic is highly controversial and that some people would consider it better to use code duplication).
Another issue worth mentioning is that you are using global variables (which I have taken over in my solution). This is considered bad programming style and should generally be avoided. Here is a modified version of my solution which avoids the use of global variables:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct user_data
{
int user_id;
char username[20];
char password[30];
};
//prototype function
int user_name( void );
int main( void )
{
//get username
user_name();
}
int user_name( void )
{
struct user_data ud;
int user_len;
while( true )
{
char line[100];
char *p;
//prompt user for input
printf( "Enter your username: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
printf( "Error reading input!\n" );
exit( EXIT_FAILURE );
}
//find newline character
p = strchr( line, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( p == NULL )
{
//a missing newline character is ok on end-of-file condition
if ( !feof( stdin ) )
{
int c;
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Error reading from input\n" );
return false;
}
} while ( c != '\n' );
goto line_too_long;
}
}
else
{
//remove newline character by overwriting it with null character
*p = '\0';
}
//find length of string
user_len = strlen( line );
//check if length is acceptable
if ( user_len >= 20 )
{
goto line_too_long;
}
//username is ok, so copy it
strcpy( ud.username, line );
//break out of infinite loop
break;
line_too_long:
printf( "Line was too long, try again!\n" );
}
//print username
printf( "Username is: %s\n", ud.username );
return user_len;
}
Related
Here's the basic skeleton of my code:
int getSentence(SearchResults* input){
printf("Enter sentence:");
fgets(input->sentence, 100, stdin);
printf("Enter message ID:");
fgets(input->messageID, 20, stdin);
return 1;
}
As is, this has a couple of problems. One is that when I print the string later, they have a newline character at the end, which I don't want. The other is that if I enter more than the 100 or 20 characters, it will overflow those characters into the next fgets call.
I've found "solutions" online, but they all either introduce new problems, or are recommended against using. Most of what I found is summarized in this SO post: How to properly flush stdin in fgets loop.
fflush works for the second problem, but is apparently "problematic".
I came up with *(strstr(input->sentence, "\n")) = '\0'; for the first issue, but it doesn't help with the second
while ((getchar()) != '\n')(and variations) is a commonly recommended solution for both problems, but it introduces a new issue: my next input requires two enters before the program will continue running. I tried adding fputc('\n', stdin); after the while loop and it solves all three problems, but only when the input exceeds the character limit. If I write a sentence less than 100 chars, I have to hit enter twice for the program to continue.
setbuf(stdin, NULL) is one of the solutions given, but one of the comments says "mucking around with setbuf is even worse [than fflush]"
I recommend that you create your own function that calls fgets, verifies that the entire line was read in and removes the newline character. If the function fails due to the input being too long, you can print an error message, discard the remainder of the line and reprompt the user. Here is a function that I have written myself for this purpose some time ago:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( !feof(stdin) && (c=getchar()) != '\n' )
{
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
if ( c == EOF )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
c = getchar();
} while ( c != '\n' );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
Here is a demonstration program in which I apply my function to your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//forward declaration
void get_line_from_user( const char prompt[], char buffer[], int buffer_size );
int main( void )
{
char sentence[100];
char messageID[20];
get_line_from_user( "Enter sentence: ", sentence, sizeof sentence );
get_line_from_user( "Enter message ID: ", messageID, sizeof messageID );
printf(
"\n"
"The following input has been successfully read:\n"
"sentence: %s\n"
"message ID: %s\n",
sentence, messageID
);
}
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( !feof(stdin) && (c=getchar()) != '\n' )
{
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
if ( c == EOF )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
c = getchar();
} while ( c != '\n' );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
This program has the following behavior:
Enter sentence: This is a test sentence.
Enter message ID: This is another test sentence that is longer than 20 characters and therefore too long.
Input was too long to fit in buffer!
Enter message ID: This is shorter.
The following input has been successfully read:
sentence: This is a test sentence.
message ID: This is shorter.
Here's what I'm using to solve my issue, thanks to Steve Summit and Andreas Wenzel for their comments.
int getSentence(SearchResults* input){
printf("Enter sentence:");
fgets(input->sentence, 100, stdin);
int temp = strcspn(input->sentence, "\n");
if(temp < 100 - 1) input->sentence[temp] = '\0';
else while ((temp = getchar()) != '\n' && temp != EOF);
printf("Enter message ID:");
fgets(input->messageID, 20, stdin);
temp = strcspn(input->messageID, "\n");
if(temp < 20 - 1) input->messageID[temp] = '\0';
else while ((temp = getchar()) != '\n' && temp != EOF);
return 1;
}
EDIT: For anyone else who has the same issue as me, see comments below for additional problems you may need to account for if you use this solution, such as fgets returning NULL.
Good afternoon, my question is conceptual. How can I make it generate a "fancy" error when the user incorrectly enters some data that does not correspond to the scanf() function? So as to only allow integers to be entered in the example below (not characters or array of characters or an inappropriate data).
For example:
#include <stdio.h>
int a;
printf("Enter a number\n");
scanf("%d", &a); //the user is supposed to enter a number
printf("Your number is %d ", a);
//but if the user enters something inappropriate, like a character, the program leads to
//undetermined behavior (which as I understand it interprets said character according to its
//value in the ASCII code).
From already thank you very much
In order to determine whether scanf was able to successfully convert the input to an integer, you should check the return value of scanf:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int num;
printf( "Enter a number: " );
if ( scanf( "%d", &num ) != 1 )
{
printf( "Failed to convert input!\n" );
exit( EXIT_FAILURE );
}
printf( "Conversion successful! The number is %d.\n", num );
}
However, using scanf for line-based user input is generally not recommended, because scanf does not behave in an intuitive manner when dealing with that kind of input. For example, scanf will generally not consume an entire line of input at once. Instead, it will generally only consume the input that matches the argument, but will leave the rest of the line on the input stream, including the newline character.
Leaving the newline character on the input stream can already cause a lot of trouble. For example, see this question.
Also, if the user enters for example 6abc, then scanf will successfully match the 6 and report success, but leave abc on the input stream, so that the next call to scanf will probably immediately fail.
For this reason, it is generally better to always read one line of input at a time, using the function fgets. After successfully reading one line of input as a string, you can use the function strtol to attempt to convert the string to an integer:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char line[200], *p;
int num;
//prompt user for input
printf( "Enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
printf( "Input failure!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert string to integer
num = strtol( line, &p, 10 );
if ( p == line )
{
printf( "Unable to convert to integer!\n" );
exit( EXIT_FAILURE );
}
//print result
printf( "Conversion successful! The number is %d.\n", num );
}
However, this code has the following issues:
It does not check whether the input line was too long to fit into the buffer.
It does not check whether the converted number is representable as an int, for example whether the number is too large to be stored in an int.
It will accept 6abc as valid input for the number 6. This is not as bad as scanf, because scanf will leave abc on the input stream, whereas fgets will not. However, it would probably still be better to reject the input instead of accepting it.
All of these issues can be solved by doing the following:
Issue #1 can be solved by checking
whether the input buffer contains a newline character, or
whether end-of-file has been reached, which can be treated as equivalent to a newline character, because it also indicates the end of the line.
Issue #2 can be solved by checking whether the function strtol set errno to the value of the macro constant ERANGE, to determine whether the converted value is representable as a long. In order to determine whether this value is also representable as an int, the value returned by strtol should be compared against INT_MIN and INT_MAX.
Issue #3 can be solved by checking all remaining characters on the line. Since strtol accepts leading whitespace characters, it would probably also be appropriate to accept trailing whitespace characters. However, if the input contains any other trailing characters, the input should probably be rejected.
Here is an improved version of the code, which solves all of the issues mentioned above and also puts everything into a function named get_int_from_user. This function will automatically reprompt the user for input, until the input is valid.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
This program has the following behavior:
Enter a number: abc
Error converting string to number!
Enter a number: 6000000000
Number out of range error!
Enter a number: 6 7 8
Unexpected input encountered!
Enter a number: 6abc
Unexpected input encountered!
Enter a number: 6
Input was valid.
The number is: 6
How to get verified user input of a specific type
#1 Get user input as a string
char s[100];
if (!fgets( s, sizeof(s), stdin )) *s = '\0';
char * p = strptok( s, "\r\n" );
if (!p) complain_and_quit();
*p = '\0';
...
Alternately:
#define __STDC_WANT_LIB_EXT2__ 1
#include <stdio.h>
char * s = NULL;
size_t n = 0;
if (getline( &s, &n, stdin ) < 0)
{
free( s );
complain_and_quit();
}
...
free( s );
#2 Get rid of any trailing whitespace
This could easily be put in a trim() function, but here we’ll spell it out:
Can’t believe I forgot this step. Sorry. 😳
p = strchr( s, '\0' );
while (p-- != s) if (!isspace( *p )) break;
p[1] = '\0';
#3 Try to convert that string to the type of thing you want.
char * p;
int user_input = strtol( s, &p, 10 );
if (*p)
{
// Input was not JUST an integer.
// It could be something like "123 xyz", or "not-an-integer".
// Look at the value of p to figure out where the conversion went wrong.
complain();
}
do_something_with_an_integer( user_input );
That’s it!
I am trying to do the exercise about the line folding in the K&R C-book, but I can't go much forward.
In particular, I do not knwo how to handle blank spaces inside the line i have to cut. The exercise is the following:
"Write a program to ''fold'' long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column."
The code i have implemented is the following:
#include <stdio.h>
#define CUT 6
int main()
{
int c, i = 0;
while ((c = getchar()) != EOF) {
if (i == CUT) {
printf(",");
putchar(c);
i = 1;
} else {
putchar(c);
i++;
}
if (c == '\n')
i = 0;
}
}
The code check the character in input while using a counter to check once it arrives to the line it needs to cut. For instance, for the line LoremIpsumissimplydummytex it will give LoremI,psumis,simply,dummyt,ext.
The condition if (c=='\n'{ i=0;} at the end of the main is used to reinitialize the counter i, used for the CUT, at every newline.
The problem is with the blank space handling: for instance i think that for the line
Lorem Ipsum (with many blank spaces), the progam should be implemented in order to print Lorem,Ipsum. But I do not understand how to write the necessary code to implement this solution.
Sorry for the length of the post and thanks in advance.
EDIT:______________________________________________________
I added some conditions to the code in order to handle the multiple blank spaces. Wanted to ask if this could be considered the right solution:
#include <stdio.h>
#define CUT 6
int main()
{
int c,i=0;
while ((c=getchar()) !=EOF){
if (i==CUT){
if (c!=' '){
putchar(c);
} else {
printf("\n");
i=1;}
} else{
putchar(c);
i++;
}
}
}
With this code, once reached the treshold CUT, if a normal character [non blank] is encounterd it is simply added to the new line to print, otherwise "\n" is printed and the counter is re-initialized to 1.
If you to split long lines into several lines, as stated in the task description, then you must print '\n' instead of ',' when encountering the cut treshold.
You should not print the character on the output stream until you know whether it should be printed on the current line or the next line. Therefore, you must store all characters until you know which line it must be printed on.
You may want to use the function isblank to determine whether a character is a space or a tab character.
In accordance with the community guidelines on homework questions, I will not provide a full solution to the problem at this time. However, if required, I will provide further hints.
UPDATE 1:
The code in your most recend edit is not correct. According to the task description, you are supposed to split the line at the last blank before the treshold, not at the first blank after the threshold.
Most of the time when you encounter a new character, you cannot know whether it belongs in the current line or in a new line. Therefore, as already stated in my answer, you must remember all characters until you know which line they belong on. You should not print a character before you know whether it belongs on the current line or the next line.
You may find it easier to solve this problem if you use fgets instead of getchar. However, the problem can also be solved with getchar.
UPDATE 2:
Since you appear to be struggling with the problem for several days, I am now providing my solutions to the problem:
Here is my solution which uses getchar:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
//this memory buffer will hold the remembered
//line contents
char line[CUT+1];
//current index
int i = 0;
//whether a blank character has been encountered in
//the current line
bool found_blank = false;
//index of the last encountered blank character
int blank_index;
//this will store the current character
int c;
//this loop will read one character per loop iteration
while ( (c=getchar()) != EOF )
{
//if we encounter the end of the line, flush the
//buffer and start a new line
if ( c == '\n' )
{
line[i] = '\0';
puts( line );
i = 0;
found_blank = false;
continue;
}
//check if new character is blank and, if it is, then
//remember the index
if ( isblank(c) )
{
blank_index = i;
found_blank = true;
}
//write new character into array
line[i] = c;
if ( i == CUT - 1 )
{
if ( !found_blank )
{
//flush buffer
line[CUT] = '\0';
puts( line );
//reset line
i = 0;
found_blank = false;
continue;
}
else // found_blank == true
{
//remember character that is going to be overwritten
char temp = line[blank_index+1];
//output everything up to and including the last blank
line[blank_index+1] = '\0';
puts( line );
//move unwritten characters to start of next line
i = CUT - 1 - blank_index;
line[0] = temp;
memmove( line + 1, line+blank_index+2, i );
found_blank = false;
continue;
}
}
i++;
}
//check stream for error
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//if we reach this, then we must have encountered
//end-of-file
assert( feof( stdin ) );
//flush buffer
line[i] = '\0';
puts( line );
}
Here is my solution which uses fgets:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
char line[CUT+2];
size_t leftovers = 0;
//in every iteration of the loop, we write one line of output
for (;;)
{
size_t blank_index;
bool found_blank = false;
if ( fgets( line + leftovers, sizeof line - leftovers, stdin ) == NULL )
{
//print all leftovers
line[leftovers] = '\0';
printf( "%s\n", line );
break;
}
size_t len = strlen( line );
//this check is probably not necessary
assert( len != 0 );
if ( line[len-1] == '\n' )
{
//we read a complete line, so print it
printf( "%s", line );
leftovers = 0;
continue;
}
//if we reach this, then input line was not read in
//completely, or we are dealing with the last line before
//end-of-file or input failure
//find last blank
for ( size_t i = 0; line[i] != '\0'; i++ )
{
if ( isblank( (unsigned char)line[i] ) )
{
found_blank = true;
blank_index = i;
}
}
if ( !found_blank )
{
if ( len <= CUT )
{
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//we should only reach this if end-of-file was
//encountered in the middle of a line
assert( feof(stdin) );
printf( "%s\n", line );
break;
}
//remember last character
char temp = line[len-1];
line[len-1] = '\n';
printf( "%s", line );
line[0] = temp;
leftovers = 1;
}
else
{
//remember character after last blank
char temp = line[blank_index+1];
//replace character after last blank with terminator
line[blank_index+1] = '\0';
//print line up to and including last blank
printf( "%s\n", line );
if ( temp != '\0' )
{
//move unprinted characters to start of next line
line[0] = temp;
leftovers = len - blank_index - 1;
memmove( line + 1, line + blank_index + 2, leftovers - 1);
}
else
{
leftovers = 0;
}
}
}
}
It appears that my initial advice of using fgets instead of getchar was not very good, as the fgets solution turned out to be slightly more complicated than the getchar solution.
Here is some sample input and output of both programs (both programs behave the same way):
Sample input:
This is a line with several words.
Thisisalinewithonelongword.
Sample output:
This is a
line with
several
words.
Thisisalin
ewithonelo
ngword.
void openMenu(int *op) {//edited
do {
printf("Your turn...\t\n");
scanf(" %d", op);
if (*op > 14 || *op < 1 ) {
printf("Only enter a number between 1 and 14!\n");
}
} while (*op > 14 || *op < 1 );
}
I am trying to make a checking loop which controls if the value which was entered is between 1 and 14. If there are letters it has to repeat too, the enter process.
Perhaps it isn't working and everytime it goes in the second run the scanf didn't run.
I checked the thing to set a space in front of the %d, but it isn't working too...
Did u have maybe a nice idea?
Working with Xcode on Mac 11.1
You need to check the returning value of your scanf:
#include <stdio.h>
void openMenu(int *op) {//edited
do {
printf("Your turn...\t\n");
if (scanf(" %d", op) != 1 || *op > 14 || *op < 1 ) {
while(getchar()!='\n'); // clean the input buffer
printf("Only enter a number between 1 and 14!\n");
}
} while (*op > 14 || *op < 1 );
}
int main()
{
int op;
openMenu(&op);
printf("Number Read {%d}\n", op);
return 0;
}
A more robust (and complicated) solution would be the following:
int isNumber(char buffer[]){
for(int i = 0; buffer[i] != '\0'; i++)
if(!isdigit((unsigned char) buffer[i]))
return 0;
return 1;
}
int readInput(char buffer[]){
int result = scanf("%99s", buffer);
while(getchar()!='\n');
return result;
}
int isInRange(int *op, char buffer[]){
*op = atoi(buffer);
return *op <= 14 && *op >= 1;
}
void openMenu(int *op) {
do {
char buffer[100];
if(readInput(buffer) && isNumber(buffer) && isInRange(op, buffer)) {
break;
}
printf("Only enter a number between 1 and 14!\n");
} while (1);
}
This would avoid that input such as 4odgjlda would be considered a valid number. Nevertheless, with the current approach inputs such as 4 odgjlda would still be considered as a valid input, since scanf would read the first word and not the entire line. For a more robust solution you should use fgets instead. One can see an example of such solution on the answer provided by Andreas Wenzel.
The problem is that if you enter something like "sdfokhs" the first time, then scanf will not be able to match any integer and will return 0. Because scanf did not consume this invalid input from the input stream, calling scanf a second time won't cause the user to be prompted for new input. Instead, scanf will attempt again to match an integer from the non-consumed input, and will fail again for the same reason as the fist time. This means you have an infinite loop.
Therefore, to fix this, you must consume the rest of the line before calling scanf again, for example like this:
while ( fgetc( stdin ) != '\n' ) ;
Or, if you want more robust error checking:
int c;
do
{
c = fgetc( stdin );
if ( c == EOF )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
Also, it is always a good idea to check the return value of scanf.
However, in this case, I don't recommend using scanf. It would make more sense to always read exactly one line of input per loop iteration, using fgets. The disadvantage of using scanf is that it may read several lines of input per iteration, or only part of one line, which requires you to consume the rest of the line.
The following solution is longer than the solution of all other answers, but it is also the one with the most robust input validation and error handling.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINESIZE 100
void openMenu(int *op)
{
char buffer[MAX_LINESIZE];
char *p;
long converted;
//goto label
try_again:
//prompt user for input
printf( "Please enter number between 1 and 14: " );
//read line of input into buffer
if ( fgets( buffer, MAX_LINESIZE, stdin ) == NULL )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
//make sure that a full line was read and remember position of newline character
p = strchr( buffer, '\n' );
if ( p == NULL )
{
int c;
printf( "Input was too long!\n" );
//attempt to consume input until newline character found
do
{
c = fgetc( stdin );
if ( c == EOF )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
goto try_again;
}
//remove newline character from string
*p = '\0';
//convert string to number
converted = strtol( buffer, &p, 10 );
//make sure conversion was successful
if ( p == buffer )
{
printf( "Only enter a number!\n" );
goto try_again;
}
//verify that remainder of line is whitespace
while ( *p != '\0' )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Only enter a number!\n" );
goto try_again;
}
p++;
}
//verify that number was in the correct range
if ( converted < 1 || converted > 14 )
{
printf( "Only enter a number between 1 and 14!\n" );
goto try_again;
}
//since all tests were passed, write the value
*op = converted;
}
Note that using goto should normally not be done, if a loop can be used just as well. However, in this case, I believe it is the cleanest solution.
as i can see you are comparing the *op (which i assume is a pointer).
so, check if you have already assigned the value to the predefined variable or not.
It somewhat should look like this.
int value = 0;
int *op = &value;
do {
printf("Your turn...\t\n");
scanf(" %d", op);
if (*op > 14 || *op < 1 ) {
printf("Only enter a number between 1 and 14!\n");
}
}while (*op > 14 || *op < 1 );
i am trying to create a looping which keeps looping till "only" newline charater is inputted or maybe just a space (until nothing is entered to the input line).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
while(1)
{
scanf("%d",&num);
if(num==NULL)
break;
printf("%d",num);
}
return 0;
}
You can't do that with scanf (at least not easily). If you want to process user input, scanf is a bad choice (in fact, in all my years of developing in C, I've never used scanf; I recommend you avoid it altogether).
num==NULL makes no sense: num is a number, but NULL is a pointer value. If you want to check whether scanf was successful, you need to check its return value.
I'd do something like:
char line[100];
while (fgets(line, sizeof line, stdin)) { // read input line by line
int num;
if (sscanf(line, "%d", &num) != 1) { // the line didn't start with a valid integer
break;
}
printf("%d\n", num);
}
If you want to check specifically for an empty string, not just something that doesn't look like a number, you could use strspn:
if (line[strspn(line, " \t\n")] == '\0') {
// line contains spaces / tabs / newlines only
There are other things that can be on a line other than an integer. Your code indicates an integer expected, but your text only indicates the line is blank or only contains a space.
Given your text in the question:
#include <stdio.h>
#include <string.h>
int main( void )
{
char line[1024];
while( fgets( line, sizeof( line ), stdin ) )
{
if( (strlen( line ) == 1 )
|| (strlen( line ) == 2 && line[0] == ' '))
{
// all done
break;
}
else
{
// process line
}
} // end while
}