I'm currently trying writing a program using C (very new to C - only been learning it for 2 weeks), and I wanted to get a string of input from the user by stdin, in which the string has a char, followed by 2 floats (each has space in between). Example would be: "y 2.1 1.1".
My question is how can I obtain and store the 3 inputs, while making sure the first is a char, and the following two inputs are floats?
Stick with sscanf(), but don't forget to check its return value (look here). What really happens for input "y 1u 1" is that sscanf will read and store the char, which is valid, then it will read and store the int 1, which is valid, and then stop, because "u" does not match the format string.
Below is example code (using scanf() rather then fgets() and sscanf()).
char in1;
int in2,in3;
int retval;
/*
char array[100] = {'\0'};
fgets(array, 100, stdin);
retval = sscanf(array, "%c %d %d", &in1, &in2, &in3);
*/
retval = scanf("%c %d %d", &in1, &in2, &in3);
printf("Scanned %d items\n", retval);
printf("Here they come: ");
if(retval > 0) {
printf("%c ", in1);
}
if(retval > 1) {
printf("%d ", in2);
}
if(retval > 2) {
printf("%d", in3);
}
putchar('\n');
How can I obtain and store the 3 inputs, while making sure the first is a char, and the following two inputs are ints?
problem with this code is that there are extra spaces at the very end, and I don't know how to get rid of it.
A simple way to use sscanf() and check if there is extra anything after the scanned variable is to use "%n" to record the location of the scan at that point.
char in1;
int in2, in3;
int n = 0;
sscanf(array,"%c %d %d%n", &in1, &in2, &in3, &n);
if (n > 0 && (array[n] == '\n' || array[n] == '\0')) {
Success(in1, in2, in3);
}
It is always important to check the results of sscanf(). One way is to check its return value which should be 3 here. Unfortunately that does not tell us if anything exist after in3. By setting n == 0 and then testing n > 0, code knows that scanning proceeded all the way successfully to "%n". Code can also test what character the scanning stopped at.
Related
The purpose of this code is to sum up to a number greater than zero and then ask the user if they want to sum another number. The summing part of the program works, but I can't seem to get the user input to work correctly. Any help or insight would be appreciated.
#include <stdio.h>
int main(void)
{
char * another;
int start = 0;
int x = 0;
int Input=0;
int sum = 0;
do
{
printf("Please enter a number greater than zero to sum up to: \n");
scanf("%d", &x);
if(start<x)
Input=1;
else
printf("The number needs to be greater than zero.\n");
}
while (Input ==0) ;
while (start <= x) {
sum += start;
start++;
if (start >x)
{
printf("The sum of the numbers 0 to %d is: %d \n" ,x , sum);
}
while (start >x)
{
printf("Would you like to sum another number? Y/N:");
scanf("%s",another);
}
} while ((another =="y")||(another=="Y"));
return 0;
}
There are quite a few things to address here.
char *another allocates no memory for a string to be placed. It is just an uninitialized pointer to memory, containing a garbage value. Utilizing this value in any way will invoke Undefined Behavior.
You must allocate some memory if you want to store a string. The easiest way is on the stack, as a character array:
char another[64];
Strings should not be compared with ==, as that compares their addresses, which even for two identical literals ("a" == "a") might not be the same. Use strcmp to compare strings.
There is no while ... while.
while (start <= x) {
/* ... */
} while ((another =="y")||(another=="Y"));
This is one while statement with a Compound Statement for a body, followed by another, separate while statement with an empty Expression Statement for a body.
More clearly read as:
while (start <= x) {
/* ... */
}
while ((another =="y")||(another=="Y"));
It is of course possible to have a do ... while whose body is itself a while statement
do
while (/* ... */) {
/* ... */
}
while (/* ... */);
but this is a bit confusing, and probably not what you really want.
The return value of scanf should be checked such that it matches the number of conversions you expected to succeed, in order to proceed to work with that data.
if (scanf("%d", &x) != 1) {
/* Something has gone wrong, handle it */
}
Failure to check this value can result in using uninitialized or otherwise indeterminate data.
This is also where one of the major pitfalls of scanf occurs:
In the event that scanf cannot apply a conversion to the input stream, the data is left in the input stream, and scanf fails early. Your next call to scanf will read that same data unless it is purged first (usually accomplished by consuming characters until a newline or end-of-file is reached).
This is why it is generally advised to separate your reading and your parsing to gain more control. This can be achieved with fgets and sscanf, to first read a line of input, and then parse it.
The other option is to simply terminate the program on any failure, which is what I've done in the example below (for simplicity's sake).
Additionally note that scanf("%s", buffer) is vulnerable to overflowing buffer. Always limit your input using field width specifiers, in the form scanf("%127s", buffer), which should be the length of your buffer minus one (leaving room for the NUL terminating byte).
Some things to consider:
Allocate memory for your string buffer.
Limit the amount of information that can be read into your buffer.
Handle errors in some way.
Use continue or break to help structure your flow.
Use separate functions to clarify a common task.
An example:
#include <stdio.h>
int seqsum(int from, int to) {
int sum = 0;
while (from <= to)
sum += from++;
return sum;
}
int main(void) {
char another[64];
int working = 1;
int n;
while (working) {
printf("Please enter a number greater than zero to sum up to: \n");
if (scanf("%d", &n) != 1) {
fprintf(stderr, "Invalid input or read error.\n");
return 1;
}
if (n < 0) {
printf("The number needs to be greater than zero. Retrying..\n");
continue;
}
printf("The sum of the numbers 0 to %d is: %d\n", n, seqsum(0, n));
printf("Would you like to sum another number? (y/n): ");
if (scanf("%63s", another) != 1) {
fprintf(stderr, "Invalid input or read error.\n");
return 1;
}
working = (another[0] == 'y' || another[0] == 'Y');
}
}
As an addendum, perhaps you were trying to read a single character?
Character constants are denoted by their enclosing single quotes (e.g., 'A'), and can be compared with the == operator.
The scanf format specifier for a single character is "%c". To skip leading white space (e.g., a line feed), you can add a space before the format specifier: " %c". The address of your char is given to scanf with the address-of operator (&).
char ch;
if (scanf(" %c", &ch) != 1)
/* failure */;
else if (ch == 'a' || ch == 'b')
/* do something */;
I'm very new to programming and C. I have textfile with some random text and an integer that i want to find and save. The textfile looks something like this (I only want to save 23 in this case, not 56):
# this is a comment
23
this is some random text
56
And this is the code I have:
int *num = malloc(sizeof(int));
*num = fgetc(f);
while(!feof(f)){
*num = fgetc(f);
if(isdigit(*num)){
break;
}
}
if(!isdigit(*num)){
printf("Error: no number found.\n");
free(num);
}
else{
printf("%c\n", *num);
}
I'm kinda stuck right now and my program only prints out the number 2 :/
Very thankful for help.
As #pbn said you're better off using sscanf.
But if you really, really want, you can do it your way, by reading one character at a time, but you'll need to "build" the integer yourself, converting the character to integer, keeping track of what you have, and multiplying by powers of 10 for every digit the number that you already have.
Something like this (not complete code, it's just to get you started):
int c;
int num = 0;
while (c = fgetc(f)) {
if(!isdigit(c)) {
break;
}
num = (num * 10) + (c - '0');
}
The c- '0' part is to convert the text representation of the integer to the integer itself. 0 is character 48, 1 is 49 and so on.
This is assuming that on the line with numbers, you ONLY have numbers, not a mix of numerical and non-numerical characters.
Also, do not use !feof(file).
One option could be using getline and sscanf functions. I assumed that text lines do not contain numbers:
#include <stdio.h>
int main() {
int value, matched = 0;
char *line = NULL;
size_t size;
while(getline(&line, &size, stdin) != -1) {
if ((matched = sscanf(line, "%d", &value)) != 0)
break;
}
if (matched)
printf("value: %d\n", value);
return 0;
}
This part:
while(getline(&line, &size, stdin) != -1) {
will try to read the entire stream line by line.
Next line uses sscanf return value, which is the number of input items successfully matched and assigned, to determine whether the integer value has been found. If so it stops reading the stream.
One simple way in your program is once you find digit don't just stop continue untill you find next " " , "\n" , "\0" . Till then add Number = Number*10 +(*num);, define Number as global or something.
I found an answer to the first part of my question (how to read multiple values with scanf) but it doesn't seem to work for me (I think it's because of putting the values into an array and maybe also because I'm checking if the values given are 6 ints for sure):
I am writing a program that stores co-ordinates of 4 triangles in an array. Each line has 6 values and stores co-ordinates of one triangle. I want to read 6 co-ordinates at one time and do this operation for 4 triangles separately.
int tab[4][6];
for (int i = 0; i < 4; i++){
while (scanf("%d %d %d %d %d %d", &tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5]) != 6){
printf("Error, try again: ");
while (getchar() != '\n'){}
}
}
So for example if first triangle's co-ordinates are (2,1), (5,6), (2,7), then I want to type in: "2 1 5 6 2 7" and as a result I want it to fill the first line of the array with the said numbers in the order I typed them in.
Obviously it doesn't work, the program stops working (not finishes the work, it stops) after the first line is given.
I get this error after debugging (after giving first line):
"Unhandled exception at 0x0FDCC28C (msvcr120d.dll) in xxx.exe: 0xC0000005: Access violation writing location 0xCCCCCCCC."
How to fix it?
You need to subtract the pointer i when detecting input error like this for example ->
#include <stdio.h>
int main(int argc, const char * argv[]) {
int tab[4][6];
for (int i = 0; i < 4; i++){
printf("Enter 6 values \n");
int retVal=scanf("%d %d %d %d %d %d", &tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5]);
if (retVal == 6) {
printf("You did enter -> %d %d %d %d %d %d\n",tab[i][0],tab[i][1],tab[i][2],tab[i][3],tab[i][4],tab[i][5]);
} else {
printf("Error entering values.. (Enter numbers). \n");
while (getchar() != '\n'){}
i--;
}
}
return 0;
}
Unclear why OP's code failed without posting input used and prior code.
How to fix it?
Use fgets() to read a line of user input. Avoid mixing scanf() with fgets() in prior code. Then parse the buffer. Use " %n" at the end to look for success and extra text.
int tab[4][6];
char buf[6*12 * 2]; // Use a buffer twice expected max needs
for (int i = 0; i < 4; i++) {
while (1) {
if (fgets(buf, size buf, stdin) == NULL) {
return "Failed to read enough data"; // Handle end-of-file in some fashion
}
int n = 0;
sscanf(buf, "%d%d%d%d%d%d %n",
&tab[i][0], &tab[i][1], &tab[i][2], &tab[i][3], &tab[i][4], &tab[i][5], &n);
if (n > 0 && buf[n] == 0) {
break; // Success!
}
printf("Error - bad input, try again: ");
}
}
I want to read int from a file
The first line is composed of 1 int and the second of 2
ie
1
2 3
if i do
fscanf(FILE, "%d \n %d %d", &a, &b, &c);
I obtain correctly the 3 numbers
but if i put all the numbers on the same line in the file
ie 1 2 3
I obtain the same result (and that's not what i want)
I want to know : How to force the user to go to a new line in his file ?
Edit :
As it seems unclear to some (i'm sorry for that) i want that the file
1
2 3
Produce the result :
a = 1
b = 2
c = 3
And the file
1 2 3
produce either an error or
a = 1
b = 0
c = 0
You need to read each line into a char buffer using fgets and parse each line with its own sscanf. You can use an extra %s on the end of the format string (and an extra pointer argument to a dummy variable of type char *) to detect whether the line contains extra stuff after the fields you're looking for.
fscanf(FILE, "%d", ...); first scans and discard white space before scanning for int characters. In scanning white-space, both ' ' and '\n' are treated the same, so using '%d' loses the end-of-line.
fscanf(FILE, "\n", ...); and fscanf(FILE, " ", ...); do the same thing: scan and discard any white space. Using "\n" does not scan only for '\n'.
Code could use fscanf(FILE, "%d%*1[\n]%d %d", &a, &b, &c) == 3, to find a '\n' after a, but additional '\n' could be lurking in other places.
The only way using scanf() family to detect a '\n' involves using '%c' or '%[]' or '%n'. It is easier to use fgets() and then parse with sscanf() or strtol().
int Read1and2int(FILE *stream, int *a, int *b, int *c) {
char buf[100];
int n;
if (fgets(buf, sizeof buf, stream) == NULL) return EOF;
int count = sscanf(buf,"%d %n", a, &n);
// Non-numeric or extra data
if (count != 1 || buf[n]) return 0;
if (fgets(buf, sizeof buf, stream) == NULL) return 1;
count = sscanf(buf,"%d%d %n", b, c, &n);
// Non-numeric or extra data
if (count != 2 || buf[n]) return 1;
return 3;
}
I'm kind of new to C, and the input reading is really confusing me. I'm trying to initialize an array of size 4, but sometimes the user will enter valid input of 3. In Java, I could check the length of the input and add conditionals, but I'm not sure how this works in C.
main(void){
char str[N];
int i;
for(i = 0; i < N; i++){
scanf("%c", &str[i]);
}
for(i = 0; i < N; i++){
printf("%c\n", str[i]);
}
}
Right now, if I input 4 or more, it works fine. If I input 3, it breaks. I'd like it to handle both 3 or 4 characters.
Actually, the root of the problem is: I'm trying to figure out a way in C to read in a 24-hour-clock time, and add it to a 24-hour-clock duration. Should I be approaching this an entirely different way?
Thanks,
The short answer is: you can't.
Using scanf() is particularly dangerous because of this if you want to read in a string (%s); if the user enters more input than your buffer can hold, you have a buffer overflow on your hands.
fgets() on the other hand, allows you to specify the max number of bytes you will read, preventing you from overflowing the buffer.
Here's a quick example on how you'd write a function for some input that verified that the input was within a specified length and was a complete line (ending with \n - this routine discards the \n from the input):
void getInput(char *question, char *inputBuffer, int bufferLength)
{
printf("%s (Max %d characters)\n", question, bufferLength - 1);
fgets(inputBuffer, bufferLength, stdin);
if (inputBuffer[strlen(inputBuffer) -1] != '\n')
{
int dropped = 0;
while (fgetc(stdin) != '\n')
dropped++;
if (dropped > 0) // if they input exactly (bufferLength - 1)
// characters, there's only the \n to chop off
{
printf("Woah there partner, your input was over the limit by %d characters, try again!\n", dropped );
getInput(question, inputBuffer, bufferLength);
}
}
else
{
inputBuffer[strlen(inputBuffer) -1] = '\0';
}
}
int main()
{
char firstAnswer[10];
getInput("Go ahead and enter some stuff:", firstAnswer, 10);
printf("Okay, I got: %s\n",firstAnswer);
}
scanf() allows the use of maximum width specifiers:
So scanf("%3s", buffer) reads at most 3 characters + 1 NUL terminator.