How to use strtol to extract numbers from user input - c

I'm trying to build a Linear Equation calculator in C. My source code is below. I know this is a coding question but to explain my issue, I need to explain a little math here. I have the user input the points in the format (x,y) and want to convert the equation into one of the following ways:
Slope-intercept -> y = mx + b
Standard form -> ax + by = c
Point-slope form -> y - y1 = m(x - x1)
y is the point on the y-axis of the coordinate plane, x is the point on the x-axis on the coordinate plane, m is the slope of a line, b is the y-intercept of the first equation, and a, b, and c are variables in the second equation.
My issue is that I'm having trouble finding a way to extract numbers from a coordinate. In my source code, I have a 2 dimensional array that holds 2 strings with a certain size. I don't know if i should use strtol() or something else. For example, take the point (34,89). I want to extract the 34 and 89 and plug it in to the values for finding the slope (which would be (y2 - y1) divided by (x2 - x1). So it would be (89 - y) / (34 - x). As for the second point, I want to be able to do the same thing. I would like to avoid making 4 variables for each point if possible. I would also like to avoid asking the user to enter the x value of the first point then the y value of the first point etc. etc. I want to be able to ask the user for a point, including both x and y values. Near the end of the code is unfinshed, so if i have errors, I'll figure them out as I go. The problem is near the beginning and middle.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MAXC 56
//void convert_equation(); Function is not defined or used. Uncomment when ready to define
void equation_format();
void print_dots(int n);
char points[2][MAXC];
int main(void) {
printf("\033[0;32mInitializing Linear Equation Calculator ");
fflush(stdout);
print_dots (3);
putchar('\n');
printf("\nEnter the 1st point on the line, format (x,y)\n>>> ");
fflush(stdout);
fgets(points[0], sizeof points[0], stdin);
/** trim \n from end of string read with fgets()
*
* use: stringvar[strcspn (stringvar, "\n")] = 0;
*
* strcspn returns the length of stringvar that does NOT include \n
* this allows you to simply overwrite the \n with \0 (or plain old 0)
*/
points[0][strcspn(points[0], "\n")] = 0;
printf("Enter the 2nd point on the line, format (x,y)\n>>> ");
fflush(stdout);
fgets(points[1], sizeof points[1], stdin);
points[1][strcspn(points[1], "\n")] = 0;
equation_format();
return 0;
}
void equation_format() {
char option;
while (1) {
printf("\n\nWhat format would you like the equation in?\n1. Slope-Intercept\n2. Standard Form\n3. Point-slope\n>>> ");
fgets(&option, 2, stdin);
switch(option) {
case(1):{
int slope, yintercept;
break;
}
case(2):{
break;
}
case(3):{
break;
}
default: {
printf("Invalid input. Try again");
print_dots(3);
}
}
break;
}
}
void print_dots(int n) {
if (n < 0)
n = -n;
while (n--) {
sleep(1);
putchar('.');
fflush(stdout);
}
}
This is a little hard to explain so if I'm not being clear, please tell me. Thank you!

I want to be able to ask the user for a point, including both x and y values.
After fgets(), parse the string with a helper function, tailored to your needs.
Robust code also detects when the input is ill-formed.
// return 2 on success
// return -1 on failure.
int parse_2_int(const char *s, long *x, long *y) {
errno = 0;
char *endptr;
*x = strtol(s, &endptr, 0);
if (s == endptr || errno) return -1; // no conversion or overflow
s = endptr;
while (isspace((unsigned char) *s) { // skip spaces
s++;
}
if (*s != ',') return -1; // Missing ,
errno = 0;
*y = strtol(s, &endptr, 0);
if (s == endptr || errno) return -1;
s = endptr;
while (isspace((unsigned char) *s) { // skip spaces
s++;
}
if (*s != '\0') return -1; // junk at the end
return 2;
}
Usage
long x,y;
if (fgets(points[1], sizeof points[1], stdin)) {
if (parse_2_int(points[1], &x, &y) == 2) {
printf("Success %ld, %ld\n", x,y);
} else
printf("Trouble with <%s>\n", points[1]);
}
}

"My issue is that I'm having trouble finding a way to extract numbers from a coordinate.".
There are several way to convert a string to a number, strtol() and atoi() are either able to do this. Regarding user input, it is recommended that you keep the instructions to any user input as simple as possible. For example, rather than instructing a user to input "(34,89)", consider leaving the parenthesis off: "\nEnter the 1st point on the line, format: x,y\n>>> "
With that said, after user inputs are entered as say "56,78" and "3,7" and read into the string variables point1[0] and point1[1] respectively, it is a simple process to parse these into int (or long) members of a point struct using strtok():
typedef struct {
int x;
int y;
}POINT;
POINT p[2] = {0};
First, parse the string into char *, and convert:
char *tok = NULL;
tok = strtok(point[0], ",");
if(tok)
{
p[0].x = atoi(tok);
tok = strtok(NULL, ",");
if(tok)
{
p[0].y = atoi(tok);
)
And similar for p[1]. Then you can use the member pairs for x and y as arguments in the equation.
If strtol() is favored over atoi(), then adjust to replace:
p[0].x = atoi(tok);
with
p[0].x = strtol(tok, &ptr, 10);
As shown in the following:
typedef struct {
long x;
long y;
}POINT;
POINT p[2] = {0};
char *ptr = NULL;
p[0].x = strtol(tok, &ptr, 10);
//test return value for good results, and handle error if necessary
if(*ptr)
printf("Unable to convert '%s'.", tok);
else
...

Related

Determining Data Type Of User Entered Value

I was reading one of the application of "Unions" of creating mixed data types. Example
typedef union {
int x;
float y;
}mix;
mix arr[100];
Each element of array arr[100] can store either a int or a float type value. But suppose I want to take a input from user and store it in arr[ ] and I won't know that either user is going to enter a floator an int value. So I don't know which statement from the following I should choose to store that input from user.
1.scanf ("%d",&arr[0].x);
OR
2.scanf ("%f",&arr[0].y);
And similar problem arises when I want to print that value.
I know I can solve this problem using a "tag field". So I can do it as
#include <stdio.h>
typedef union {
int x;
float y;
}mix;
mix arr[100];
int main ()
{
int k; // tag field
puts("Mention 1 if you want to enter integer and 0 if you want to enter float value");
scanf ("%d",&k);
if (k)
{
scanf ("%d",&arr[0].x);
printf ("%d is the entered integer value\n",arr[0].x);
}
else
{
scanf ("%f",&arr[0].y);
printf ("%f is the entered float value\n",arr[0].y);
}
}
But here user is telling the type of data he is gonna enter(with the help of 0 or 1). I want to know: Is there any way in C language that compiler can automatically detect the type of data user is entering and according run either 1st or 2nd scanf statement without help of user? OR Is there any predefined function present in library for doing that?
Also tell if you have any another intresting way of doing this program.
This might help you I guess...
float num;
printf("Enter number\n");
scanf("%f",&num);
if((num - (int)num)== 0) //(int)num : Type casting
printf("Entered number is of int type\n");
else
printf("Entered number is of float type\n");
Determining Data Type Of User Entered Value
Read as a line fgets()and the parse with strtol(), strtof().
Untested code, read comments.
puts("Mention 1 if you want to enter integer and 0 if you want to enter float value");
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin)) {
// OK we have an input line of text now as a string
buffer[strcspn(buffer, "\n")] = '\0'; // lop off potential \n
char *endptr;
errno = 0;
long lval = strtol(buffer, &endptr);
// If conversion occurred and no text at the end ...
if (endptr > buffer && *endptr == '\0') {
// An integer type!
if (errno == ERANGE) puts("Integer value out of range");
printf("Integer value: %ld\n", lval);
} else {
errno = 0;
float = strtof(buffer, &endptr);
if (endptr > buffer && *endptr == '\0') {
// A float
if (errno == ERANGE) puts("float value out of range");
printf("float value: %g\n", f);
} else
puts("Non-numeric input");
}
}
For a int mystrtoi(const char *str), see ref code.

Function that prompts user for integer value and checks for valid input

I currently am stuck on a small part of an assignment I need to do.
One requirement of the assignment is
"Call a function that prompts the user for each of the values of the coefficients a, b, and c for the quadratic equation and returns the value entered, with error checking for a valid input (scanf returned a value)."
and I can't figure out how to do this. I can easily prompt the user for input and I can check if it is valid input, but I don't know how to turn this into a function. My current code is:
{
if (isalpha(a))
{
printf("INPUT ERROR!\n");
printf("Enter a value for a: ");
scanf("%d", &a);
}
} //this is how I would normally check the input
int main(void) //start of main() function definition
{
int a, b, c, n, D; //declares integer variables a, b, c, n, and D
float root1, root2; //declares float variables root1 and root2
do //do while loop starts here
{
printf("Enter a value for a: "); //prompts user to input integer for variable 'a'
scanf("%d", &a); //reads an integer from the keyboard and stores in the variable 'a'
printf("%d\n", a); //returns value of integer that was input for variable 'a'
printf("Enter a value for b: "); //prompts user to input integer for variable 'b'
scanf("%d", &b); //reads an integer from the keyboard and stores in the variable 'b'
printf("%d\n", b); //returns value of integer that was input for variable 'b'
printf("Enter a value for c: "); //prompts user to input integer for variable 'c'
scanf("%d", &c); //reads an integer from the keyboard and stores in the variable 'c'
printf("%d\n", c); //returns value of integer that was input for variable 'c'
...}
Sorry for any formatting mistakes, but that is basically the part of the program I am stuck with.
My question is, how can I combine the first function with everything in the do/while loop to make one big function that I can call three times?
I don't know how I'd be able to switch out all the instances of a for b and c using a function, as I've never really had to use a function like this before.
Function that prompts user for integer value and checks for valid input
If users only entered valid integer text on a line-by-line basis, then code is easy:
// Overly idealized case
fputs(prompt, stdout);
char buf[50];
fgets(buf, sizeof buf, stdin);
int i = atoi(buf);
But users are good, bad and ugly and **it happens. If code wants to read a line, parse it for an in-range int, and detect a host of problems, below is code that vets many of the typical issues of bogus and hostile input.
I especially interested in detecting overly long input as hostile and so invalid as a prudent design against hackers. As below, little reason to allow valid input for a 32-bit int with more than 20 characters. This rational deserve a deeper explanation.
End-of-file
Input stream error
Overflow
No leading numeric test
Trailing non-numeric text
Excessive long line
First a line of input is read with fgets() and then various int validation tests applied. If fgets() did not read the whole line, the rest is then read.
#include <limits.h>
#include <ctype.h>
// Max number of `char` to print an `int` is about log10(int_bit_width)
// https://stackoverflow.com/a/44028031/2410359
#define LOG10_2_N 28
#define LOG10_2_D 93
#define INT_DEC_TEXT (1 /*sign*/ + (CHAR_BIT*sizeof(int)-1)*LOG10_2_N/LOG10_2_D + 1)
// Read a line and parse an integer
// Return:
// 1: Success
// 0: Failure
// EOF: End-of-file or stream input error
int my_get_int(int *i) {
// Make room for twice the expected need. This allows for some
// leading/trailing spaces, leading zeros, etc.
// int \n \0
char buf[(INT_DEC_TEXT + 1 + 1) * 2];
if (fgets(buf, sizeof buf, stdin) == NULL) {
*i = 0;
return EOF; // Input is either at end-of-file or a rare input error.
}
int success = 1;
char *endptr;
errno = 0;
long value = strtol(buf, &endptr, 10);
// When `int` is narrower than `long`, add these tests
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (value < INT_MIN) {
value = INT_MIN;
errno = ERANGE;
} else if (value > INT_MAX) {
value = INT_MAX;
errno = ERANGE;
}
#endif
*i = (int) value;
if (errno == ERANGE) {
success = 0; // Overflow
}
if (buf == endptr) {
success = 0; // No conversion
}
// Tolerate trailing white-space
// Proper use of `is...()` obliges a `char` get converted to `unsigned char`.
while (isspace((unsigned char ) *endptr)) {
endptr++;
}
// Check for trailing non-white-space
if (*endptr) {
success = 0; // Extra junk
while (*endptr) { // quietly get rest of buffer
endptr++;
}
}
// Was the entire line read?
// Was the null character at the buffer end and the prior wasn't \n?
const size_t last_index = sizeof buf / sizeof buf[0] - 1;
if (endptr == &buf[last_index] && buf[last_index - 1] != '\n') {
// Input is hostile as it is excessively long.
success = 0; // Line too long
// Consume text up to end-of-line
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
;
}
}
return success;
}
Sample usage
puts("Enter a value for a: ", stdout);
fflush(stdout); // Insure output is seen before input.
int a;
if (my_get_int(&a) == 1) {
printf("a:%d\n", a);
}
My question is, how can I combine the first function with everything in the do/while loop to make one big function that I can call three times?
Well, the function need not be big. The things to factor out are the prompt string and the variable to read - the latter can be left in the calling main() and assigned from a return value. Regarding how you would normally check the input, I recommend leaving this checking to scanf() and just test its return value.
#include <stdio.h>
#include <stdlib.h>
int input(char *prompt)
{ // prompts user to input integer
// reads an integer from standard input and returns it
int a, s; // leave it to scanf to check the input:
while (printf("%s", prompt), fflush(stdout), s = scanf("%d", &a), !s)
{
printf("INPUT ERROR!\n");
do s = getchar(); while (s != '\n' && s != EOF); // consume bad input
}
if (s == EOF) puts(""), exit(0); // no more input
return a;
}
In main() you can then just do
a = input("Enter a value for a: ");
b = input("Enter a value for b: ");
c = input("Enter a value for c: ");
(without a loop).
scanf() already processes the input for you according to the format specifier (%d) so you just need to understand how scanf works and use it to check and build your function :)
When you write scanf("%d", &a); the program expects you write an integer because of the %d specifier, and if an integer is read, the program writes it into variable a.
But the function scanf also has a return value, ie, you can do check = scanf("%d", &a); and check will have a value of 0 or 1 in this case. This is because the return value records how many values have been successfuly read. If you entered dsfugnodg there's no number so it would return 0. If you entered 659 32 it would read the 1st value successfully and return 1.
Your function would look something like:
#include <stdio.h>
int getAndPrint(char label)
{
int n = 0, val = 0;
do {
printf("Enter a value for %c: ", label);
n = scanf("%d", &val);
if (n == 0) {
printf("Error, invalid value entered.\n");
/* Consume whatever character leads the wrong input
* to prevent an infinite loop. See:
* https://stackoverflow.com/questions/1669821/scanf-skips-every-other-while-loop-in-c */
getchar();
}
} while (n == 0);
printf("%c = %d\n", label, val);
return val;
}
int main()
{
int a, b, c;
a = getAndPrint('a');
b = getAndPrint('b');
c = getAndPrint('c');
printf("a=%d, b=%d, c=%d\n", a, b, c);
}
See also:
Scanf skips every other while loop in C
I think the following code is you wanted:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> // for isalpha
void InputAndCheck(int * pValue, const char * pName)
{
do
{
printf("Enter a value for %s: ", pName);
scanf("%d", pValue);
if (isalpha(*pValue))
{
printf("INPUT ERROR!\n");
continue;
}
else
{
break;
}
} while (1);
// clear the input buffer
fflush(stdin);
return;
}
int main()
{
int a, b, c;
InputAndCheck(&a, "a");
InputAndCheck(&b, "b");
InputAndCheck(&c, "c");
printf("a=%d;b=%d;c=%d;\r\n",a,b,c);
return 0;
}
What you are looking for is an introduction to functions.
Here is one : https://www.tutorialspoint.com/cprogramming/c_functions.htm
This is a very important building block in programming and you should definitely learn to master that concept.
functions will allow you to execute some code in different contexts over and over, just changing the context (the parameters).
It is declared like this
int add(int first, int second){
//here we can use first and second
printf("first: %d\n", first);
printf("second: %d\n", second);
//and eventually return a value
return first+second;
}
Now when using we are reusing our previous code to excute a task which result will vary depending of the arguments we pass.
printf("1+2 = %d\n", add(1, 2));
-->3
printf("2+2 = %d\n", add(2, 2));
-->4
Example solution for your task:
//this will handle validation
int validateInput(int input){
if(isalpha(input)){
printf("INPUT ERROR!\n");
return 0;
}
return 1;
}
//this will prompt the user and return input only if the input is valid
int askForCoefficient(unsigned char coefficientName){
int valid = 0;
int value = 0;
while(!valid){
printf("Enter a value for %c: ", coefficientName);
value = scanf("%d", &value);
valid = validateInput(value);
}
printf("%d\n", value);
return value;
}

Is there a way to check if a string can be a float in C?

Checking if it can be an int is easy enough -- just check that every digit is between '0' and '9'. But a float is harder. I found this, but none of the answers really work. Consider this code snippet, based on the top (accepted) answer:
float f;
int ret = sscanf("5.23.fkdj", "%f", &f);
printf("%d", ret);
1 will be printed.
Another answer suggested using strpbrk, to check if certain illegal characters are present, but that wouldn't work either because 5fin7 wouldn't be legal, but inf would.
Yet another answer suggested checking the output of strtod. But consider this:
char *number = "5.53 garbanzo beans"
char *foo;
strtod(number, &foo);
printf("%d", isspace(*foo) || *foo == '\0'));
It'll print 1. But I don't want to remove the isspace call entirely, because " 5.53 " should be a valid number.
Is there a good, elegant, idiomatic way to do what I'm trying to do?
The first answer should work if you combine it with %n, which is the number of characters read:
int len;
float ignore;
char *str = "5.23.fkdj";
int ret = sscanf(str, "%f %n", &ignore, &len);
printf("%d", ret==1 && !str[len]);
!str[len] expression will be false if the string contains characters not included in the float. Also note space after %f to address trailing spaces.
Demo
You could check if - after having read a value using strtod - the remainder consists solely of white spaces. Function strspn can help here, and you can even define "your personal set of white spaces" to consider:
int main() {
char *number = "5.53 garbanzo beans";
char *foo;
double d = strtod(number, &foo);
if (foo == number) {
printf("invalid number.");
}
else if (foo[strspn(foo, " \t\r\n")] != '\0') {
printf("invalid (non-white-space) trailing characters.");
}
else {
printf("valid number: %lf", d);
}
}
Is there a way to check if a string can be a float?
A problem with the sscanf(...,"%f") approach is on overflow, which is UB. Yet it is commonly handled nicely.
Instead use float strtof(const char * restrict nptr, char ** restrict endptr);
int float_test(const char *s) {
char *ednptr;
errno = 0;
float f = strtof(s, &endptr);
if (s == endptr) {
return No_Conversion;
}
while (isspace((unsigned char) *endptr)) { // look past the number for junk
endptr++;
}
if (*endptr) {
return Extra_Junk_At_End;
}
// If desired
// Special cases with with underflow not considered here.
if (errno) {
return errno; // likely under/overflow
}
return Success;
}
This is a variation on the code fragment posted by dasblinkenlight that is slightly simpler and more efficient as strlen(str) could be costly:
const char *str = "5.23.fkdj";
float ignore;
char c;
int ret = sscanf(str, "%f %c", &ignore, &c);
printf("%d", ret == 1);
Explanation: sscanf() returns 1 if and only if a float was converted, followed by optional white space and no other character.
This code is closely based on the answer by dasblinkenlight. I proffer it as food for thought. Some of the answers it gives may not be what you wanted.
#include <stdio.h>
#include <string.h>
static void test_float(const char *str)
{
int len;
float dummy = 0.0;
if (sscanf(str, "%f %n", &dummy, &len) == 1 && len == (int)strlen(str))
printf("[%s] is valid (%.7g)\n", str, dummy);
else
printf("[%s] is not valid (%.7g)\n", str, dummy);
}
int main(void)
{
test_float("5.23.fkdj"); // Invalid
test_float(" 255. "); // Valid
test_float("255.123456"); // Valid
test_float("255.12E456"); // Valid
test_float(" .255 "); // Valid
test_float(" Inf "); // Valid
test_float(" Infinity "); // Valid
test_float(" Nan "); // Valid
test_float(" 255 "); // Valid
test_float(" 0x1.23P-24 "); // Valid
test_float(" 0x1.23 "); // Valid
test_float(" 0x123 "); // Valid
test_float("abc"); // Invalid
test_float(""); // Invalid
test_float(" "); // Invalid
return 0;
}
Testing on a Mac running macOS Sierra 10.12.6 using GCC 7.1.0 as the compiler, I get the output:
[5.23.fkdj] is not valid (5.23)
[ 255. ] is valid (255)
[255.123456] is valid (255.1235)
[255.12E456] is valid (inf)
[ .255 ] is valid (0.255)
[ Inf ] is valid (inf)
[ Infinity ] is valid (inf)
[ Nan ] is valid (nan)
[ 255 ] is valid (255)
[ 0x1.23P-24 ] is valid (6.775372e-08)
[ 0x1.23 ] is valid (1.136719)
[ 0x123 ] is valid (291)
[abc] is not valid (0)
[] is not valid (0)
[ ] is not valid (0)
The hexadecimal numbers are likely to be particularly problematic. The various forms of infinity and not-a-number could be troublesome too. And the one example with an exponent (255.12E456) overflows float and generates an infinity — is that really OK?
Most of the problems raised here are definitional — that is, how do you define what you want to be acceptable. But note that strtod() would accept all the valid strings (and a few of the invalid ones, but other testing would reveal those problems).
Clearly, the test code could be revised to use an array of a structure containing a string and the desired result, and this could be used to iterate through the test cases shown and any extras that you add.
The cast on the result of strlen() avoids a compilation warning (error because I compile with -Werror) — comparison between signed and unsigned integer expressions [-Werror=sign-compare]. If your strings are long enough that the result from strlen() overflows a signed int, you've got other problems pretending they're valid values. OTOH, you might want to experiment with 500 digits after a decimal point — that's valid.
This code notes the comments made to dasblinkenlight's answer:
Leading blank in format
Tricky special circumstances
Outline fix — now adopted in the answer.
Maybe this? Not very good but may do the job. Returns -1 on error 0 on no conversions done and > 0 with converted numbers flags set.
#define INT_CONVERTED (1 << 0)
#define FLOAT_CONVERTED (1 << 1)
int ReadNumber(const char *str, double *db, int *in)
{
int result = (str == NULL || db == NULL || in == NULL) * -1;
int len = 0;
char *tmp;
if (result != -1)
{
tmp = (char *)malloc(strlen(str) + 1);
strcpy(tmp, str);
for (int i = strlen(str) - 1; i >= 0; i--)
{
if (isspace(tmp[i]))
{
tmp[i] = 0;
continue;
}
break;
}
if (strlen(tmp))
{
if (sscanf(tmp, "%lf%n", db, &len) == 1 && strlen(tmp) == len)
{
result |= FLOAT_CONVERTED;
}
if (sscanf(tmp, "%d%n", in, &len) == 1 && strlen(tmp) == len)
{
result |= INT_CONVERTED;
}
}
free(tmp);
}
return result;
}

Scanf for reading string and int array in brackets

I've been trying to come up with solution for reading input which contains string and then brackets with array of numbers (I don't know how many numbers will be inputed.
Input could look like:
sacrifice (1, 2, 4, 2)
I am wondering if it is possible to achieve with scanf. I've been looking for different functions such as getline, sscanf, fgets and so on. But I couldn't come up with solution.
My code looks like this:
scanf("%[^(]", command);
while ( ( c = getchar() ) != ')' )
{
scanf("%d", weights[pos]);
pos++;
}
Which should read string until the bracket is found and then I tried to load the numbers in array as long as it doesn't reach the ')'. Yet it doesn't seem to work.
Is scanf viable to achieve this? Could anyone point me in better direction if not please?
I think it would be simpler to read the complete line from stdin and then parse it by hand using strtok or strcspn. Something like below could be done.
Disclaimer: This is just some sample code and doesn't handle all possible inputs and will crash with invalid input, it is just to give you an idea about how to do it. If you want to go this way, you would have to handle various error conditions, such as:
checking return value of malloc/getline/realloc
instead of atoi using a better function like strtol (which allows error checking),
handling white spaces in the input and
handling input which does not contain any parenthesis
Those are some of the many things which you would have to think about.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int *parse_numbers(char *numstr, size_t *size)
{
char *p;
char *s = numstr;
char *last;
size_t array_size = 10;
int *numbers = malloc(sizeof(int) * array_size);
size_t offset = 0;
for (p = strtok_r(s, ",", &last); p; p = strtok_r(NULL, ",", &last)) {
if (offset == array_size) {
array_size *= 2;
numbers = realloc(numbers, sizeof(int) * array_size);
//TODO do error check
}
numbers[offset++] = atoi(p); //strtol would be a better choice
}
*size = offset;
return numbers;
}
int main()
{
char *s = NULL;
char *p;
char *last;
int i = 0;
int *numbers;
size_t size;
size_t linesize = 0;
getline(&s, &linesize, stdin);
for (p = strtok_r(s, "(", &last); p; p = strtok_r(NULL, "(", &last)) {
if (i++ == 0) {
//This is the part of the string before '('
cmd = p;
} else {
// This is the part of the string after '('
numbers = parse_numbers(p, &size);
}
}
for (i = 0; i < size; i++) {
printf("%d\n", numbers[i]);
}
free(numbers);
free(s);
return 0;
}
Separate input from parsing. Far easier to handle the various issues of command processing. Concerning "don't know how many numbers will be inputed", IMO, a reasonable upper bound should be established. Else code is susceptible to overwhelming memory resources due to user input - a hacker exploit.
char command[1000];
while (fgets(command, sizeof command, stdin)) {
Now process the command using sscanf(), strtok() or your own code. The best method depends on maybe things not posted by OP, especially error handling.
int cmd_start;
int cmd_end;
int n = 0;
// sacrifice (1, 2, 4, 2, ...)
// +----------------- skip optional white space
// |+---------------- record scan position
// || +-------------- scan, but not save, lower case letters
// || | +------- record scan position
// || | | +----- skip optional white space
// || | | |+---- scan (
// || | | ||+--- skip optional white space
// || | | |||+-- record scan position
sscanf(command, " %n%*[a-z]%n ( %n", &cmd_start, &cmd_end, &n);
if (n == 0) {
printf("Invalid command '%s'\n", command);
continue;
}
int x[sizeof command / 2];
int x_count = 0;
char *p = &command[n]; // pick up where previous scan ended.
char sep[2] = {0};
while (sscanf(p, "%d %1[,)] %n", &x[x_count], sep, &n) == 2) {
x_count++;
p += n;
if (sep[0] == ')') break;
}
if (*p || sep[0] != ')') {
printf("Invalid separator '%s'\n", command);
continue;
}
// Use command
command[cmd_end] = '\0';
Process_Command(&command[cmd_start], x, x_count);
}
scanf("%d", weights[pos]); --> scanf("%d", &weights[pos]); – BLUEPIXY
That's indeed adequate to make the code work, provided a sufficiently dimensioned weights array.

A basic/ manual way to check that a value entered by the user is numeric

I've searched in and out of these forums but am still having trouble. My understanding of C is still very basic. I'm creating a small program that takes 3 numerical values entered by the user and then calculates the highest. I nailed that.
I now want to ensure that the user enters only integer values. I managed to get the prog to keep prompting the user to re-enter the value until it is within the specified numerical range (for example, any number between 1 and 1000 inclusive, piece of cake) but that's not good enough. I used 3 while loops to test each value, but this only works as long as the input is of type integer.
The trick is I cant use built in functions. It needs to be manual (sorry, poor choice of words) I tried to use char variables and x = getchar(); to get the ASCII value and test it in a condition but I can't get it working in a loop. (while/ do-while)
I also tried using a "for loop" and array variables but once again am struggling to get it to keep prompting the user.
I've also tried to test the value returned by scanf to see if its integer but my knowledge level of correct C syntax is level: noob. Either my loops don't loop or they loop infinitely.
Here is some sample code:
int x, y, z =0;
printf("Enter the first number:\n");
scanf("d", &x);
while (condition) /* Here is where I need to determine that the entered val is false */
{
printf("Wrong input. Re-enter a valid value.\n");
x =0;
scanf("%d", &x); /*user re-prompted */
}
I'm getting the idea that I'll have to use ASCII and a loop, but I just can't get to it. Also, the values entered get sent to a function for comparing and are then returned.
Could someone give me some advice and a few tips please?
Much thanks
You would have to use something like fgets, and strtol:
long someValue;
char *bufEnd = NULL;
char buf[128]; // max line size
do {
printf("enter a value: ");
fgets(buf, 128, stdin);
someValue = strtol(buf, &bufEnd, 10); // base 10
} while (bufEnd == buf || *bufEnd != '\n');
printf("got value: %li", someValue);
What we are doing here is we are tapping into strtol's capability to tell us where it stopped parsing, by passing in bufEnd.
Then, we are making sure that bufEnd doesn't point to the beginning of buf (in which case, it didn't start with a number), and also checking to make sure that bufEnd points to \n, or the end of the line (making sure that the user didn't enter something like 123abc, which strtol would interpret as 123). You may wish to trim buf of whitespace characters first, however.
You're absolutely on the right track with "scanf()". Just check the return value. If you don't get the expected #/values, then you got invalid input:
char found = FALSE;
int ival;
double x;
while (!found)
{
printf("Please enter a valid integer: ");
if (scanf("%d", &ival) !=1) {
printf ("Invalid! Please re-enter!\n");
continue;
}
printf("Please enter a valid floating point number: ");
if (scanf("%lf", &x) !=1) {
printf ("Invalid! Please re-enter!\n");
continue;
}
found = TRUE;
}
Here's my solution. It safe against buffer overflow and straightforward .
#include <stdio.h>
#define LEN 10
int main() {
int a;
char str[LEN];
fgets( str, LEN, stdin );
while ( !sscanf( str, "%d", &a ) )
fgets( str, 10, stdin );
printf("Num is : %d\n", a);
return 0;
}
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
int getInteger(int* err){
int ch;
int n;//int32
int takeNum, sign;
long long int wk;//long long int as int64
wk=0LL;
*err = 0;
takeNum = 0;//flag
sign = 1;//minus:-1, other:1
/* //skip space character
while(EOF!=(ch=getchar()) && (ch == ' ' || ch == '\t' || ch == '\n'));
ungetc(ch, stdin);
*/
while(EOF!=(ch=getchar())){
if(ch == '-'){
if(takeNum != 0){//in input number
*err = 1;
break;
}
if(sign == -1){//already sign
*err = 2;
break;
}
sign = -1;
continue;
}
if(ch >= '0' && ch <= '9'){//isdigit(ch) in ctype.h
if(takeNum == 0)
takeNum = 1;
wk = wk * 10 + (ch - '0')*sign;
if(INT_MAX < wk || INT_MIN > wk){//overflow
*err = 3;
break;
}
continue;
}
if(ch != '\n'){//input other [-0-9]
*err = 4;
}
break;
}
if(takeNum == 0){//not input number
*err = 5;
} else {
n=wk;
}
while(ch != '\n' && EOF!=(ch=getchar()));//skip to newline
return n;
}
int getValue(const char* redoprompt, int low, int high){
int num, err=0;
while(1){
num = getInteger(&err);
if(err || low > num || high < num)
printf("%s", redoprompt);
else
break;
}
return num;
}
#define max(x,y) ((x)>(y))? (x) : (y)
int main(){
const char *error_message = "Wrong input. Re-enter a valid value.\n";
int x, y, z, max;
x = getValue(error_message, 1, 1000);
y = getValue(error_message, 1, 1000);
z = getValue(error_message, 1, 1000);
max = max(max(x,y), z);
printf("max:%d\n", max);
return 0;
}

Resources