I'm trying to get an array of ints from the user, i did check for illegal input and it works just fine except for the last input:
int *array=(int*)malloc(sizeof(int)*size);
For example for the size 3, let's say the input is 3 5 2.2
So when i assign the numbers into the array the last input (2.2) is considered as 2 and the program continues even though it shouldn't.
Any ideas?
Thank you.
Has nothing to do with your use of malloc(). Instead, you need to check how you are parsing the input. A very naive parser would just read the 2.2 as 2 with some extra garbage at the end. scanf() for example, behaves this way.
You can test this easily:
#include <stdio.h>
void main(void) {
int i;
scanf("%d",&i);
printf("%d\n",i);
}
Feed it a decimal, such as 4.2 and what do you get? 4 -- what happened to the .2 at the end? It's still in the input buffer, actually, waiting for something to read it.
You will have to use a smarter scanner to verify that the user isn't entering garbage.
As PaulProgrammer suggested above that you will have to use a smarter scanner to verify that the user isn't entering garbage.You can use character reader scanner and then check if value entered by user is an integer or not by checking some characteristics, if it belongs to int just convert the character string into integer using functions like atoi(), else output a warning to user.
I have written a small code for you which takes 6 integers and checks for floats and other wrong values.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch,arr[20]; //arr is an array for storing the character values initially taken as input.
int x,input[100],i=0,count=0; //input is an array which will hold the integer values
while((x=scanf("%c",&ch))>0){
if(ch=='.') //checking if there is any floating point number
{
printf("Wrong Input");
return 0;
}
if(ch>='0' && ch <='9') //check if ch is in the range of 0-9
{
arr[i++]=ch;
}
if(ch==' ' || ch=='\n'){
arr[i]='\0';
input[count++]=atoi(arr);
i=0;
}
if(count==7) break;
}
for(int loop=0;loop<6;loop++){
printf("%d ",input[loop]);
}
}
I hope you got the point.Please notice when you write this code make sure that it checks for every possible input error.
Related
I'd like some assistance with understand how inputting data in a program of C works. So far I'm used the java syntax having the convenient try{}catch(){}; clause but I don't see it anywhere on C (or I haven't found it?).
Assuming I have the following array;
float f_array[10];
Normally for me to input data I'd either use a scanf(...); or a file which I can read input from, but for the shake of simplicity let's assume I use scanf(...);
And I have the following;
int i;
for(i = 0; i<10; i++){
scanf("%f", &f_array[i]);
}
Now , my question is how to restrain the user from putting in the input a character or a string or the wrong data type for that matter? Also , should I always try to initialize the array before actually putting values in it?
Note that scanf() returns number of elements successfully read, you can check it:
int success = scanf(...);
if (!success) {
scanf("%*[^\n]%*c"):
// OR while(getchar() != '\n');
}
There is, however, a complex solution. You don't use scanf(), but write a custom input method that processes keystrokes and filters out invalid characters, possibly using getch() (Windows/nCurses). Here's a minimized Windows version:
void readFloat(float* in){
int ch, ind = 0;
char buf[100];
while (1){
ch = getch();
if (ch >= '0' && ch <= '9' || ch == '.') {
buf[ind++] = (char)ch;
putchar(ch);
}
else if (ch == 8) /* Backspace */ {
printf("\b \b");
ind --;
}
}
buf[ind] = '\0';
float ret;
sscanf(buf, "%f", &ret);
return ret;
}
So a possible result of the code:
User input (key presses): 123aaa.bbb456
Program filter (displayed on screen): 123.456
Return value: (float)123.456
Now , my question is how to restrain the user from putting in the input a character or a string or the wrong data type for that matter?
Without dedicated hardware support (say, using a keyboard that does not have letter keys, or some device that gives the user an electric shock to discourage them from hitting the 'A' key) there is no way to restrain a user from entering unwanted data.
Instead, you need to write your code with the ASSUMPTION that the user will enter invalid or poorly formed data, and cope with that. It is true that your code is simpler if you can assume an obedient and tractable user who only gives correct input, but the real world isn't like that.
scanf() - reading and interpreting data directly from stdin doesn't actually work well with such an assumption. The return value from scanf() can give you an indication a problem after the fact (e.g. the return value is number of fields successfully input, or EOF). However, when a problem occurs, scanf() handles it in a way you cannot control. Let's say you code has a
scanf("%f", &f_array[i]);
and the user hits the 'X' followed by the Enter key. scanf() will recognise the 'X' character is waiting to be read, and return immediately. The value it returns will not be 1 (which would indicate success). Even worse, the 'X' will be left to be read by a subsequent call of scanf() and the same will happen again (unless a different format is specified). Which means, if you call scanf() in a loop this way, the same will happen over and over again.
Some folks will tell you to simply find a way to read and discard the character 'X'. The problem with that approach is that there are MANY ways for the user to enter bad inputs, and you need to account for all of them. If the user does something you (or your code) doesn't expect, you get problems (e.g. program hanging waiting for the same input repeatedly, input being used as data when it isn't). You're back where you started.
The more robust approach is to simply read a line of input, and do checks before trying to extract a floating point value from it, such as
char buffer[20];
int got_one = 0;
while (!gotone && fgets(buffer, sizeof buffer, stdin) != NULL)
{
if (check_string(buffer))
{
if (sscanf(buffer, "%f", &f_array[i]) == 1)
{
/* yay - we got a floating point value */
got_one = 1;
}
else
{
fprintf(stderr, "Floating point scanning failed. Try again\n");
}
}
else
{
fprintf(stderr, "Bad data discarded. Try again\n");
}
}
Essentially, this provides several hooks so you can check user input in various ways. If you want to, it can be adapted to discard part of a line, and scan useful data from whatever's left.
The key, however, is that the code does not assume the user is well behaved. It only attempts to read a floating point value after a gauntlet of checks, and still copes if the reading fails.
The code can also be adapted to deal with users who enter data that overflows the buffer (e.g. entering 30 floating point characters on a single line). I'll leave that as an exercise.
Also , should I always try to initialize the array before actually putting values in it?
That depends on the needs of your code, but generally speaking I would not bother.
With approaches like I suggest above, you can avoid a circumstance of using the array (or elements of the array) unless valid data has actually been put into it.
All initialising the array will do is obscure cases where the code doing input (reading from the user) has not properly dealt with bad user input.
give the user some feedback on a per input basis.
process each input and allow user to make corrections as you go.
use "atof()" to do the conversion, but it has a couple of quirks:
it tells you there is an error by returning a value of 0.0
it stops processing if/when it finds an invalid char and returns what it has up to that point
eg. 6.35k gives 6.35 -- this usually works out ok;
otherwise you have to check for invalid chars yourself.
try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
float f_array[10];
int i;
float input_value;
char temp_string[32];
for(i = 0; i<10; i++){
printf("input a floating point number: ");
scanf("%s",&temp_string[0]);
input_value = atof(temp_string);
while(input_value == 0.0) {
printf("%s is not a valid floating point number\n");
printf("example is 5.6 or 1e32 or 17\n");
printf("try again - input a floating point number: ");
scanf("%s",&temp_string[0]);
input_value = atof(temp_string);
}
f_array[i] = input_value;
printf("String value = %s, Float value = %f\n", temp_string, input_value);
}
/* use the data */
for(i = 0; i<10; i++){
printf("%f\n",f_array[i]);
/* do something */
}
}
I'm working on program which input looks as follows:
3.14 (it's variable stored in union)
4 (number of calls)
int (asked types to return)
long
float
double
On output should i get:
1078523331
1078523331
3.140000
0.000000
Full instruction to this task
My program works except on double case: instead of giving me any output program gives me none. Can anyone explain me why? Here is my code.
#include <stdio.h>
#include <string.h>
#define SIZE 1000
#define CHARLENGTH 6
union Data {
int i;
long long l;
float f;
double d;
};
int main(){
union Data x;
char types[SIZE][CHARLENGTH];
int n;
scanf("%f",&x.f);
scanf("%d",&n);
for(int i = 0;i<=n+1;i++){
fgets(types[i],CHARLENGTH,stdin);
types[i][strcspn(types[i],"\n")] ='\0';//removing newline
}
for(int i = 1;i<=n+1;i++){
if(strcmp(types[i], "int") == 0){
printf("%d\n",x.i);
}
else if(strcmp(types[i], "long") == 0){
printf("%lli\n",x.l);
}
else if(strcmp(types[i], "float") == 0){
printf("%f\n",x.f);
}
else if(strcmp(types[i], "double") == 0){
printf("%lf\n",x.d);
}
}
}
You do not allow sufficient space in array types for a six-character string such as "double", because you need an extra byte for the terminator. Because you have used fgets() in a reasonable way, however, you have saved yourself from overrunning the bounds of that array -- fgets() just stops reading after the fifth character of "double", and appends a terminator. Therefore, what actually gets stored is "doubl". Naturally, that compares different from "double", so no corresponding output is produced.
In the first place, you should increase CHARLENGTH to at least 7. Doing so will take care of your immediate problem.
You should also consider adding a final else clause inside your loop that prints out a diagnostic message in the event that none of the other cases is satisfied. Such a message could have clued you in to what's going on.
for robustness, you might consider making sure to read and discard any trailing junk on the type lines; as it is, even trailing whitespace after one of the shorter type names will screw up your matching.
Perhaps it's respondent to the exercise as it is, but your program would be a lot more user friendly if it prompted for each input item.
Three Four quick observations:
0) As a minimum, the main function should be: int main(void).
1) Because C strings are defined as an array of char terminated with NULL, the string "double" requires a buffer with space for 7 char to contain it.
|d|o|u|b|l|e|\0| //includes NULL char termination
Change
#define CHARLENGTH 6
to
#define CHARLENGTH 7
2) Because it is not clear from the cmd line prompts in the running program what items are to be entered, if one of the string types, eg "double", is not entered, the line:
fgets(types[i],CHARLENGTH,stdin);
will not do as it is intended. Suggest adding some printf statements with instructions for what to enter for all 3 entries per line.
3) types is not initialized before use.
This can be addressed by simply initializing like this:
memset(types, 0, SIZE*CHARLENGTH);
or even simpler:
char types[SIZE][CHARLENGTH] = {0};
A comparison of what the memory looks like by the time it gets to the fgets statement, uninitialized, or initialized (by either method):
I got input like 12345679890 but I just want to read 1 integer at a time, that is read 1 then 2 then 3 ... and do some operations next. However when I use scanf, it read all the numbers i.e. 1234567890. Can anyone help? Thank you!!
This is the code that I have
#include <stdio.h>
int main() {
int input;
scanf("%x",&input);
while (scanf("%x",&input)==1){}
}
12345679890 is an integer, what you want to do is read one digit at a time. To do this, you would use the format string %1u rather than %x.
For a start, %x specifies a hexadecimal item, meaning it will accept a through f as well, and %d would allow for a leading sign which you probably don't want.
In addition, you appear to consume (and throw away) the first digit before you enter the loop, so you would be better off with something like:
#include <stdio.h>
int main(void) {
unsigned int digit;
while (scanf("%1d", &digit) == 1) {
//doSomethingWith(digit);
}
return 0;
}
The goal of this program is to create a function which reads in a single string, user typed, command (ultimately for program to be used in conjunction with a robot) which consists of an unknown command word(stored and printed as command), and an unknown number of decimal parameters(the quantity is stored and printed as num, and the parameters are to be stored as float values in the array params). In the User input, the command and parameters will be separated by spaces. I believe my issue is with the atof function when I go to extract the decimal values from the string. What am I doing wrong? Thank you for the help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(char *input, char *command, int *num, float *params);
int main()
{
char input[40]={};
char command[40]={};
int num;
float params[10];
printf("Please enter your command: ");
gets(input);
func(input,command,&num,params);
printf("\n\nInput: %s",input);
printf("\nCommand: %s",command);
printf("\n# of parameters: %d",num);
printf("\nParameters: %f\n\n",params);
return 0;
}
void func(char *input, char *command, int *num, float *params)
{
int i=0, k=0, j=0, l=0;
int n=0;
while(input[i]!=32)
{
command[i]=input[i];
i++;
}
for (k=0; k<40;k++)
{
if ((input[k]==32)&&(input[k-1]!=32))
{
n++;
}
}
*num=n;
while (j<n)
{
for (l=0;l<40;l++)
{
if((input[l-1]==32)&&(input[l]!=32))
{
params[j]=atof(input[l]);
j++;
}
}
}
}
A Sample Output Screen:
Please enter your command: Move 10 -10
Input: Move 10 -10
Command: Move
# of parameters: 2
Parameters: 0.000000
The Parameters output should, ideally, read "10 -10" for the output. Thanks!
Change atof(input[l]) to atof(input + l). input[l] is single char but you want to get substring from l position. See also strtod() function.
Other people have already remarked the problem in your code, but may I suggest that you have a look at strtod() instead?
While both atof() and strtod() discard spaces at the start for you (so you don't need to do it manually), strtod() will point you to the end of the number, so that you know where to continue:
while(j < MAX_PARAMS) // avoid a buffer overflow via this check
{
params[j] = strtod(ptr, &end); // `end` is where your number ends
if(ptr == end) // if end == ptr, input wasn't a number (say, if there are none left)
break;
// input was a number, so ...
ptr = end; // continue at end for next iteration
j++; // increment number of params
}
Do note that the above solution does not differentiate between invalid arguments (say, foo instead of 3.5) and missing ones (because we've hit the last argument). You can check for that by doing this: if(!str[strspn(str, " \t\v\r\n\f")]) --- this checks if we're at the end of string (but allowing trailing whitespace). See the second side-note for what it does.
SIDE-NOTES:
You can use ' ' instead of 32 to check for space; this has two advantages:
It is clearer to the reader (it's very clear that it's a whitespace, instead of "some magic number that happens to have meaning")
It works in non-ASCII encodings (and the standard allows other encodings, though ASCII is by far the most popular; one common encoding is EBCDIC)
For future reference, this trick can help you skip whitespace: ptr += strspn(ptr, " \t\v\r\n\f");. strspn returns the number of characters at the start of the string that match the set (in this case, one of " \t\v\r\n"). Check documentation for more info.
Example for strspn: strspn("abbcbaa", "ab"); returns 3 because you have aab (which match) before c (which doesn't).
you are trying to convert a char into a float,
params[j]=atof(input[l]);
you should get the entire word(substring) of the float.
Example, "12.01" a null terminated string with 5 characters and pass it to atof, atof("12.01") and it will return a double of 12.01.
so, you should first extract the string for each float parameter and pass it to atof
Avoid comparing character to ascii value, rather you could have use ' ' (space) directly.
Instead of using for loop with a fixed size, you can use strlen() or strnlen() to find the length of the input string.
I need to limit the input from a user to only positive values, and count the number of digits in that number. The user will only type in a (+/-) whole number up to 9 characters long.
I'm only allowed to use the scanf function and for, while, or do-while loops.(I saw in similar questions how to do this using getchar, but I can only use scanf). I'm not allowed to use arrays, or any other library besides stdio.h and math.h
I know that if I write:
n=scanf("%c%c%c%c%c",&a,&b,&c,&e,&f);
n will count the number of successful scanf conversions.
The problem i'm having is that when I define the input with char, it does everything I want except that the user MUST enter 5 characters. So if the user wants to input "55" he has to press "5" "5" "enter" "enter" "enter".
I need the program to move on after the first "enter" but also be flexible to receive a number up to 9 digits long.
again, I can't use getchar or anything fancy. Just the really basic stuff in C that you learn in the first 2 weeks.
Use scanf to read the number into a long int , then use a for loop with a /10 to count the number of digits
What do you want the program to do in case of a -ve number being entered?
#include<stdio.h>
int main()
{
long int a;
int b;
do
{
scanf ("%ld",&a);
if(a<0)
printf ("invalid input");
}while(a<0);
for(b=0;a!=0;b++,a=a/10);
printf("%d",b);
}
(does not handle -ve numbers specially)
Something like
#include <stdio.h>
int main(void)
{
char buffer[10] = { 0 };
size_t len;
scanf("%9[0-9]", buffer);
for(len = 0; buffer[len] != 0; len++) ;
printf("%zu '%s'\n", len, buffer);
return 0;
}
works, but I don't know if it fits your need.
EDIT (bits of explanation)
You can replace size_t with int (or unsigned int), though size_t is better. If you do, use %d or %u instead of %zu.
The basic idea is to exploit a feature of the format of scanf; the 9[0-9] says the input is a sequence of up to 9 char in the given set i.e. the digits from 0 to 9.
The for(...) is just a way to count char, a simple implementation of a strlen. Then we print the result.
The approach I would take would be the following.
Loops are allowed, so go ahead and set one up.
You need to have a variable somewhere that will keep track of what the current number is.
Think about typing out a number, one character at a time. What needs to happen to the current_number variable?
You need to stop the loop if a return key has been pressed.
Something like this should do for starters, but I'll leave the rest up to you, specifically what return_check(ch), update_state(current_val) and char_to_int(ch) looks like. Also note that rather than use a function, feel free to put your own function directly into the code.
int current_val=0;
int num_digits=0;
char ch="\0"
for (num_digits=0;return_check(ch) && num_digits<=9;num_digits++)
{
fscanf("%c");
current_val=update_state(current_val);
current_val=current_val+char_to_int(ch);
}
As for the logic in update_state(), think about what happens, one character at a time, if a user types in a number, like 123456789. How is current_val different from a 1 to a 12, and a 12 to a 123.
Can you wrap a loop around it, something like (I don't know if all of the syntax is right):
const int max_size=9
int n=0; //counter for number of chars entered
char a[max_size-1];
do {
scanf(%c,&a[n]);
n++;
} while (a[n] != '\r' && n<max_size)