I'm coming from Python and there you can easily compare two strings (char arrays) like that:
if "foo" == "bar":
# ...
How would I do this in C? I already saw this post but it didn't work.
Code:
int main(void) {
char string[100];
printf("Please enter something: ");
fgets(string, 100, stdin);
if (strcmp(string, "a") == 0)
printf("a");
else if (strcmp(string, "b") == 0)
printf("b");
else if (strcmp(string, "c") == 0)
printf("c");
else
printf("something else");
return (0);
}
It prints "something else" though I entered a.
The function fgets can append to the entered string the new line character '\n' that you should remove. For example
fgets(string, 100, stdin);
string[ strcspn( string, "\n" ) ] = '\0';
or
fgets(string, 100, stdin);
char *p = strchr( string, '\n' );
if ( p != NULL ) *p = '\0';
From the C Standard (7.21.7.2 The fgets function)
2 The fgets function reads at most one less than the number of
characters specified by n from the stream pointed to by stream into
the array pointed to by s. No additional characters are read after a
new-line character (which is retained) or after end-of-file. A null
character is written immediately after the last character read into
the array.
The fgets() also takes in the newline character when the user presses the Enter key. So in order to remove that from what is stored in `string[100], just change :
fgets(string, 100, stdin);
to
strtok(fgets(string, 100, stdin), "\n");
to remove the newline character. Just make sure to include the #include <string.h> header
Further Reading
If you are wondering what strtok does, have a look at https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
The C library function char *strtok(char *str, const char *delim)
breaks string str into a series of tokens using the delimiter delim.
char *strtok(char *str, const char *delim)
You could answer this question yourself if you did put some research effort.
int main(void) {
char string[100];
printf("Please enter something: ");
fgets(string, 100, stdin);
if (strcmp(string, "a") == 0)
printf("a");
else if (strcmp(string, "b") == 0)
printf("b");
else if (strcmp(string, "c") == 0)
printf("c");
else
{
printf("something else - lets check why:\n Entered string:\n");
for(size_t n = 0; n <= strlen(string); n++)
{
printf("string[%2zu] = ", n);
switch(string[n])
{
case '\n':
printf("\\n");
break;
case '\r':
printf("\\r");
break;
case 0:
printf("null char");
break;
default:
if(string[n] < ' ' || string[n] > 127)
{
printf("\\x%x", (unsigned)string[n]);
}
else
printf("'%c'", string[n]);
}
printf("\n");
}
}
return (0);
}
https://godbolt.org/z/afb3Ej7E9
Related
I've made a user-defined function for reading input and replacing newline character '\n' with '\0' so when I use printf statement for printing the string it won't add newline at the end.
char xgets(char *line, int size, FILE *stdn)
{
//READS THE LINE
fgets(line, size, stdn);
//REMOVES NEWLINE CHARACTER '\n' AND ADDS '\0'
line[strcspn(line, "\n")] = '\0';
return line;
}
When I call xgets inside main() function it works properly, but when it is called in other user-defined function it does not wait for user-input.
I'm using Visual Studio 2015 for debugging my code.
Here's my code:
#include<stdio.h>
#include<stdlib.h>
#include<process.h>
//USER-DEFINED FUNCTION
char xgets(char *line, int size, FILE *stdn);
void sortm_hgrade();
void sortm_rcharge();
void header(void);
void header(void)
{
printf("*-*-*-*-*HOTEL_INFO*-*-*-*-*");
printf("\n\n");
}
char xgets(char *line, int size, FILE *stdn)
{
//READS THE LINE
fgets(line, size, stdn);
//REMOVES NEWLINE CHARACTER '\n' AND ADDS '\0' END LINE CHARACTER
line[strcspn(line, "\n")] = '\0';
return line;
}
#define MAX 1000
//PROGRAMS STARTS HERE
int main(void)
{
//VARIABLE-DECLARATION
int i = 0, j = 0, n = 0;
char line[MAX] = { 0 };
char o = { 0 };
char h[10] = { 0 };
//FUCNTION CALL-OUT
header();
printf("Type anything : ");
xgets(h, sizeof(h), stdin);
printf("Enter one option from the following : \n\n");
printf("(a) To Print out Hotels of a given Grade in order of charges. \n");
printf("(b) To Print out Hotels with Room Charges less than a given Value. \n");
printf("Please type a proper option. \n");
while (n == 0){
scanf_s(" %c", &o);
switch (o){
case 'a':
sortm_hgrade();
n = 1;
break;
case 'b':
sortm_rcharge();
n = 1;
break;
default:
printf("Option INVALID \n");
printf("Please type a proper option \n");
n = 0;
break;
}
}
//TERMINAL-PAUSE
system("pause");
}
void sortm_hgrade()
{
//FOR SORTING BY GRADE
char g[10] = { 0 };
printf("Enter the Grade : ");
xgets(g, sizeof(g), stdin);
printf("\n");
}
void sortm_rcharge()
{
printf("----");
}
You should change
scanf(" %c", &o);
to
scanf("%c ", &o);
This force scanf to consume trailing chars, like '\n'
In your code '\n' of user input for scanf %c is not consumed and it is consumed by fgets in your xgets function that exit immediately with an empty buffer.
BTW that solution can wok only if a single char is input by user.
Best code would be
char c;
while (n == 0)
{
o = getchar();
while ((c = getchar()) != EOF && c != '\n') ;
EDIT
With the second solution code is waiting, and discarding, chars until a '\n' is triggered or end of file. In your specific case (using stdin as console) EOF is not mandatory. It will be mandatory in case of input is being read from a "real file".
You need to skip the \n character after you take in a character. you can command scanf for that. fgets reads that newline character up first and then hence it terminates. use this
scanf(" %c *[^\n]", &o);
This should do the trick
I'm pretty new to C. Writing in Visual Studio 2015, I'm trying to safely prompt a user for a string by using fgets. I want to use fgets to get the string, check if the string is too long, and reprompt the user if it is until they enter a good string. Here is my code
/*
* Nick Gilbert
* COS317 Lab 2 Task 2
*/
#include "stdafx.h"
int main()
{
char str[10];
int isValid = 0;
while (isValid == 0) {
printf("Please enter a password: ");
fgets(str, 10, stdin);
if (strlen(str) == 9 && str[8] != '\n') { //http://stackoverflow.com/questions/21691843/how-to-correctly-input-a-string-in-c
printf("Error! String is too long\n\n");
memset(&str[0], 0, sizeof(str));
}
else {
printf(str);
isValid = 1;
}
}
printf("Press 'Enter' to continue...");
getchar();
}
However, when I run this and enter a bad string, the excess characters get fed into the next fgets automatically!
How can I fix this to do what I want it to do?
If the string read in by fgets doesn't end with a newline, call fgets in a loop until it does, then prompt the user again.
if (strlen(str) > 0 && str[strlen(str)-1] != '\n') {
printf("Error! String is too long\n\n");
do {
fgets(str, 10, stdin);
} while (strlen(str) > 0 && str[strlen(str)-1] != '\n') {
}
Also, never pass a variable at the first argument to printf, particularly if the contents of that variable comes from user entered data. Doing so can lead to a format string vulnerability.
Try this:
#include "stdafx.h"
int main()
{
char str[10];
int isValid = 0;
while (isValid == 0) {
printf("Please enter a password: ");
fgets(str, str, stdin);
if (strlen(str) == 9 && str[8] != '\n') { //http://stackoverflow.com/questions/21691843/how-to-correctly-input-a-string-in-c
printf("Error! String is too long\n\n");
memset(str, 0, sizeof(str));
}
else {
printf("%s",str);
isValid = 1;
}
}
printf("Press 'Enter' to continue...");
getchar();
}
In addition:
While using memset() you can directly use the array_name rather &array_name[0].
I got errors while creating a menu using fgets and readrestofline function. I don't know where is the error coming from. Am I missing something? After compiling, errors shows at "fgets", "readrestofline" and "stdin".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int printMenu(void)
{
int option;
char input[3];
while((option != 3)||(option < 4)||(option > 0))
{
printf("Welcome\n");
printf("---------------------\n");
printf("1.Play \n2.Display Scores\n3.Quit\n");
printf("Please enter your choice: ");
fgets(input, 3, stdin);
if (input[strlen(input) - 1] != '\n')
{
printf("Input was too long.\n");
readRestOfLine();
}
else
{
input[strlen(input) - 1] = '\0';
}
switch (option)
{
case 1:
printf("Loading ...\n");
break;
case 2:
printf("Loading ...\n");
break;
case 3:
printf("Quitting...\n");
exit(0);
break;
default:
printf("Invalid ! Please choose again.\n");
break;
}
}
}
void readRestOfLine()
{
int c;
/*read until the end of the line or end-of-file*/
while ((c = fgets(stdin)) != '\n' && c != EOF);
/*clear the error and end-of-file flags*/
clearerr(stdin);
}
errors while creating a menu using fgets...
Regarding your code line:
while ((c = fgets(stdin)) != '\n' && c != EOF);
fgets, prototype is:
char *fgets (char Line_Buffer[], int Number_of_Chars, FILE *Stream);
Reads characters from the specified input stream into a lineBuffer until end-of-file is encountered, a newline character is read, or (number_ofChars - 1) characters are read. The newline character is retained. An ASCII NUL byte is appended to the end of the string. If successful, the function returns a pointer to lineBuffer.
you have only provided 1 of the 3 necessary arguments.
Example usage:
char buf[80];//line buffer with space for 80 char
int c;
while(fgets(buf, 80, stdin))
{
//do something with buf
}
Also, instead of using the line(s): (undefined behavior)
if (input[strlen(input) - 1] != '\n') //used twice in your code example
Consider testing the contents of the string(s) like this:
if(strstr(input, "\n"))//change the second argument to search for other values
{
//do something
}
Note that your first usage of fgets in the posted code is syntactically correct.
What is the difference between fgets() and gets()?
I am trying break my loop when the user hits just "enter". It's working well with gets(), but I don't want to use gets().
I tried with fgets() and scanf() but I don't have the same results as with gets(). fgets() breaks the loop whatever user enters in text! Here is my code :
void enter(void)
{
int i,
for(i=top; i<MAX; i++)
{
printf(".> Enter name (ENTER to quit): ");
gets(cat[i].name);
if(!*cat[i].name)
break;
printf(".> Enter Last Name: ");
scanf("%s",cat[i].lastname);
printf(".> Enter Phone Number: ");
scanf("%s",cat[i].phonenum);
printf(".> Enter e-Mail: ");
scanf("%s",cat[i].info.mail);
printf(".> Enter Address: ");
scanf("%s",cat[i].info.address);
printf("\n");
}
top = i;
}
A difference between gets() and fgets() is that fgets() leaves the newline in the buffer. So instead of checking whether the first element of the input is 0, check whether it's '\n';
fgets(cat[i].name, sizeof cat[i].name, stdin);
if (cat[i].name[0] == '\n' || cat[i].name[0] == 0) {
// empty line or no input at all
break;
} else {
// remove the trailing newline
int len = strlen(cat[i].name);
cat[i].name[len-1] = 0;
}
Drop gets() and scanf().
Create a helper function to handle and qualify user input.
// Helper function that strips off _potential_ \n
char *read1line(const char * prompt, char *dest, sizeof size) {
fputs(prompt, stdout);
char buf[100];
*dest = '\0';
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL; // EOF or I/O error
}
// Remove potential \n
size_t len = strlen(buf);
if (len > 0 && buf[len-1] == '\n') {
buf[--len] = `\0`;
}
// Line is empty or too long
if (len == 0 || len >= size) return NULL;
return memcpy(dest, buf, len+1);
}
void enter(void)
{
int i;
for(i=top; i<MAX; i++)
{
if (read1line(".> Enter name (ENTER to quit): ",
cat[i].name, sizeof cat[i].name) == NULL) break;
if (read1line(".> Enter Last Name: ",
cat[i].lastname, sizeof cat[i].lastname) == NULL) break;
if (read1line(".> Enter Phone Number: ",
cat[i].phonenum, sizeof cat[i].phonenum) == NULL) break;
if (read1line(".> Enter e-Mail: ",
cat[i].info.mail, sizeof cat[i].info.mail) == NULL) break;
if (read1line(".> Enter Address: ",
cat[i].info.address, sizeof cat[i].info.address) == NULL) break;
}
top = i;
}
Some attributes of fgets() and gets():
fgets() reads input and saves to a buffer until:
1) The buffer is 1 shy of being full - or -
2) '\n' is encountered - or -
3) The stream reaches an end-of-file condition - or -
4) An input error occurs.
gets() does #2 - #4 above except it scans, but does not save a '\n'.
gets() is depreciated in C99 and no longer part of C11.
The problematic difference between gets and fgets is that gets removes the trailing '\n' from an input line but fgets keeps it.
This means an 'empty' line returned by fgets will actually be the string "\n".
The nasty difference, that means it's best to avoid gets altogether, is that if you give gets a line that's too long your program will crash in very bad ways.
you can use fgets() with STDIN instead.
This function is secured and always insert a '\0' at the string end.
An example:
char inputbuffer[10];
char *p;
p = fgets(inputbuffer, sizeof(inputbuffer), stdin);
printf(">%s<\n", p); /* p is NULL on error, but printf is fair */
You'll get at most 9 characters + '\0', in this example.
My teacher has asked me to "Fool proof" my code from any sort of misuse, So I have come up with an
program that can remove any empty values (by disallowing them entirely)
Here is the Un-foolproofed code
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
printf("Type something: ");
fgets(text,16, stdin);
printf("You typed: %s",text);
getch();
}
I have made some simple adjustments to ensure there is no error, however, i cannot get the if filter to work properly, as it still allows the NULL input
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
int loop;
do
{
printf("Type something: ");
fgets(text,16, stdin);
if( text[0] == '\0')
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
}
while(loop > 0);
printf("You typed: %s",text);
getch();
}
I've tried google and i cannot get a solid answer, this probably is some very simple line of code, but sadly i have no idea what it is.
Edit: it's fixed, the if statement should be:
if (text[0] == '\n')
Using the return value from fgets() is the best first step to fool-proofing user I/O.
char text[16];
printf("Type something: ");
if (fgets(text, sizeof text, stdin) == NULL) {
if (feof(stdin)) Handle_stdin_is_closed(); // no more input
if (ferror(stdin) Handle_IOerror(): // very rare event, more common with files
}
// Test is input is is only a '\n'
if (text[0] == '\n')
printf("Try again");
// Look for long line.
size_t len = strlen(text);
if (len + 1 == sizeof text && text[len - 2] != '\n') HandleLongLine();
The next step is to look for scan errors. Let's assume code is to read a long.
errno = 0;
char *endptr;
long = strtol(text, &endptr, 10);
if (errno) Handle_NumericOverflow();
if (text == endptr) Handle_InputIsNotNumeric();
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr != '\0') Handle_ExtraTextAfterNumber();
Although this is a lot of code, robust handling of hostle user input is best spun off to a helper function where lots of tests can be had.
char * prompt = "Type something: ";
long number;
int stat = GetLong(stdin, prompt, &number); // put all tests in here.
if (stat > 0) Handle_SomeFailure();
if (stat < 0) Handle_EOF();
printf("%ld\n", number);
fgets reads a whole line including the newline into the buffer and 0-terminates it.
If it reads something and then the stream ends, the read line will not have a newline.
If the line does not fit, it won't contain a newline.
If an error occurs before it successfully reads the first character, it returns NULL.
Please read the man-page for fgets: http://man7.org/linux/man-pages/man3/fgets.3.html
According to the fgets() man page
char *fgets(char *s, int size, FILE *stream);
//fgets() returns s on success, and NULL on error or when end of file
//occurs while no characters have been read.
so, you can check the return value of fgets()
n = fgets(text,16, stdin);
if that value is NULL, then nothing have been read.
you can do this by checking the value of n in a for loop,
if( n == NULL)
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}