How to take int and double as input but not a char? - c

I'm trying to make a while loop that will be used to take an int and a double as input. But sometimes there could be a char in the input which I want to skip, and then continue the loop.
This will skip the loop and I want to still use the scanf:
scanf("%d%lf", &num,&n_double);
while((num != 'a')&&(n_double != 'a'))

First read the whole line, then use sscanf to parse the input line into an integer and a double. If, however parsing fails to give an int and a double, conclude that as the error case, i.e. a char present in the line.
You can try this code:
int main(int argc, char const *argv[])
{
char line[100];
while(fgets(line, 100, stdin)) {
int i;
double d;
if(sscanf(line, "%d %lf", &i, &d) == 2) {
printf("%d %lf\n", i, d);
}
else {
printf("wrong input!\n");
}
}
return 0;
}
Edited as per comment:
from cppreference.com
char *fgets( char *str, int count, FILE *stream );
Parameters
str - pointer to an element of a char array
count - maximum number of characters to write (typically the length
of str)
stream - file stream to read the data from
Return value
str on success, null pointer on failure.
So, while(fgets(str...)) translates to "while fgets doesn't return null", which translates to "while fgets continues to successfully read the input stream (which in this case is stdin, the standard input)".
Please take a look at the documentation for further clarification.

Do you mean input validation?
char line[80];
int ival;
double dval;
fgets(line, 80, stdin);
if (sscanf(line, "%d", &ival) == 1)
/* got an int */
else if (sscanf(line, "%f", &dval) == 1)
/* got a double */
else
fprintf(stderr, "Not int nor double\n");

Related

How to make a C program that can read a data and copy some in a variable?

I'm a student, I am wondering...
How can I make a program that can Get some data from my text file to a variable on my program and print them
Example:
My Text File
I,Ate,Cookies
She,Drink,Coffee
Tom,Wears,Pyjamas
My code
main()
{
FILE *fp=fileopen("c:\\textfile.txt","r");
char name[20],action[20],item[20];
prinf("Enter name: \n");
scanf("%s",&name);
/* I dont Know what to do next */
}
I though about some checking code:
if (name==nametxt) /*nametxt is the first line on the text file */
{
printf("%s\n %s\n %s\n",name,action,item);
}
If the name is "I",the output would look like this :
Enter name:
I
I
Eat
Cookies
A help will satisfy my curiosity thanks in advance
You are reading characters from file until you receive new line character (\n) or fill an array, then you return characters stored in an array passed by caller.
From this returned array you may get separated values with strtok.
Repeat until you receive 0 from getline (Getline received EOF from file.)
Here is simple example with your own getline function which you may modify.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getline(char s[],int lim, FILE * fp)
{
int c, i;
for (i=0; i < lim-1 && (c=fgetc(fp))!=EOF && c!='\n'; ++i)
{
s[i] = c;
}
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
int main()
{
FILE * fp = fopen("c:\\textfile.txt", "r");
char line[100];
char * ptr;
while (getline(line, 100, fp))
{
ptr = strtok(line, ",");
while( ptr != NULL )
{
printf(" %s\n", ptr);
ptr = strtok(NULL, ",");
}
}
return 0;
}
Output
I
Ate
Cookies
She
Drink
Coffee
Tom
Wears
Pyjamas
Storing strings into variable isnt tough, here is an example
strcpy(name, ptr);
But be careful, writing outside of bounds have undefined behavior.
strncpy(name, ptr, 100); You can limit number of copied characters with strncpy, but be careful, this function is error-prone.
You can do like this,
Go on reading characters from a file, after every character is read compare with ',' character.
If the character read is ',' then you have finished reading the name, otherwise store it in a character array and continue reading the file.
Once you hit ',' character, terminate the character array with null character(Now you have a complete name with you).
Compare this character array with a string you receive as input using a strcmp(String compare function). If its it matches decide what you wanna do?
I hope i am clear.
There is different ways to read data from a FILE * in C :
You read only one character : int fgetc(FILE *fp);.
You read a whole line : char *fgets(char *buf, int n, FILE *fp); (take care to buf, it must point to allocate memory).
You read a formatted string, which is your case here : int fscanf(FILE *stream, const char *format, ...), it works like printf() :
This way :
char name[20], action[20], item[20];
FILE *f = fopen("myfile.txt", "r");
if (! f)
return;
if (3 == fscanf(f, "%19[^,\n],%19[^,\n],%19[^,\n]\n", name, action, item))
printf("%s %s %s\n", name, action, item)
%30[^,\n], here is used to read of whole object of your line, except , or \n, which will read item by item the content of your string.
start with like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATA_FILE "data.txt"
#define LEN 19
#define SIZE (LEN+1)
//Stringification
#define S_(n) #n
#define S(n) S_(n)
enum { NOT_FOUND, FIND };
int pull_data(const char name[SIZE], char action[SIZE], char item[SIZE]){
int ret = NOT_FOUND;
FILE *fp = fopen(DATA_FILE, "r");//fileopen --> fopen
if(fp == NULL){
perror("fopen:");
exit(EXIT_FAILURE);
} else {
char nametxt[SIZE];
*action = *item = 0;
while(fscanf(fp, "%" S(LEN) "[^,],%" S(LEN) "[^,],%" S(LEN) "[^\n]%*c", //"%19[^,],%19[^,],%19[^\n]%*c"
nametxt, action, item) == 3){
if(strcmp(name, nametxt) == 0){//Use strcmp for comparison of strings
ret = FIND;
break;
}
}
}
fclose(fp);
return ret;
}
int main(void){
char name[SIZE], action[SIZE], item[SIZE];
printf("Enter name: \n");//prinf --> printf
if(scanf("%" S(LEN) "s", name) == 1){
if(pull_data(name, action, item) == FIND){
printf("%s\n%s\n%s\n", name, action, item);
} else {
printf("%s not found.\n", name);
}
}
}

proper use of scanf in a while loop to validate input

I made this code:
/*here is the main function*/
int x , y=0, returned_value;
int *p = &x;
while (y<5){
printf("Please Insert X value\n");
returned_value = scanf ("%d" , p);
validate_input(returned_value, p);
y++;
}
the function:
void validate_input(int returned_value, int *p){
getchar();
while (returned_value!=1){
printf("invalid input, Insert Integers Only\n");
getchar();
returned_value = scanf("%d", p);
}
}
Although it is generally working very well but when I insert for example "1f1" , it accepts the "1" and does not report any error and when insert "f1f1f" it reads it twice and ruins the second read/scan and so on (i.e. first read print out "invalid input, Insert Integers Only" and instead for waiting again to re-read first read from the user, it continues to the second read and prints out again "invalid input, Insert Integers Only" again...
It needs a final touch and I read many answers but could not find it.
If you don't want to accept 1f1 as valid input then scanf is the wrong function to use as scanf returns as soon as it finds a match.
Instead read the whole line and then check if it only contains digits. After that you can call scanf
Something like:
#include <stdio.h>
int validateLine(char* line)
{
int ret=0;
// Allow negative numbers
if (*line && *line == '-') line++;
// Check that remaining chars are digits
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1; // Remember that at least one legal digit was found
++line;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin)) // Read the whole line
{
if (validateLine(line)) // Check that the line is a valid number
{
// Now it should be safe to call scanf - it shouldn't fail
// but check the return value in any case
if (1 != sscanf(line, "%d", &x))
{
printf("should never happen");
exit(1);
}
// Legal number found - break out of the "while (y<5)" loop
break;
}
else
{
printf("Illegal input %s", line);
}
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Input
1f1
f1f1
-3
Output
Please Insert X value
Illegal input 1f1
Please Insert X value
Illegal input f1f1
Please Insert X value
Illegal input
Please Insert X value
x=-3
Another approach - avoid scanf
You could let your function calculate the number and thereby bypass scanf completely. It could look like:
#include <stdio.h>
int line2Int(char* line, int* x)
{
int negative = 0;
int ret=0;
int temp = 0;
if (*line && *line == '-')
{
line++;
negative = 1;
}
else if (*line && *line == '+') // If a + is to be accepted
line++; // If a + is to be accepted
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1;
// Update the number
temp = 10 * temp;
temp = temp + (*line - '0');
++line;
}
if (ret)
{
if (negative) temp = -temp;
*x = temp;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin))
{
if (line2Int(line, &x)) break; // Legal number - break out
printf("Illegal input %s", line);
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Generally speaking, it is my opinion that you are better to read everything from the input (within the range of your buffer size, of course), and then validate the input is indeed the correct format.
In your case, you are seeing errors using a string like f1f1f because you are not reading in the entire STDIN buffer. As such, when you go to call scanf(...) again, there is still data inside of STDIN, so that is read in first instead of prompting the user to enter some more input. To read all of STDIN, you should do something the following (part of code borrowed from Paxdiablo's answer here: https://stackoverflow.com/a/4023921/2694511):
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Used for strtol
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
#define NaN 3 // Not a Number (NaN)
int strIsInt(const char *ptrStr){
// Check if the string starts with a positive or negative sign
if(*ptrStr == '+' || *ptrStr == '-'){
// First character is a sign. Advance pointer position
ptrStr++;
}
// Now make sure the string (or the character after a positive/negative sign) is not null
if(*ptrStr == NULL){
return NaN;
}
while(*ptrStr != NULL){
// Check if the current character is a digit
// isdigit() returns zero for non-digit characters
if(isdigit( *ptrStr ) == 0){
// Not a digit
return NaN;
} // else, we'll increment the pointer and check the next character
ptrStr++;
}
// If we have made it this far, then we know that every character inside of the string is indeed a digit
// As such, we can go ahead and return a success response here
// (A success response, in this case, is any value other than NaN)
return 0;
}
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
// (Per Chux suggestions in the comments, the "buff[0]" condition
// has been added here.)
if (buff[0] && buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
void validate_input(int responseCode, char *prompt, char *buffer, size_t bufferSize){
while( responseCode != OK ||
strIsInt( buffer ) == NaN )
{
printf("Invalid input.\nPlease enter integers only!\n");
fflush(stdout); /* It might be unnecessary to flush here because we'll flush STDOUT in the
getLine function anyway, but it is good practice to flush STDOUT when printing
important information. */
responseCode = getLine(prompt, buffer, bufferSize); // Read entire STDIN
}
// Finally, we know that the input is an integer
}
int main(int argc, char **argv){
char *prompt = "Please Insert X value\n";
int iResponseCode;
char cInputBuffer[100];
int x, y=0;
int *p = &x;
while(y < 5){
iResponseCode = getLine(prompt, cInputBuffer, sizeof(cInputBuffer)); // Read entire STDIN buffer
validate_input(iResponseCode, prompt, cInputBuffer, sizeof(cInputBuffer));
// Once validate_input finishes running, we should have a proper integer in our input buffer!
// Now we'll just convert it from a string to an integer, and store it in the P variable, as you
// were doing in your question.
sscanf(cInputBuffer, "%d", p);
y++;
}
}
Just as a disclaimer/note: I have not written in C for a very long time now, so I do apologize in advance if there are any error in this example. I also did not have an opportunity to compile and test this code before posting because I am in a rush right now.
If you're reading an input stream that you know is a text stream, but that you are not sure only consists of integers, then read strings.
Also, once you've read a string and want to see if it is an integer, use the standard library conversion routine strtol(). By doing this, you both get a confirmation that it was an integer and you get it converted for you into a long.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool convert_to_long(long *number, const char *string)
{
char *endptr;
*number = strtol(string, &endptr, 10);
/* endptr will point to the first position in the string that could
* not be converted. If this position holds the string terminator
* '\0' the conversion went well. An empty input string will also
* result in *endptr == '\0', so we have to check this too, and fail
* if this happens.
*/
if (string[0] != '\0' && *endptr == '\0')
return false; /* conversion succesful */
return true; /* problem in conversion */
}
int main(void)
{
char buffer[256];
const int max_tries = 5;
int tries = 0;
long number;
while (tries++ < max_tries) {
puts("Enter input:");
scanf("%s", buffer);
if (!convert_to_long(&number, buffer))
break; /* returns false on success */
printf("Invalid input. '%s' is not integer, %d tries left\n", buffer,
max_tries - tries);
}
if (tries > max_tries)
puts("No valid input found");
else
printf("Valid input: %ld\n", number);
return EXIT_SUCCESS;
}
ADDED NOTE: If you change the base (the last parameter to strtol()) from 10 to zero, you'll get the additional feature that your code converts hexadecimal numbers and octal numbers (strings starting with 0x and 00 respectively) into integers.
I took #4386427 idea and just added codes to cover what it missed (leading spaces and + sign), I tested it many times and it is working perfectly in all possible cases.
#include<stdio.h>
#include <ctype.h>
#include <stdlib.h>
int validate_line (char *line);
int main(){
char line[256];
int y=0;
long x;
while (y<5){
printf("Please Insert X Value\n");
if (fgets(line, sizeof(line), stdin)){//return 0 if not execute
if (validate_line(line)>0){ // check if the string contains only numbers
x =strtol(line, NULL, 10); // change the authentic string to long and assign it
printf("This is x %d" , x);
break;
}
else if (validate_line(line)==-1){printf("You Have Not Inserted Any Number!.... ");}
else {printf("Invalid Input, Insert Integers Only.... ");}
}
y++;
if (y==5){printf("NO MORE RETRIES\n\n");}
else{printf("%d Retries Left\n\n", (5-y));}
}
return 0;}
int validate_line (char *line){
int returned_value =-1;
/*first remove spaces from the entire string*/
char *p_new = line;
char *p_old = line;
while (*p_old != '\0'){// loop as long as has not reached the end of string
*p_new = *p_old; // assign the current value the *line is pointing at to p
if (*p_new != ' '){p_new++;} // check if it is not a space , if so , increment p
p_old++;// increment p_old in every loop
}
*p_new = '\0'; // add terminator
if (*line== '+' || *line== '-'){line++;} // check if the first char is (-) or (+) sign to point to next place
while (*line != '\n'){
if (!(isdigit(*line))) {return 0;} // Illegal char found , will return 0 and stop because isdigit() returns 0 if the it finds non-digit
else if (isdigit(*line)){line++; returned_value=2;}//check next place and increment returned_value for the final result and judgment next.
}
return returned_value; // it will return -1 if there is no input at all because while loop has not executed, will return >0 if successful, 0 if invalid input
}

Expecting specific data types in C

I'm attempting to finish a portion of a program but I can't seem to make sense of how to complete a simple problem. In order for the user to get to the next portion of the program they need to enter a value as a char, decimal, and hex. If they don't the control switches to another function.
I was hoping it would be as easy as
if(input != "%c %d %x") etc.
from what I'm reading it seems to be much more confusing than that and I can't seem to find an answer although I'm sure I overlooked an obvious one.
Edit:
int main() {
char input[512];
int n;
user_id = (char *)malloc(100);
printf("Type your user id\n");
my_fgets(user_id, 100, stdin);
printf("Input for phase 1\n");
my_fgets(input, 512, stdin);
phase_1(input);
n = hash2(user_id);
printf("Your number is %d\n", n);
}
void phase_2(char *input, int n)
{
n = n + 100;
if(input != "%c\n")
explode_bomb();
}
You need to write an input function, which reads input into a string, then use isdigit() ischar() isxchar() to scan the string to find out what type the input is.
I'm assuming you expect input to be something like this: C 67 43. The character C along with its value in decimal and hex. You need to write a function to parse this string and determine if it's correct.
First, the parsing. You're on the right track. What you need is sscanf.
char char_char;
unsigned int char_hex;
unsigned int char_int;
if( sscanf(input, "%c %u %x", &char_char, &char_int, &char_hex) < 3 ) {
fprintf(stderr, "%s doesn't look like what I want\n", input);
return false;
}
I chose unsigned int because %x maps to an unsigned integer and char also can safely be compared with an unsigned integer.
Then all you need to do is check if the three values are the same. sscanf has already converted the hex into an unsigned integer, and char can safely be compared to an unsigned integer.
if( char_int != char_hex ) {
fprintf(stderr, "%u and %u don't match\n", char_int, char_hex);
return false;
}
if( char_int != char_char ) {
fprintf(stderr, "%u and %c don't match\n", char_int, char_char);
return false;
}
return true;
Put it all together and wrap a function around it.
#include <stdbool.h>
#include <stdio.h>
bool check_input(const char *input) {
char char_char;
unsigned int char_int;
unsigned int char_hex;
if( sscanf(input, "%c %d %x", &char_char, &char_int, &char_hex) < 3 ) {
fprintf(stderr, "%s doesn't look like what I want\n", input);
return false;
}
if( char_int != char_hex ) {
fprintf(stderr, "%u and %u don't match\n", char_int, char_hex);
return false;
}
if( char_int != char_char ) {
fprintf(stderr, "%u and %c don't match\n", char_int, char_char);
return false;
}
return true;
}
A better function won't print to stderr, but would instead set the error message via a passed in char *.
In order to test if a string complies with a given format, use "*" and "%n".
The * still scans for text that matches the specifier, but suppresses saving and also does not add to the return value.
"%n" directs *scanf() to save the number of char scanned so far.
By testing if n > 0 and if input[n] is the end of the string, code can simple detect a matching format.
int n = 0;
sscanf(input, "%*c %*d %*x %n", &n);
if (n > 0 && input[n] == '\0') {
puts("Success");
}

using sscanf() read from command line [duplicate]

I need to get argv[1] and argv[2] to different types. I found that I could only use sscanf() once or the next string in argv cannot be retrieved.
Here's my code.
int main( int argc, char *argv[])
{
char t;
float temp;
sscanf(argv[1], "-%[cf]",&t);
sscanf(argv[2], "%f", &temp);
return 0;
}
Only the first sscanf() can get the formatted value.
How could I also get done with argv[2]?
Attempt to save string data in a char leading to undefined behavior (UB).
"%[]" expects to match a character array.
// char t;
// sscanf(argv[1], "-%[cf]",&t);
char t[100];
if (sscanf(argv[1], "-%99[cf]",t) != 1) Handle_Failure();
Recommend:
Add the width limit, like 99, to limit string input. Set to 1 less than the size of t.
Check the return value of sscanf().

Checking user input for numbers

In my main function, I have the following:
int main(){
FILE *fp;
char ch;
char name[100];
printf("Create file with name: ");
scanf("%s", &name);
fp = fopen(name, "w");
printf("Enter data to be stored in the file: ");
while((ch=getchar())!=EOF){
if(isNumeric(ch)){
putc(ch,fp);
}
}
fclose(fp);
return 0;
}
Which creates a file and stores data (by the user till the end of the input stream or Ctrl+Z) in it with getchar(). I want to check if the supplied data has been numerical but I'm hitting a rock. I've read many topics and all answers suggest isdigit() but it doesn't validate numbers with a floating point. Here's my isNumeric() function:
int isNumeric (const char * s)
{
if (s == NULL || *s == '\0' || isspace(*s))
return 0;
char * p;
strtod (s, &p);
return *p == '\0';
}
The fundamental problem here is that isNumeric is designed to determine whether a string of characters is a valid number, but you're only giving isNumeric one character at a time.
To fix the problem, you need a char array that stores characters until you reach a point where the array should contain a complete number. Then check the array with isNumeric.

Resources