Simple test program using sscanf does not work - c

I was wondering why the following does not work:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int nbytes = 100;
char* string;
string = malloc((sizeof(char) * nbytes) + 1);
int x, y, z;
int args_assigned = 0;
while (args_assigned != 3)
{
printf("Please enter three integers separated by whitespace\n"
scanf("%s", string);
args_assigned = sscanf(string, "%d %d %d", &x, &y, &z);
}
free(string);
printf("Thanks for %d %d %d\n", x, y, z);
return 0;
}
In the original version of this code, the programmer had used getline instead of scanf, but apparently this is no longer a valid function in C99? Please correct me if I am wrong.
Anyway, I suspect the problem is to do with my use of scanf. Is there another function I should be using to provide the string for sscanf to parse? Of course, there could be something far more fundamental that I am missing here...

You ask the user to enter three integers separated by spaces.
You try to read that information with "%s" which stops reading at the first space. This is why you run into problems. You could have found this out by printing what you get from your scanf() call.
Don't forget to check the return value from sscanf().
There is a POSIX function getline() which reads a whole line and tells you how long it is. Alternatively, there is the standard C function fgets() which can be used to read whole lines.
At a pinch, you could use scanf(" %[^\n]", string), but I really wouldn't recommend it; use getline() or fgets().

Be sure to finish this line:
printf("Please enter three integers separated by whitespace\n"

To read a line of input, use fgets().
fgets(string, nbytes + 1, stdin);

Related

'scanf_s' function doesn't work well in my C project

My code:
#include <stdio.h>
int main() {
char words[30];
printf("Please typing text under 30 text!:");
scanf_s("%s", words);
printf("text: %s \n", words);
return 0;
}
The error I get:
Missing integer argument to 'scanf_s' that corresponds to coversion
specifier '2', 'scanf_s' not enough arguments passed for format string
Consider using fgets instead if you're simply reading everything into a string buffer. It's simpler and more portable:
char buffer[31]; // 1 extra for the zero terminator
printf("Please enter text with less than %zu characters\n", sizeof(buffer) - 1);
if (!fgets(buffer, (int)sizeof(buffer), stdin)) {
puts("Failed to read input");
} else {
// use input
}
As you can see in the scanf_s documentation:
specifiers each expect two arguments (the usual pointer and a value of
type rsize_t indicating the size of the receiving array, which may be
1 when reading with a %c into a single char)
I.e. for each argument you want scanf_s to parse, you need to pass its size.
Also scanf family return the number of arguments parsed, and you should check it to find out if it actually succeeded.
In your case change the scanf_s line to:
int n = scanf_s("%s", words, sizeof(words));
if (n != 1)
{
// handle error
}
Note that sizeof(words) works here because it is an array allocated on the stack. If you allocate it as a pointer with malloc family you'll need to pass the right size (because then sizeof will return the size of the pointer itself).
Try this code:
#include <stdio.h>
int main() {
char words[30];
printf("Please typing text under 30 text!:");
scanf_s("%s", words,30);
printf("text: %s \n", words);
return 0;
}
Also, you could put sizeof(words) instead of 30 as someone suggested (note that this is only possible if you are working with static memory).
If you are using scanf_s, I think you want to ensure to read n symbols.
Someone already suggested you to use fgets. Another possible solution is to use memcpy (you will read the exact bytes):
#include <stdio.h>
int main() {
char words[30];
char words2[30];
printf("Please typing text under 30 text!:");
scanf("%s", words);
memcpy(words2,words,sizeof(char)*30);
words2[sizeof(char)*30]='\0';
printf("text: %s \n", words2);
return 0;
}

Using scanf to read an integer with nothing else but a newline character

Is there a way to use scanf (without using any other I/O function) to check whether the user input exists only of a single integer with nothing following it?
For example:
int g;
while(scanf("%d", &g)!=1){
printf("\nincorrect input, try again");
}
This works fine for input like "/" or "-" but when you input "54.32" then it will read until the ".", the read count of scanf will be 1 and 54 will be stored in g. Is there a way to check if the input consists solely of a single integer followed by nothing but a newline character?
I would like to know if there exists a solution without using fgets or any other IO function?
to check solely of a single integer followed by nothing but a newline character
Use "%n" to record number of characters scanned, if it gets that far.
int n = 0;
scanf("%d*1[\n]%n", &g, &n);
if (n > 0) puts("input consists solely of a single integer followed by a newline");
If the result is not as hoped, additional code needed to cope with the errant input.
I recommend using fgets() to solve the larger problem.
Edit because I misunderstood the question: what about this?
#include <stdio.h>
int main() {
int n;
char c;
scanf("%d", &n);
scanf(" %c", &c) ? printf("incorrect input, try again\n") : printf("%d\n", n);
return 0;
}
You can use the assignment-suppressing format operator to extract everything (anything) after the integer, and the number-of-characters-read format specifier to see whether that matched anything, without having to store it anywhere.
See your documentation.
Eg,
int g, gchars, xchars;
scanf("%d%n%*s%n", &g, &gchars, &xchars);
if (xchars > gchars)
printf("%d extra characters discarded after integer %d\n", xchars-gchars, g);

Get a space in a multidimensional array

I am trying to get a name in an array " char name[100][100]". I tried doing many thing like these, but none work.Can you help me?
The code: Its a simple student's grade system i think, but only prints "" when trying to save a name.
#include <stdio.h>
#include <string.h>
void insert();
char name[100][100];float f[20];int z;
int main()
{
int x=0;
do{
printf("<1> Insert student\n");
printf("=> ");
scanf("%d",&x);
printf("\n*************************************************************\n");
switch(x){
case 1:
insert();
break;
default: printf("NO");
break;
}
}while(insert >=0 );
return 0;
}
void insert()
{
int x;
int y=0;
float n1,n2,p;
printf("How many students?: ");
scanf("%d",&y);
for(x=0;x<y;x++){
printf("Insert name: ");
fgets(name[x], 100, stdin);
int len = strlen(name[x]);
if (name[x][len-1] == '\n') {
name[x][len-1] = '\0';
}
printf("name[%d] = \"%s\"\n", x, name[x]);
printf("Insert first grade: ");
scanf("%f",&n1);
printf("Insert second grade: ");
scanf("%f",&n2);
printf("Insert final grade: ");
scanf("%f",&p);
f[x] = (n1 * 0.3)+(n2 * 0.3)+(p * 0.4);
z++;
}
for(x=0;x<z;x++){
if(f[x] < 6){
printf("the final grade of %s is: %.2f \n",name[x], f[x]);}
else{printf("the final grade de %s es: %.2f \n",name[x], f[x]);}
}
}
You should bear in mind that fgets() returns the new-line as well, if there's enough space in the buffer. You might want to take it out:
#include <stdio.h>
#include <string.h>
int main()
{
char name[100][100];
int y = 5;
int x = 0;
for (x = 0; x < y; x++) {
printf("Insert name: ");
fgets(name[x], 100, stdin);
int len = strlen(name[x]);
if (name[x][len-1] == '\n') {
name[x][len-1] = '\0';
}
printf("name[%d] = \"%s\"\n", x, name[x]);
}
}
Why are you using that %[^\t\n] string format? You should just go with a %s string format if you want to read a string (or, better, a %100s to limit the number of characters read).
scanf("%100s",name[x]) works just fine, but will mess things up when you try to use spaces (i.e. the scanf() will read one word at a time).
To avoid that, you can use the second option, that is fgets(). But, in this case, you need to pay attention to the final \n character that is appended to the string. To prevent the newline character from ending your string, you can simply do the following:
name[x][strlen(name[x])-1] = 0;
The previous code simply replaces the \n character with a null byte, thus ending the string and "ignoring" the newline.
EDIT:
The thing you need to understand is that the standard input (i.e. the keyboard input usually) is handled as if it were a file (in fact, you can use functions like fgets(), as if you were reading a normal file). So, as it happens with normal files, each line ends with a special character, \n. Every time you enter an input, and you press "Enter", a newline character is appended to your input.
There's a couple of things you need to know to understand what it is that you're doing wrong:
Some functions (like fgets()) read a line until a newline character is found. The newline character is also read, and returned in the string that was just read.
Other functions (like scanf()) also read lines until some special characters (such as or \n) are found. But, in this case, the final character is not read.
And, last: every time you open a file, the process keeps count of the number of characters you have read from the beginning of the file (or, to put it in an easier (and more correct) way, it "stores" a "pointer" to the next character that should be read).
With this being said, let's have a look at what happens with your program: first, the number of students is read (using scanf()), and, then, a name is read (using fgets()).
So, your input "file", looks like:
4\n
^
John Smith\n
...
The ^ is a pointer to the next character that should be read (and isn't, obviously, part of the input).
After the scanf() (which, as I mentioned, won't read the \n), the situation will be the following:
4\n
^
John Smith\n
...
Now, when you read the next line using fgets(), the "pointer" is already pointing to a newline character, and will therefore assume (correctly!) that the line has ended. The string you are reading is therefore "\n", instead of "John Smith\n".
The easiest way to fix this problem is to read, after every scanf(), single characters from standard input until a newline character is encountered.
scanf ( ... );
while (getc(stdin)!='\n');
Usually reading a single character should be enough, but in some cases (e.g. 4 \n) a single getc() isn't effective.
Basically, whenever a character is read from the file, the "pointer" is updated.
I really hope this cleared things up a bit. It isn't that easy to understand these details at first but, as you get more experience, things will definitely become clearer!

Reading string from input with space character? [duplicate]

This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 4 years ago.
I'm using Ubuntu and I'm also using Geany and CodeBlock as my IDE.
What I'm trying to do is reading a string (like "Barack Obama") and put it in a variable:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
scanf("%s", name);
printf("Your Name is: %s", name);
return 0;
}
Output:
Enter your name: Barack Obama
Your Name is: Barack
How can I make the program read the whole name?
Use:
fgets (name, 100, stdin);
100 is the max length of the buffer. You should adjust it as per your need.
Use:
scanf ("%[^\n]%*c", name);
The [] is the scanset character. [^\n] tells that while the input is not a newline ('\n') take input. Then with the %*c it reads the newline character from the input buffer (which is not read), and the * indicates that this read in input is discarded (assignment suppression), as you do not need it, and this newline in the buffer does not create any problem for next inputs that you might take.
Read here about the scanset and the assignment suppression operators.
Note you can also use gets but ....
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Try this:
scanf("%[^\n]s",name);
\n just sets the delimiter for the scanned string.
Here is an example of how you can get input containing spaces by using the fgets function.
#include <stdio.h>
int main()
{
char name[100];
printf("Enter your name: ");
fgets(name, 100, stdin);
printf("Your Name is: %s", name);
return 0;
}
scanf(" %[^\t\n]s",&str);
str is the variable in which you are getting the string from.
The correct answer is this:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
// pay attention to the space in front of the %
//that do all the trick
scanf(" %[^\n]s", name);
printf("Your Name is: %s", name);
return 0;
}
That space in front of % is very important, because if you have in your program another few scanf let's say you have 1 scanf of an integer value and another scanf with a double value... when you reach the scanf for your char (string name) that command will be skipped and you can't enter value for it... but if you put that space in front of % will be ok everything and not skip nothing.
NOTE: When using fgets(), the last character in the array will be '\n' at times when you use fgets() for small inputs in CLI (command line interpreter) , as you end the string with 'Enter'. So when you print the string the compiler will always go to the next line when printing the string. If you want the input string to have null terminated string like behavior, use this simple hack.
#include<stdio.h>
int main()
{
int i,size;
char a[100];
fgets(a,100,stdin);;
size = strlen(a);
a[size-1]='\0';
return 0;
}
Update: Updated with help from other users.
#include <stdio.h>
// read a line into str, return length
int read_line(char str[]) {
int c, i=0;
c = getchar();
while (c != '\n' && c != EOF) {
str[i] = c;
c = getchar();
i++;
}
str[i] = '\0';
return i;
}
Using this code you can take input till pressing enter of your keyboard.
char ch[100];
int i;
for (i = 0; ch[i] != '\n'; i++)
{
scanf("%c ", &ch[i]);
}
While the above mentioned methods do work, but each one has it's own kind of problems.
You can use getline() or getdelim(), if you are using posix supported platform.
If you are using windows and minigw as your compiler, then it should be available.
getline() is defined as :
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
In order to take input, first you need to create a pointer to char type.
#include <stdio.h>
#include<stdlib.h>
// s is a pointer to char type.
char *s;
// size is of size_t type, this number varies based on your guess of
// how long the input is, even if the number is small, it isn't going
// to be a problem
size_t size = 10;
int main(){
// allocate s with the necessary memory needed, +1 is added
// as its input also contains, /n character at the end.
s = (char *)malloc(size+1);
getline(&s,&size,stdin);
printf("%s",s);
return 0;
}
Sample Input:Hello world to the world!
Output:Hello world to the world!\n
One thing to notice here is, even though allocated memory for s is 11 bytes,
where as input size is 26 bytes, getline reallocates s using realloc().
So it doesn't matter how long your input is.
size is updated with no.of bytes read, as per above sample input size will be 27.
getline() also considers \n as input.So your 's' will hold '\n' at the end.
There is also more generic version of getline(), which is getdelim(), which takes one more extra argument, that is delimiter.
getdelim() is defined as:
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
Linux man page
If you need to read more than one line, need to clear buffer. Example:
int n;
scanf("%d", &n);
char str[1001];
char temp;
scanf("%c",&temp); // temp statement to clear buffer
scanf("%[^\n]",str);
"%s" will read the input until whitespace is reached.
gets might be a good place to start if you want to read a line (i.e. all characters including whitespace until a newline character is reached).
"Barack Obama" has a space between 'Barack' and 'Obama'. To accommodate that, use this code;
#include <stdio.h>
int main()
{
printf("Enter your name\n");
char a[80];
gets(a);
printf("Your name is %s\n", a);
return 0;
}
scanf("%s",name);
use & with scanf input

Hard-coded string in the format of scanf

I'm trying to match lines with a format like "point %d %d". So I only need to two those two integers, then the "point" is hard-coded in the format string. As I understand reading Linux man pages of scanf, this should work correctly.
The next code, the way I want to use, the first call to scanf works, but the next calls scanf return with an error code and never take more numbers from the stdin (scanf doesn't block waiting for more input from stdin):
for (;;)
{
scanf("point %d %d", &x, &y);
printf("=> point %d %d\n", x, y);
}
In this way, everything work as expected:
int x, y;
char s[10];
for (;;)
{
scanf("%s %d %d", s, &x, &y);
printf("=> point %d %d\n", x, y);
}
Any suggestion about what could I am misunderstanding?
Thanks.
There's still unconsumed data such as end-of-line characters in stdin that make the upcoming scans to stop with a non-match. In the second version this end-of-line data gets consumed by the %s.
I suggest you fgets to a buffer first and then sscanf it. And do check your return values.
My guess is that you are not giving it proper input. For example this input will not work:
4 5
This should work:
point 4 5
You didn't mention the error code, but it is probably saying that you didn't follow the format correctly (i.e. put in point before the numbers).
As a good programming practice you should flush the standard input before taking inputs from user.

Resources