sscanf while reading 2 integers, extracts 0 for first digit - c

I am reading formatted data with
sscanf(buf,"%d %d",&a,&b);
data format = (unsigned short SPACE unsigned short);
but when i read it only successfully extract 2nd integer value from buffer for first it extracts 0. I am checking with (printf("nRecvd %d and %d",a,b)) I am reading from socket and I verified buffer values. All is ok untill sscanf.
char buf[MAXBUFL];
unsigned short a, b;
if (sscanf(buf,"%d %d",&a,&b) != 2)
snprintf (buf, sizeof(buf), "data error\r\n");
else
{
printf("\nRecvd %d and %d",a,b);}
Any suggestions?

You are scanning into short variables which means that you must tell sscanf that. You need:
if (sscanf(buf,"%hd %hd",&a,&b) != 2)
This is explained in the man page for scanf.

Related

Read() integer in c

I tried code below, but the results aren't correct. I think that something with size of buffer can be implemented in a wrong way.
int f(int* as) {
*as = read(STDIN_FILENO, as, sizeof(int));
} //i print 123
int s;
f(&s);
printf("%d",s); // prints 4
Two things that prevent the program to give the result you expect
1) using read to read from standard input (characters) and store that into a (binary) integer
2) storing the result of read into that same integer, overwriting the (wrong) value stored in 1)
Have a look at scanf or fgets (atoi...), to read into a character array (string), then convert the characters read into a binary number, for instance
char str[20];
fgets(str, 20, stdin);
int s = atoi(str);
read version
char str[20];
ssize_t nread = read(STDIN_FILENO, str, 20);
int s = atoi(str);
See what an integer is,

Casting string to int in C

I am trying to find out what this casting operation do:
char w[12] = {0};
int r;
r = (int)gets(w);
When input is for example 156, the value of r is -1073744588, so it is not a simple conversion to integer.
What your code does is cast the return value of gets, which is a pointer to the first character of the user input string, into an int. In other words, you are putting the address of the string into an integer, r. However, the address is so high that it "wraps around" in the integer r, yielding the large negative value.
You are most likely trying to convert the user's input into an int. This is the code to do so
char buf[80];
int res;
if (fgets(buf, sizeof buf, stdin)) /* load input into buf */
if (sscanf(buf, "%d\n", &res) < 1) /* try to read integer from buf */
fprintf(stderr, "Bad input\n"); /* input was bad; write error */
Notice, you should never use gets because it has serious security problems. Use fgets instead to read a line from the standard input.

Why fgets is not inputting first value?

I am writing a program to write my html files rapidly. And when I came to write the content of my page I got a problem.
#include<stdio.h>
int main()
{
int track;
int question_no;
printf("\nHow many questions?\t");
scanf("%d",&question_no);
char question[question_no][100];
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],sizeof(question[track-1]),stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
}
In this program I am writing some questions and their answers (in html file). When I test run this program I input the value of question_no to 3. But when I enter my first question it doesn't go in question[0] and consequently the first question doesn't output. The rest of the questions input without issue.
I searched some questions on stackoverflow and found that fgets() looks for last \0 character and that \0 stops it.
I also found that I should use buffer to input well through fgets() so I used: setvbuf and setbuf but that also didn't work (I may have coded that wrong). I also used fflush(stdin) after my first and last (as well) scanf statement to remove any \0 character from stdin but that also didn't work.
Is there any way to accept the first input by fgets()?
I am using stdin and stdout for now. I am not accessing, reading or writing any file.
Use fgets for the first prompt too. You should also malloc your array as you don't know how long it is going to be at compile time.
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 8
int main()
{
int track, i;
int question_no;
char buffer[BUFSIZE], **question;
printf("\nHow many questions?\t");
fgets(buffer, BUFSIZE, stdin);
question_no = strtol(buffer, NULL, 10);
question = malloc(question_no * sizeof (char*));
if (question == NULL) {
return EXIT_FAILURE;
}
for (i = 0; i < question_no; ++i) {
question[i] = malloc(100 * sizeof (char));
if (question[i] == NULL) {
return EXIT_FAILURE;
}
}
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],100,stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
for (i = 0; i < question_no; ++i) free(question[i]);
free(question);
return EXIT_SUCCESS;
}
2D arrays in C
A 2D array of type can be represented by an array of pointers to type, or equivalently type** (pointer to pointer to type). This requires two steps.
Using char **question as an exemplar:
The first step is to allocate an array of char*. malloc returns a pointer to the start of the memory it has allocated, or NULL if it has failed. So check whether question is NULL.
Second is to make each of these char* point to their own array of char. So the for loop allocates an array the size of 100 chars to each element of question. Again, each of these mallocs could return NULL so you should check for that.
Every malloc deserves a free so you should perform the process in reverse when you have finished using the memory you have allocated.
malloc reference
strtol
long int strtol(const char *str, char **endptr, int base);
strtol returns a long int (which in the code above is casted to an int). It splits str into three parts:
Any white-space preceding the numerical content of the string
The part it recognises as numerical, which it will try to convert
The rest of the string
If endptr is not NULL, it will point to the 3rd part, so you know where strtol finished. You could use it like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * endptr = NULL, *str = " 123some more stuff";
int number = strtol(str, &endptr, 10);
printf("number interpreted as %d\n"
"rest of string: %s\n", number, endptr);
return EXIT_SUCCESS;
}
output:
number interpreted as 123
rest of string: some more stuff
strtol reference
This is because the previous newline character left in the input stream by scanf(). Note that fgets() stops if it encounters a newline too.
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the
buffer
Don't mix fgets() and scanf(). A trivial solution is to use getchar() right after scanf() in order to consume the newline left in the input stream by scanf().
As per the documentation,
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a < newline > is read and
transferred to s, or an end-of-file condition is encountered
In case of scanf("%d",&question_no); a newline is left in the buffer and that is read by
fgets(question[track-1],sizeof(question[track-1]),stdin);
and it exits.
In order to flush the buffer you should do,
while((c = getchar()) != '\n' && c != EOF)
/* discard */ ;
to clear the extra characters in the buffer

What does the n stand for in `sscanf(s, "%d %n", &i, &n)`?

The man page states that the signature of sscanf is
sscanf(const char *restrict s, const char *restrict format, ...);
I have seen an answer on SO where a function in which sscanf is used like this to check if an input was an integer.
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
Looking at !s[n] it seems to suggest that we check if sscanf scanned the character sequence until the termination character \0. So I assume n stands for the index where sscanf will be in the string s when the function ends.
But what about the variable i? What does it mean?
Edit:
To be more explicit: I see the signature of sscanf wants a pointer of type char * as first parameter. A format specifier as seconf parameter so it knows how to parse the character sequence and as much variables as conversion specifiers as next parameters. I understand now that i is for holding the parsed integer.
Since there is only one format specifier, I tried to deduce the function of n.
Is my assumption above for n correct?
Looks like the op has his answer already, but since I bothered to look this up for myself and run the code...
From "C The Pocket Reference" (2nd Ed by Herbert Shildt) scanf() section:
%n Receives an integer of value equal to the number of characters read so far
and for the return value:
The scanf() function returns a number equal to the number of the number of fields
that were successfully assigned values
The sscanf() function works the same, it just takes it's input from the supplied buffer argument ( s in this case ). The "== 1" test makes sure that only one integer was parsed and the !s[n] makes sure the input buffer is well terminated after the parsed integer and/or that there's really only one integer in the string.
Running this code, an s value like "32" gives a "true" value ( we don't have bool defined as a type on our system ) but s as "3 2" gives a "false" value because s[n] in that case is "2" and n has the value 2 ( "3 " is parsed to create the int in that case ). If s is " 3 " this function will still return true as all that white space is ingored and n has the value of 3.
Another example input, "3m", gives a "false" value as you'd expect.
Verbatim from sscanf()'s man page:
Conversions
[...]
n
Nothing is expected; instead, the number of characters
consumed thus far from the input is stored through the next pointer,
which must be a pointer to int. This is not a
conversion, although it can be suppressed with the * assignment-suppression character. The C
standard says: "Execution of
a %n directive does not increment the assignment count returned at the completion of
execution" but the Corrigendum seems to contradict this. Probably it is wise not
to make any assumptions on the effect of %n conversions on the return value.
I would like to point out that the original code is buggy:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
I will explain why. And I will interpret the sscanf format string.
First, buggy:
Given input "1", which is the integer one, sscanf will store 1 into i. Then, since there is no white space after, sscanf will not touch n. And n is uninitialized. Because sscanf set i to 1, the value returned by sscanf will be 1, meaning 1 field scanned. Since sscanf returns 1, the part of the expression
sscanf(s, "%d %n", &i, &n) == 1
will be true. Therefore the other part of the && expression will execute. And s[n] will access some random place in memory because n is uninitialized.
Interpreting the format:
"%d %n"
Attempts to scan a number which may be a decimal number or an integer or a scientific notation number. The number is an integer, it must be followed by at least one white space. White space would be a space, \n, \t, and certain other non-printable characters. Only if it is followed by white space will it set n to the number of characters scanned to that point, including the white space.
This code might be what is intended:
static bool is_int(char const* s)
{
int i;
int fld;
return (fld = sscanf(s, "%i", &i)) == 1;
}
int main(int argc, char * argv[])
{
bool ans = false;
ans = is_int("1");
ans = is_int("m");
return 0;
}
This code is based on, if s is an integer, then sscanf will scan it and fld will be exactly one. If s is not an integer, then fld will be zero or -1. Zero if something else is there, like a word; and -1 if nothing is there but an empty string.
variable i there means until it has read an integer vaalue.
what are you trying to ask though? Its not too clear! the code will (try to ) read an integer from the string into 'i'

C programming: How to use sscanf with a ':' delimiter?

I have been trying to extract hours, seconds and minutes from an input text using sscanf. After sscanf function is performed, only s variable which holds the seconds has the right value. h and m which have hours and minutes in them hold only zeros. Please suggest changes to my code below.
char text[20];
if (fgets(text, sizeof text, stdin)!= NULL){
char* newline = strchr(text, '\n');
if (newline != NULL){
*newline = '\0';
}
}
uint8_t s = 0;
uint8_t m = 0;
uint8_t h = 0;
sscanf(text, "%02i:%02i:%02i",&h,&m,&s);
Note in the debugger, text has the right values.
This program:
#include <stdio.h>
int main(void)
{
const char hhmmss[] = "10:32:54";
int hh, mm, ss;
if (sscanf(hhmmss, "%i:%i:%i", &hh, &mm, &ss) != 3)
printf("Failed to scan 3 values from '%s'\n", hhmmss);
else
printf("From <<%s>> hh = %d, mm = %d, ss = %d\n", hhmmss, hh, mm, ss);
return 0;
}
gives this output:
From <<10:32:54>> hh = 10, mm = 32, ss = 54
The %02i conversions should also work, but the digits are somewhat superfluous.
The amended question shows that the variables are of type uint8_t, in which case you must use the correct conversion specifiers from <inttypes.h>:
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
const char hhmmss[] = "10:32:54";
uint8_t s;
uint8_t m;
uint8_t h;
if (sscanf(hhmmss, "%02" SCNi8 ":%02" SCNi8 ":%02" SCNi8, &h, &m, &s) != 3)
printf("Failed to scan 3 values from '%s'\n", hhmmss);
else
printf("From <<%s>> h = %d, m = %d, s = %d\n", hhmmss, h, m, s);
return 0;
}
This produces the same output as before. With any of the scanf() family of functions, it is crucial that your format conversion specifiers match the types of the pointers you are passing into the function. You can get away with quite a lot of mismatches in printf() - certainly by comparison - because of default integer (in particular) promotions, but scanf() is a lot less forgiving.
#Jonathan Leffler's answer is entirely correct, but...
You should never use scanf or fscanf or sscanf for parsing input from file handle or a string, except perhaps in known-to-be-thrown-away-tomorrow code. They are too error-prone and too hard to control. For an exhaustive summary of the various problems with scanf, I recommend this series of articles. A few highlights:
If you need to read single characters, use getchar.
If you want to read a string, scanf has all the buffer overflow problems of gets.
If you want to read numbers, scanf's parsing is error-prone and hard to use. Use strtoul and strtod instead.
If you have more complicated input, everything is just worse.
What to do?
Read your own input using something better than gets, that is, without buffer overflow problems. Do not attempt to combine getting the bytes in with interpreting them.
Use a combination of strcspn, strspn, and stroul and strtod combined with some custom code to scan the input.
There are times when this too is a drag, but by that time your typically building some sort of input language that needs more generic techniques anyway.

Resources