Using fgets() to recieve a sentence input - c

I seem to be having an issue with some code. The purpose of the code is to take a phrase and convert it to pig latin.
It seems that this code will not take user input, at the block where we say if (x == 1). What it will do is it will automatically take NULL as input to fgets, and I'm clueless as to why.
I've spent entirely too much time on this problem, and I would appreciate any advice on how to improve this code. Please leave a comment on how I can improve my questions in the future.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int pigLatin()
{
char phrase[250] = { 0 };
char pigPhrase[300] = { 0 };
char * tokens[300] = { 0 };
char fileName[260] = { 0 };
FILE * read = NULL;
FILE * write = NULL;
int i = 0;
int x;
int size;
while (i < 10000) {
i++;
x = 0;
printf("Enter one(1) to input via console, two(2) to input via .txt, or (3) to exit:\n");
scanf_s("%d", &x);
if (x == 1) {
printf_s("Enter your Phrase Do not include:\nany punctuation, words less than 2 letters long, or words seperated by blanks:");
fgets(phrase, sizeof phrase, stdin);
phrase[strlen(phrase) - 1] = '\0';
printf_s("\nPhrase Entered:%s\n", phrase);
system("pause");
}
else if (x == 2)
{
printf("Enter name of input file:\n");
scanf_s("%s", fileName, 260);
printf("File name:\n%s\n", fileName);
if (fopen_s(&write, fileName, "r") == 0)
{
scanf_s("%s", phrase, 260);
}
}
else if (x == 3)
{
break;
}
else
{
printf("Invalid Statement\n");
break;
}
}
return 0;
}

scanf("%d", &number); will read an integer but leave everything else in the stream including the '\n' generated by pressing [Enter] after entering the number. This newline left in the stream is then consumed by fgets() without giving you a chance for input.
Clear the stream after using scanf():
int clear(FILE *stream)
{
int ch; // reads until EOF or a newline is encountered:
while((ch = fgetc(stream)) != EOF && ch != '\n');
}
// ...
int number;
if(scanf("%d", &number) != 1) {
// handle error;
}
clear(stdin);
char foo[42];
fgets(foo, sizeof(foo), stdin);
// ...

Related

creating username function what if there is no input at all just pressing enter?

How do I make an error message if only enter or a space is entered?
do
{
printf("Please enter a username: ");
scanf("%s", name);
if(name[0] == '\n')
{
printf("invalid input");
}
printf("> %s\n", name);
}
while(strlen(name) < 2 || strlen(name) > 15);
The newline will result in an empty string so the format specifier is not satisfied, so scanf() does not return. It is somewhat arcane behaviour, but:
int count = scanf( "%16[^ \n]s", name ) ;
will return when newline or leading whitespace is entered with count == 0. It will also accept no more than 16 characters, preventing a buffer overrun while allowing the > 15 characters test.
To avoid unnecessary tests and multiple calls to strlen() for the same string:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
int main()
{
char name[20] = "" ;
bool name_valid = false ;
while( !name_valid )
{
printf("Please enter a username: ");
int count = scanf("%16[^ \n]", name);
size_t len = count == 0 ? 0 : strlen( name ) ;
name_valid = len > 1 && len < 16 ;
if( !name_valid )
{
int ch ;
do
{
ch = getchar() ;
} while( ch != '\n' && ch != EOF ) ;
printf("invalid input\n");
}
}
printf("> %s\n", name);
return 0;
}
Note that in "invalid input" you need to remove the buffered newline and any preceding junk.
I personally don't like using scanf() b/c it results in a lot of trouble and it is not safe to use it in a production environment. I recommend using fgets() instead, and here is how it works:
#include <stdio.h>
#include <string.h>
int main()
{
char buffer[50];
int buffer_size = sizeof(buffer);
/* accepts string input from user */
printf("Please enter a username: ");
fgets(buffer, buffer_size, stdin);
/* then remove "\n" from the string
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.
*/
buffer[strcspn(buffer, "\n")] = 0;
/* check if user has entered an empty string */
/* strcmp(): compares two strings and returns 0 if comparision is true */
if ((strcmp(buffer, "")) == 0 || (strcmp(buffer, " ")) == 0)
printf("I can detect that you printed nothing! \n");
else
printf("You printed: %s", buffer);
return 0;
}
It may seem like an absurd amount of work to do just to get input from user, but this is how it works in C.

How to check whether a given integer already exists in a file

How do I write a C program to enter a number from the keyboard and store it in a text file called number.dat. If the number exists in the file, display an error message. Program should allow to input numbers until the user inputs -99.
I tried this question, but I could not find how to check whether the integer already exists in the file.
This is my C code answer:
#include <stdio.h>
int main(void) {
int num;
FILE *xPtr;
xPtr = fopen("number.dat", "a");
while (num = -99) {
printf("Enter a number : ");
scanf("%d", &num);
if (num == -99)
break;
fprintf(xPtr, "%d\n", num);
}
return 0;
}
I could not find how to check whether an integer already exists in the file.
Can you please give me a solution for this matter?
There are a few things that could be improved. First of all, your while loop is using an assignment operator for the conditional expression:
while(num = -99)
Instead of assigning it to 99 at the beginning of the loop each time, you could do this:
while(num != -99)
Since you want the block inside of the loop to execute when num is not equal to -99. I would also convert it to a do-while loop, since you are not assigning num before you enter the loop the first time. When you are in the loop, you should be opening an closing the file so it can keep track of any numbers you add. In order to check your file you will need to read AND append, it is now currently set to only append. To read and append you will do the following:
xPtr = fopen("number.dat", "a+");
It might be helpful to add a function called has_num or whatever you choose, which takes the FILE* and checks for an int returning 1 if found and 0 if not. So you will modify your if statement to be
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
So with all of those changes, your code will become
#include <stdio.h>
int has_num(FILE* file, int num)
{
int curr;
int fnd = 0;
while (!fnd && (fscanf(file, "%d\n", &curr) != EOF))
{
fnd = (curr == num);
}
return fnd;
}
int main(void)
{
int num;
FILE *xPtr ;
do
{
xPtr = fopen("number.dat", "a+");
printf("Enter a number : ");
scanf("%d", &num);
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
fclose(xPtr);
} while (num != -99);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *fp; //create a pointer to FILE
char c,n,num;
printf("Enter a Number : ");
scanf("%c",&n);
if(n== -99){
// printf("Enter number greater than -99");
exit(0);
}
else{
fp = fopen("numbers.dat", "r+"); //read file
while ((c = getc(fp)) != EOF) {
num = c;
if(num==n){
printf("Included Number");
exit(0);
}
}
fp = fopen("numbers.dat","w+"); //write new number to file
putc(n, fp);
}
}
You program should successfully append numbers typed by the user to the file, but it has a few problems:
you do not check if fopen() successfully opened the file, you have undefined behavior if fopen() returns NULL.
you do not check if scanf() encountered an input failure. Entering a character that os not a number will cause undefined behavior, most likely an infinite loop appending the previously entered number if any.
you do not close the file. This will not have any adverse effect because all files are automatically closed upon program exit, but it is good style to close them explicitly.
of course you do not check if the number already exists in the file.
For the last problem, you should fopen() the file for both read and write, rewind the file and read all lines, checking if the number is present.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c, num, num1, found;
FILE *xPtr = fopen("number.dat", "w+");
if (xPtr == NULL) {
printf("cannot open file number.dat\n");
return 1;
}
for (;;) {
printf("Enter a number: ");
if (scanf("%d", &num) != 1) {
if (feof(stdin))
break;
printf("invalid input\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
break;
} else {
if (num == -99)
break;
rewind(xPtr);
found = 0;
for (;;) {
/* skip all characters that cannot start a number */
if (fscanf(xPtr, "%*[^-+0-9]") == EOF)
break;
if (fscanf(xPtr, "%d", &num2) == 1) {
if (num == num2) {
found = 1;
break;
}
} else {
getc(xPtr); // consume a byte
}
}
if (found) {
printf("number is already in the file\n");
} else {
/* append the number */
fseek(xPtr, 0L, SEEK_END);
fprintf(xPtr, "%d\n", num);
}
}
}
fclose(xPtr);
return 0;
}

Using scanf for char array in while loop

I am new to C programming.
I was curious as to see how much I have learnt C.
Therefore I thought of creating a program in which I could simply create a file and write in it.
The name of the file, I thought, should be less that 100 chars. But it doesn't matter if it is a string or one word or a letter.
I couldn't complete because I was stuck on fact that how to input a string for a file name(eg, Project work, New Doc1, etc)
So I wrote this;
int main()
{
int a = 0;
while(a != 5)
{
puts("Put a number: ");
scanf("%i", &a);
if(a == 1)
{
char name[30];
printf("Put a name: ->>");
for(int i = 0;i < 31 && name[i] != '\n';i++)
{
name[i] = getchar();
}
char ex[50] = ".txt";
strcat(name,ex);
printf("%s",name);
}
}
return 0;
}
The problem is while inputting the name, it doesn't stop at the next (when I press enter) and some how it is not printing the right file name either.
There's a lot of problems with you approach.
It's not good to mix scanf with another input primitives, you must flush stdin from any remaining characters.
Any string must end in '\0' in order to mark that string as complete. So you must reserve space to this character.
When you concat you must obey the limit of the string.
If you use printf, the string will be only displayed after flushing the stdout (when you put '\n' in the end of the string, flush is done)
Try this:
#include <stdio.h>
#include <string.h>
int main()
{
int a = 0;
while(a != 5)
{
int ch;
puts("Put a number: ");
scanf("%d", &a);
/* flush any remaining characters */
while ((ch=getchar()) != EOF && ch != '\n'); /* issue 1 */
if(a == 1)
{
int i = 0;
char name[30];
printf("Put a name: ->>");
fflush(stdout); /* issue 4 */
while ((ch=getchar()) != EOF && ch != '\n' && i < 25) /* issue 3 */
name[i++] = ch;
name[i] = '\0'; /* issue 2 */
/* flush any remaining characters [if input > 25 chars] */
if (ch != EOF && ch != '\n') while ((ch=getchar()) != EOF && ch != '\n');
char ex[50] = ".txt";
strcat(name,ex); /* issue 3 */
printf("%s\n",name);
}
}
return 0;
}
Also, consider use getline and atoi instead of getchar and scanf
#include<stdio.h>
main()
{
static char stop_char='y';
char input=0;
do{
printf("please input a character\n");
scanf("\n%c",&input);
}while(input!=stop_char);
}

How do i remove NULL input in C?

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;
}

How to prevent the user from entering more data than the maximum limit?

This code asks the user for data and subsequently a number:
$ cat read.c
#include<stdio.h>
#include<stdlib.h>
#define MAX 10
int main() {
char* c = (char*) malloc(MAX * sizeof(char));
int num;
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
printf("Enter num:\n");
scanf("%d", &num);
printf("data: %s", c);
printf("num: %d\n", num);
}
$
The problem is that apart from the instruction that states the maximum number of chars, there is nothing that stops the user from entering more, which is subsequently read into num as junk:
$ ./read
Enter data (max 10 chars):
lazer
Enter num:
5
data: lazer
num: 5
$ ./read
Enter data (max 10 chars):
lazerprofile
Enter num:
data: lazerprofnum: 134514043
$
Is there a way to discard all that is there on STDIN after the fgets call?
The scanf() function is terrible for user input, and it's not that great for file input unless you somehow know your input data is correct (don't be that trusting!) Plus, you should always check the return value for fgets() since NULL indicates EOF or some other exception. Keep in mind that you get the user's newline character at the end of your fgets() data unless the maximum is reached first. I might do it this way as a first pass:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10
void eat_extra(void) {
int ch;
// Eat characters until we get the newline
while ((ch = getchar()) != '\n') {
if (ch < 0)
exit(EXIT_FAILURE); // EOF!
}
}
int main() {
char c[MAX+1]; // The +1 is for the null terminator
char n[16]; // Arbitrary maximum number length is 15 plus null terminator
int num;
printf("Enter data (max: %d chars):\n", MAX);
if (fgets(c, MAX, stdin)) { // Only proceed if we actually got input
// Did we get the newline?
if (NULL == strchr(c, '\n'))
eat_extra(); // You could just exit with "Too much data!" here too
printf("Enter num:\n");
if (fgets(n, sizeof(n) - 1, stdin)) {
num = atoi(n); // You could also use sscanf() here
printf("data: %s", c);
printf("num: %d\n", num);
}
}
return 0;
}
To my knowledge, the only portable solution is to exhaust the buffer yourself:
while (getchar() != EOF);
Note that fflush(stdin); is not the answer.
EDIT: If you only want to discard characters until the next newline, you can do:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
What "can happen" to fgets?
it returns NULL when there is an error in input
it returns NULL when it finds an EOF before any "real" characters
it returns the pointer to the buffer
the buffer wasn't completely filled
the buffer was completely filled but there is no more data in input
the buffer was completely filled and there is more data in input
How can you distinguish between 1 and 2?
with feof
How can you distinguish between 3.1., 3.2. and 3.3.
By determining where the terminating null byte and line break were written:
If the output buffer has a '\n' then there is no more data (the buffer may have been completely filled)
If there is no '\n' AND the '\0' is at the last position of the buffer, then you know there is more data waiting; if the '\0' is before the last position of the buffer, you've hit EOF in a stream that doesn't end with a line break.
like this
/* fgets fun */
/*
char buf[SOMEVALUE_LARGERTHAN_1];
size_t buflen;
*/
if (fgets(buf, sizeof buf, stdin)) {
buflen = strlen(buf);
if (buflen) {
if (buf[buflen - 1] == '\n') {
puts("no more data (3.1. or 3.2.)"); /* normal situation */
} else {
if (buflen + 1 == sizeof buf) {
puts("more data waiting (3.3.)"); /* long input line */
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
}
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
} else {
if (feof(stdin)) {
puts("EOF reached (2.)"); /* normal situation */
} else {
puts("error in input (1.)");
}
}
The usual, incomplete tests, are buf[buflen - 1] == '\n' and checking fgets return value ...
while (fgets(buf, sizeof buf, stdin)) {
if (buf[strlen(buf) - 1] != '\n') /* deal with extra input */;
}
I would read the data and then check it for user error:
bool var = true;
while var {
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
if(strlen(c) <= 10)
var = false;
else
printf("Too long, try again! ");
}
On the other hand, if you don't want to do this, just read num twice and discard the first one.

Resources