I am getting the user to input 4 numbers. They can be input: 1 2 3 4 or 1234 or 1 2 34 , etc. I am currently using
int array[4];
scanf("%1x%1x%1x%1x", &array[0], &array[1], &array[2], &array[3]);
However, I want to display an error if the user inputs too many numbers: 12345 or 1 2 3 4 5 or 1 2 345 , etc.
How can I do this?
I am very new to C, so please explain as much as possible.
//
Thanks for your help.
What I have now tried to do is:
char line[101];
printf("Please input);
fgets(line, 101, stdin);
if (strlen(line)>5)
{
printf("Input is too large");
}
else
{
array[0]=line[0]-'0'; array[1]=line[1]-'0'; array[2]=line[2]-'0'; array[3]=line[3]-'0';
printf("%d%d%d%d", array[0], array[1], array[2], array[3]);
}
Is this a sensible and acceptable way? It compiles and appears to work on Visual Studios. Will it compile and run on C?
OP is on the right track, but needs adjust to deal with errors.
The current approach, using scanf() can be used to detect problems, but not well recover. Instead, use a fgets()/sscanf() combination.
char line[101];
if (fgets(line, sizeof line, stdin) == NULL) HandleEOForIOError();
unsigned arr[4];
int ch;
int cnt = sscanf(line, "%1x%1x%1x%1x %c", &arr[0], &arr[1], &arr[2],&arr[3],&ch);
if (cnt == 4) JustRight();
if (cnt < 4) Handle_TooFew();
if (cnt > 4) Handle_TooMany(); // cnt == 5
ch catches any lurking non-whitespace char after the 4 numbers.
Use %1u if looking for 1 decimal digit into an unsigned.
Use %1d if looking for 1 decimal digit into an int.
OP 2nd approach array[0]=line[0]-'0'; ..., is not bad, but has some shortcomings. It does not perform good error checking (non-numeric) nor handles hexadecimal numbers like the first. Further, it does not allow for leading or interspersed spaces.
Your question might be operating system specific. I am assuming it could be Linux.
You could first read an entire line with getline(3) (or readline(3), or even fgets(3) if you accept to set an upper limit to your input line size) then parse that line (e.g. with sscanf(3) and use the %n format specifier). Don't forget to test the result of sscanf (the number of read items).
So perhaps something like
int a=0,b=0,c=0,d=0;
char* line=NULL;
size_t linesize=0;
int lastpos= -1;
ssize_t linelen=getline(&line,&linesize,stdin);
if (linelen<0) { perror("getline"); exit(EXIT_FAILURE); };
int nbscanned=sscanf(line," %1d%1d%1d%1d %n", &a,&b,&c,&d,&lastpos);
if (nbscanned>=4 && lastpos==linelen) {
// be happy
do_something_with(a,b,c,d);
}
else {
// be unhappy
fprintf(stderr, "wrong input line %s\n", line);
exit(EXIT_FAILURE);
}
free(line); line=NULL;
And once you have the entire line, you could parse it by other means like successive calls of strtol(3).
Then, the issue is what happens if the stdin has more than one line. I cannot guess what you want in that case. Maybe feof(3) is relevant.
I believe that my solution might not be Linux specific, but I don't know. It probably should work on Posix 2008 compliant operating systems.
Be careful about the result of sscanf when having a %n conversion specification. The man page tells that standards might be contradictory on that corner case.
If your operating system is not Posix compliant (e.g. Windows) then you should find another way. If you accept to limit line size to e.g. 128 you might code
char line[128];
memset (line, 0, sizeof(line));
fgets(line, sizeof(line), stdin);
ssize_t linelen = strlen(line);
then you do append the sscanf and following code from the previous (i.e. first) code chunk (but without the last line calling free(line)).
What you are trying to get is 4 digits with or without spaces between them. For that, you can take a string as input and then check that string character by character and count the number of digits(and spaces and other characters) in the string and perform the desired action/ display the required message.
You can't do that with scanf. Problem is, there are ways to make scanf search for something after the 4 numbers, but all of them will just sit there and wait for more user input if the user does NOT enter more. So you'd need to use gets() or fgets() and parse the string to do that.
It would probably be easier for you to change your program, so that you ask for one number at a time - then you ask 4 times, and you're done with it, so something along these lines, in pseudo code:
i = 0
while i < 4
ask for number
scanf number and save in array at index i
E.g
#include <stdio.h>
int main(void){
int array[4], ch;
size_t i, size = sizeof(array)/sizeof(*array);//4
i = 0;
while(i < size){
if(1!=scanf("%1x", &array[i])){
//printf("invalid input");
scanf("%*[^0123456789abcdefABCDEF]");//or "%*[^0-9A-Fa-f]"
} else {
++i;
}
}
if('\n' != (ch = getchar())){
printf("Extra input !\n");
scanf("%*[^\n]");//remove extra input
}
for(i=0;i<size;++i){
printf("%x", array[i]);
}
printf("\n");
return 0;
}
Related
Pre-History:
I had the issue, that the getchar() function did not get processed in the right way as there was not a request for any given input and the program just have continued processing further.
I searched the internet about what this issue could be and found the information that if the scanf() function is implemented into a program before the getchar() function, the getchar() function does not behave in the right way, and would act like my issue was.
Citation:
I will bet you ONE HUNDRED DOLLARS you only see this problem when the call to getchar() is preceded by a scanf().
Don't use scanf for interactive programs. There are two main reasons for this:
1) scanf can't recover from malformed input. You have to get the format string right, every time, or else it just throws away whatever input it couldn't match and returns a value indicating failure. This might be fine if you're parsing a fixed-format file when poor formatting is unrecoverable anyway, but it's the exact opposite of what you want to do with user input. Use fgets() and sscanf(), fgets() and strtok(), or write your own user input routines using getchar() and putchar().
1.5) Even properly used, scanf inevitably discards input (whitespace) that can sometimes be important.
2) scanf has a nasty habit of leaving newlines in the input stream. This is fine if you never use anything but scanf, since scanf will usually skip over any whitespace characters in its eagerness to find whatever it's expecting next. But if you mix scanf with fgets/getchar, it quickly becomes a total mess trying to figure out what might or might not be left hanging out in the input stream. Especially if you do any looping -- it's quite common for the input stream to be different on the first iteration, which results in a potentially weird bug and even weirder attempts to fix it.
tl;dr -- scanf is for formatted input. User input is not formatted. //
Here is the link, to that thread: https://bbs.archlinux.org/viewtopic.php?id=161294
scanf() with:
scanf("%x",integer_variable);
seems for me as a newbie to the scene as the only way possible to input a hex number from the keyboard (or better said the stdin file) and store it to a int variable.
Is there a different way to input a hex value from the stdin and store it into an integer variable?
Bonus challenge: It would be nice also, if i could write negative values (through negative hex input of course) into an signed int variable.
INFO: I have read many threads for C here on Stackoverflow about similar problems but none of those answer my explicit question quite well. So i´ve posted this question.
I work under Linux Ubuntu.
The quote about the hundred dollar bet is accurate. Mixing scanf with getchar is almost always a bad idea; it almost always leads to trouble. It's not that they can't be used together, though. It's possible to use them together -- but usually, it's just way too difficult. There are too many fussy little details and "gotcha!"s to keep track of. It's more trouble than it's worth.
At first you had said
scanf() with ... %d ... seems for me as a newbie to the scene as the only way possible to input a hex number from the keyboard
There was some side confusion there, because of course %d is for decimal input. But since I'd written this answer by the time you corrected that, let's proceed with decimal for the moment.
(Also for the moment I'm leaving out error checking -- that is, these code fragments don't check for or do anything graceful if the user doesn't type the requested number.) Anyway, here are several ways of reading an integer:
scanf("%d", &integer_variable);
You're right, this is the (superficially) easiest way.
char buf[100];
fgets(buf, sizeof(buf), stdin);
integer_variable = atoi(buf);
This is, I think, the easiest way that doesn't use scanf. But most people these days frown on using atoi, because it doesn't do much useful error checking.
char buf[100];
fgets(buf, sizeof(buf), stdin);
integer_variable = strtol(buf, NULL, 10);
This is almost the same as before, but avoids atoi in favor of the preferred strtol.
char buf[100];
fgets(buf, sizeof(buf), stdin);
sscanf(buf, "%d", &integer_variable);
This reads a line and then uses sscanf to parse it, another popular and general technique.
All of these will work; all of these will handle negative numbers. It's important to think about error conditions, though -- I'll have more to say about that later.
If you want to input hexadecimal numbers, the techniques are similar:
scanf("%x", &integer_variable);
char buf[100];
fgets(buf, sizeof(buf), stdin);
integer_variable = strtol(buf, NULL, 16);
char buf[100];
fgets(buf, sizeof(buf), stdin);
sscanf(buf, "%x", &integer_variable);
These should all work, too. I wouldn't necessarily expect them to handle "negative hexadecimal", though, because that's an unusual requirement. Most of the time, hexadecimal notation is used for unsigned integers. (In fact, strictly speaking, %x with scanf and sscanf must be used with an integer_variable that has been declared as unsigned int, not plain int.)
Sometimes it's useful or necessary to do this sort of thing "by hand". Here's a code fragment that reads exactly two hexadecimal digits. I'll start out with the version using getchar:
int c1 = getchar();
if(c1 != EOF && isascii(c1) && isxdigit(c1)) {
int c2 = getchar();
if(c2 != EOF && isascii(c2) && isxdigit(c2)) {
if(isdigit(c1)) integer_variable = c1 - '0';
else if(isupper(c1)) integer_variable = 10 + c1 - 'A';
else if(islower(c1)) integer_variable = 10 + c1 - 'a';
integer_variable = integer_variable * 16;
if(isdigit(c2)) integer_variable += c2 - '0';
else if(isupper(c2)) integer_variable += 10 + c2 - 'A';
else if(islower(c2)) integer_variable += 10 + c1 - 'a';
}
}
As you can see, it's a bit of a jawbreaker. Me, although I almost never use members of the scanf family, this is one place where I sometimes do, precisely because doing it "by hand" is so much work. You can simplify it considerably by using an auxiliary function or macro to do the digit conversion:
int c1 = getchar();
if(c1 != EOF && isascii(c1) && isxdigit(c1)) {
int c2 = getchar();
if(c2 != EOF && isascii(c2) && isxdigit(c2)) {
integer_variable = Xctod(c1);
integer_variable = integer_variable * 16;
integer_variable += Xctod(c2);
}
}
Or you could collapse those inner expressions down to just
integer_variable = 16 * Xctod(c1) + Xctod(c2);
These work in terms of an auxiliary function:
int Xctod(int c)
{
if(!isascii(c)) return 0;
else if(isdigit(c)) return c - '0';
else if(isupper(c)) return 10 + c - 'A';
else if(islower(c)) return 10 + c - 'a';
else return 0;
}
Or perhaps a macro (though this is definitely an old-school sort of thing):
#define Xctod(c) (isdigit(c) ? (c) - '0' : (c) - (isupper(c) ? 'A' : 'a') + 10)
Often I'm parsing hexadecimal digits like this not from stdin using getchar(), but from a string. Often I'm using a character pointer (char *p) to step through the string, meaning that I end up with code more like this:
char c1 = *p++;
if(isascii(c1) && isxdigit(c1)) {
char c2 = *p++;
if(isascii(c2) && isxdigit(c2))
integer_variable = 16 * Xctod(c1) + Xctod(c2);
}
It's tempting to omit the temporary variables and the error checking and boil this down still further:
integer_variable = 16 * Xctod(*p++) + Xctod(*p++);
But don't do this! Besides the lack of error checking, this expression is probably undefined, and it definitely won't always do what you want, because there's no longer any guarantee abut what order you read the characters in. If you know p points at the first of two hex digits, you don't want to collapse it any further than
integer_variable = Xctod(*p++);
integer_variable = 16 * integer_variable + Xctod(*p++);
and even then, this will work only with the function version of Xctod, not the macro, since the macro evaluates its argument multiple times.
Finally, let's talk abut error handling. There are quite a few possibilities to worry about:
The user hits Return without typing anything.
The user types whitespace before or after the number.
The user types extra garbage after the number.
The user types non-numeric input instead of a number.
The code hits end-of-file; there are no characters to read at all.
And then how you handle these depends on what input techniques you're using. Here are the basic rules:
A. If you're calling scanf, fscanf, or sscanf, always check the return value. If it's not 1 (or, in the case where you had multiple % specifiers, it's not the number of values you expected to read), it means something went wrong. This will generally catch problems 4 and 5, and will handle case 2 gracefully. But it will often quietly ignore problems 1 and 3. (In particular, scanf and fscanf treat an extra \n just like leading whitespace.)
B. If you're calling fgets, again, always check the return value. You'll get NULL on EOF (problem 5). Handling the other problems depends on what you do with the line you read.
C. If you're calling atoi, it will deal gracefully with problem 2, but it will ignore problem 3, and it will quietly turn problem 4 into the number 0 (which is why atoi is usually not recommended any more).
D. If you're calling strtol or any of the other "strto" functions, they will deal gracefully with problem 2, and if you let them give you back an "end pointer", you can check for and deal with problems 3 and 4. (Note that I left the end-pointer handling out of my two strtol examples above.)
E. Finally, if you're doing something down-and-dirty like my "hardway" two-digit hex converter, you generally have to take care of all these problems, explicitly, yourself. If you want to skip leading whitespace you have to do so (the isspace function from <ctype.h> can help), and if there might be unexpected non-digit characters, you have to check for those, too. (That's what the calls to isascii and isxdigit are doing in my "hardway" two-digit hex converter.)
Per scanf man page, you can use scanf to read hex number from stdin into (unsigned) integer variable.
unsigned int v ;
if ( scanf("%x", &v) == 1 ) {
// do something with v.
}
As per man page, %x is always unsigned. If you want to support negative values, you will have to add explicit logic.
As mentioned in the link you posted, using fgets and sscanf is the best way to handle this. fgets will read a full line of text and sscanf will parse the line.
For example
char line[100];
fgets(line, sizeof(line), stdin);
int x;
int rval = sscanf(line, "%x", &x);
if (rval == 1) {
printf("read value %x\n", x);
} else {
printf("please enter a hexadecimal integer\n");
}
Since you're only reading in a single integer, you could also use strtol instead of sscanf. This also has the advantage of detecting if any additional characters were entered:
char *ptr;
errno = 0;
long x = strtol(line, &ptr, 16);
if (errno) {
perror("parsing failed");
} else if (*ptr != '\n' && *ptr != 0) {
printf("extra characters entered: %s\n", ptr);
} else {
printf("read value %lx\n", x);
}
I am previously a java programmer, but I'm now doing a C course at university (computer science major).
I need the user to be able to enter 3 chars,the first 2 being numbers, and the last 1 being either 'v' or 'h'.
For example "1 2 v".
I need the user to be able to enter it with the spaces in between each character.
This is my current code:
void manageInput(char box[][width]){
char move[4];
char input[16];
while(1){
scanf("%s", input);
int i = 0;
while(input[i] != 0){
if(input[i] != ' ' && input[i] != "\n"){
move[i] = input[i];
}
i++;
}
printf("%s\n", move);
makeMove(box, move);
printBox(box, height, width);
// TODO
if(move[0] == 'x'){
exit(0);
}
}
}
However if I run it, it works fine when I enter the chars with out spaces like "12v", but If I enter "1 2 v", it will print out "1", call printBox, then print out "2", then print out box again, and so on.
If someone could explain what I'm doing wrong here, I would appreciate it.
If someone could explain what I'm doing wrong here, I would appreciate it.
The short story is: Your code doesn't fulfill your requirements. It simply doesn't do what you want it to do.
Your requirements are:
All fields must be one character. This requirement isn't fulfilled by your code. Your code will mistakenly accept multiple characters per field.
There must be one space (exactly one space?) between the fields. This requirement isn't fulfilled by your code. There might be multiple spaces between the fields, and your code will mistakenly accept that.
In fact, your code invokes undefined behaviour by accessing the move array out of bounds. Consider that as a consequence of one of the above scenarios i might become some value higher than 3. What might happen in this code: move[i] = input[i];?
Your code is also way too complex. All of your functionality can be performed by scanf alone. It's a very powerful function, when you know how to use it correctly... I suggest reading and understanding the manual multiple times, when you have an opportunity. You'll learn a lot!
I notice something you neglected to mention from within the logic you have presented: It's expected that the first field might also be 'x', which corresponds to an exit usecase. This is a bad design; the caller has no opportunity to clean up... but I'll run with it. You really should use return (and return an int value or something, corresponding to error/success) instead.
Let us caste that last paragraph aside, because we can simply consider 'x' to be invalid input (and exit as a result), and I don't want to change the contracts of your functions; I'll leave that to you. The expression described so far appears to be int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);.
Note that it is expected that a, b and c will have enough space to store a string of one byte in length. That is, their declaration should look like: char a[2], b[2], c[2];.
Make sure you check the return value (x, in the example)! If x is 3, it's safe to assume that the three variables a, b and c are safe to use. If x is 2, it's safe to assume that a and b are safe to use, and so on... If x is EOF or 0, none of them are safe to use.
By checking the return value, you can reject input that doesn't match that precise pattern, that is:
Fields that aren't exactly one byte in width will be rejected.
Too many or too few spaces will be rejected.
Something else popped up that you have neglected to mention, and it's also present within your code: Chux mentioned that you'll likely be expecting the input to be terminated with a '\n' (newline) character. This can also be implemented in a number of ways using scanf:
scanf("%1*[\n]"); will attempt to read and discard precisely one '\n' character, but there's no way to ensure that was successful. getchar would be more appropriate for that purpose; something along the lines of if (getchar() != '\n') { exit(EXIT_FAILURE); } might make sense, if you wish to ensure that the lines of input are perfectly formed and bomb out when they aren't... #define BOMB_OUT?
scanf("%*[^\n]"); scanf("%*c"); makes more sense; If you're interested in reading one item per line, then it makes sense to discard everything remaining on the line, and then the newline character itself. Note that your program should always tell the user when it's discarding or truncating input. You could also use getchar for this.
void manageInput(char box[][width]){
for (;;) {
char a[2], b[2], c[2];
int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);
if (x != 3) {
/* INVALID INPUT should cause an error value to be returned!
* However, this function has no return value (which makes it
* poorly designed)... Calling `exit` gives no opportunity for
* calling code to clean up :(
*/
exit(EXIT_FAILURE);
}
if (getchar() != '\n') {
# ifdef BOMB_OUT
exit(EXIT_FAILURE);
# else
scanf("%*[^\n]");
getchar();
puts("NOTE: Excess input has been discarded.");
# endif
}
char move[4] = { a[0], b[0], c[0] };
printf("%s\n", move);
makeMove(box, move);
printBox(box, height, width);
// TODO
if(move[0] == 'x'){
exit(0);
}
}
}
%s reads a whitespace-delimited string with scanf, so if that's not what you want, it's not the thing to use. %c reads a single character, but does not skip whitespce, so you probably also want a (space) in your format to skip whitespace:
char input[3];
scanf(" %c %c %c", intput, input+1, input+2);
will read 3 non-whitespace characters and skip any whitespace before or between them. You should also check the return value of scanf to make sure that it is 3 -- if not, there was less than 3 characters in your input before an end-of-file was reached.
It's usuall a bad idea to read string via scanf because of potential buffer overflow. Consider using fscanf or better fgets as in
fgets(input, 15, stdin);
Note the extra byte for '\0'.
Also, you're comparing char to string here: input[i] != "\n". It should be input[i] != '\n' instead.
And btw you can just use something like
int x, y;
char d;
scanf("%d%d%c", &x, &y, &d);
This looks like two simple bugs.
You need to use separate indexes for move[] and input[]
int i = 0;
while(input[i] != 0){
if(input[i] != ' ' && input[i] != "\n"){
move[i] = input[i];
}
i++;
}
Imagine input of 1 2 v
input[0] != 0, so we enter the loop
it's not ' ' or '\n' either, so we copy input[0] to move[0]
so far so good
You increment i, and discover that input[1] == ' '
But then you increment i again
You discover that you are interested in input[2] (2) - so you copy it to move[2], rather than move[1]. Oops!
Then to make things worse, you never put an end-of-string character after the last valid character of move[].
I have a file like this one:
1234 Homer 18.5
1223 Bart 25.5
9341 Lisa 30.0
3420 Marge 28.4
8730 Abram 26.7
1876 Barns 27.8
1342 Smiters 23.0
7654 Milhouse 29.7
How can i get the first part ( for example 1234 ) of each line?
And how can i get the name ( for example Homer ) of each line?
I wrote this code below:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
char ch[25];
int i, num;
FILE *fp;
fp = fopen("studenti.txt","r"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of numeri.txt file are :\n");
for(i = 0; i < 25; i++){
while( ( ch[i] = fgetc(fp) ) != EOF ){
if(!(ch[i] >= 'A' && ch[i] <= 'Z') && !( ch[i] >= 'a' && ch[i] <='z')){printf("%c",ch[i]);}
}}
fclose(fp);
return 0;
}
How can do that??
This is what fscanf function is for:
int n;
char name[25];
float x;
FILE* fp = ...
while (fscanf(fp, "%d%24s%f", &n, name, &x) == 3) {
// Do something with the data you just read:
printf("int=%d name='%s' float=%f\n", n, name, x);
}
Several things to note about the above:
fscanf returns the number of items it read from the file. Continue calling fscanf while it returns 3
%24s means "a string of up to 24 characters in length". name has 25 characters, because the last one is used for null termination
int and float parameters are passed to fscanf with an ampersand, because fscanf needs a pointer. String, on the other hand, takes no ampersand, because it's equivalent to a pointer.
If you are sure of the text format, the simplest may be to use fscanf.
int num;
char name[1024];
float grade;
fscanf(fp, "%d %s %f", &num, name, &grade);
Be aware, if the name is longuer than 1024 chars, you will have buffer overflows. If the format is not sure, you need to check the return code of fscanf (see the man page).
The only thing you ever read from files is bytes.
The first step is to check if the bytes are valid characters, and convert the bytes into characters if necessary. This is not necessarily simple. If the bytes are supposed to be ASCII, then you might only need to check if the bytes are valid ASCII (e.g. not less than or equal to zero and not above 0x80; and possibly not control characters like "delete" or "vertical tab").
However, where names are involved it's extremely unlikely that ASCII is adequate. This means you want something like UTF-8. In that case, at a minimum you need to check if the bytes are valid (variable length) UTF-8 sequences; in addition to checking for invalid characters (like "delete" or "vertical tab").
More complicated is if you simply don't know what the bytes are. There are ways to auto-detect the character encoding (but it's heuristics not 100% reliable).
The second step is parsing. Parsing typically has 2 equally important goals. The first goal is to convert the characters into a more easily processed form - e.g. like maybe a structure with 3 fields (an integer, string and float) representing each line of characters. The second goal of parsing is reporting any errors to the user in an easily understood manner.
For example, maybe the first number on each line must be a 4 digit code (like "0123"); and if there's only 3 digits (like "123") then you want to generate an error (e.g. "ERROR: CourseID too short on line 5 of file 'foo.txt'") so that it's easy for the user to know exactly what the problem is and easy for the user to fix it.
Note: I don't think I've ever seen code that uses fscanf() that is close to (what I consider) acceptable. There's almost never useful/descriptive error messages.
I've been looking into a way to obtain 2 integers, seperated by a space, that are located in the first line of a file that I would read. I considered using
fscanf(file, "%d %d\n", &wide, &high);
But that read 2 integers that were anywhere in the file, and would give the wrong output if the first line was in the wrong format. I also tried using
char line[1001];
fgets(line, 1000, file);
Which seems like the best bet, except for how clumsy it is. It leaves me with a string that has up to a few hundred blank spaces, from which I must extract my precious integers, nevermind checking for errors in formatting.
Surely there is a better option than this? I'll accept any solution, but the most robust solution seems (to me) to be a fscanf on the first line only. Any way to do that?
You can capture the character immediately following the second number in a char, and check that the captured character is '\n', like this:
int wide, high;
char c;
if (fscanf(file, "%d%d%c", &wide, &high, &c) != 3 || c != '\n') {
printf("Incorrect file format: expected two ints followed by a newline.");
}
Here is a demo on ideone.
Which seems like the best bet, except for how clumsy it is.
Nah, it's not clumsy at all (except that you are using the size argument of fgets() in the wrong way...). It's perfectly fine & idiomatic. strtol() does its job pretty well:
char line[LINE_MAX];
fgets(line, sizeof line, file);
char *endp;
int width = strtol(line, &endp, 10);
int height = strtol(endp, NULL, 10);
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)