Unix C files , scanf is ignoring whitespace - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
void main (int argc, char* arcv[]) {
int fd, quest_num, i, j;
char* str;
char temp[2], buffer[20];
fd = open(arcv[1], O_WRONLY | O_CREAT, 0664);
printf("Insert number of questions\n");
scanf("%s", str);
write(fd, str, sizeof(str));
write(fd, "\n", 1);
quest_num = atoi(str);
for (i = 1; i <= quest_num; i++) {
printf("Insert question %d\n", i);
scanf("%[^\n]s", buffer);
printf("\n %s \n", buffer);
write(fd, "Question ", );
sprintf(temp, "%d", i);
write(fd, temp, sizeof(temp));
write(fd, "\n", 1);
write(fd, str, sizeof(temp));
write(fd, "\n", 1);
}
close(fd);
}
I want to make inputs like this:
Insert Number of Question:
2
Insert Question 1:
X+1=0 x=?
Insert Question 2:
X+y=0
and inside the file content i want it to look like this:
Question 1: X+1=0 x=?
1. 5
2. 2
3. 0
4. 1 Question 2: X+y=0
1. X=y
2. X= y
3. X=1
4. Y=1
but I get this in the terminal:
Insert number of questions
2
Insert question 1
x+y x=?
Insert question 2 (input is ignored here)
and inside the file:
2
Question 1
x+
Question 2
x=
Question 3
2
So in summary, scanf is ignoring the spaces input and there's an extra loop in the file content.

The basic problem is that when you scanf something that doesn't match a newline (either %s or %[^\n]) it won't read the newline at the end of the line and will leave it for the next stdio input rountine to read. You need to actually read and discard those newlines somehow.
The easiest way to do this is to use fgets to read input lines instead of scanf.
printf("Insert number of questions\n");
fgets(buffer, sizeof(buffer), stdin);
write(fd, buffer, strlen(buffer));
quest_num = atoi(buffer);
for (i = 1; i <= quest_num; i++) {
printf("Insert question %d\n", i);
fgets(buffer, sizeof(buffer), stdin);
Note that fgets will read the line including the newline, and the newline will be in the buffer, so if you don't want it, you'll need to strip it out explicitly.
If you really must use scanf, you can use a space in the format to explicitly skip over leading whitespace (including any lingering newline(s)), which might actually be desirable.
printf("Insert number of questions\n");
scanf("%19s", buffer);
write(fd, str, strlen(buffer));
write(fd, "\n", 1);
quest_num = atoi(buffer);
for (i = 1; i <= quest_num; i++) {
printf("Insert question %d\n", i);
scanf("% 19[^\n]", buffer);
printf("\n %s \n", buffer);
Note that when using scanf with %s or %[ and a fixed-size buffer, you should use an explicit size in the format to avoid buffer overruns

Related

Text doesn't show when using printf in visual studio

I'm new to programming, so here is propably an easy problem. Im using visual studio. When i type anything and then press enter, the string doesnt show. I was trying to do hex -> decimal, but for now i deleted rest of the code.
int main()
{
char liczba[5];
printf("Write hex numb: ");
scanf_s("%s", liczba , 1u);
printf(" %s ", liczba);
return 0;
}
I looked up the documentation. It notes, that in contrast to scanf for scanf_s buffer sizes need to be specified for format specifiers c, C, s and S as a second parameter following the usual one. An example:
char str[1024];
printf("Input text: ");
scanf_s("%s", str, 1024);
The documentation also states that in case of potential buffer overflow nothing is written to the buffer.
Your code works perfectly fine if you won't use "1u".
#include <stdio.h>
#include <stdlib.h>
int main()
{
char liczba[5];
int BUFFSIZE = 1024;
printf("Write hex numb: ");
scanf_s("%s", liczba , BUFFSIZE);
printf(" %s ", liczba);
return 0;
}
I have created an integer for the buffer size, but you can also go with:
scanf_s("%s", liczba , 1024);
And size of the buffer can also be lower than 1024. For example it can be 5, but if you will input a string "QWERTYUIOP" your printf won't show anything.

c programming read input error checking

Is there a way to make this error checking any better? Or is there something I am forgetting? I am expecting an integer then string. I added the suggestions to the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
int main(void) {
// your code goes here
char line[150] = {0};
int sscanf_counter = 0;
int num = 0;
char string[150] = {0};
char dummy;
while(fgets(line, sizeof line, stdin))
{
printf("line is %s\n", line);
sscanf_counter = sscanf(line, "%d %s %c", &num, string, &dummy);
printf ("sscanf_counter: %d\n", sscanf_counter);
if (sscanf_counter == 2 && isalpha(string[0]))
{
printf ("Good value: %d\n", num);
printf ("string: <%s>\n", string);
}
else
{
printf ("BAD VALUE: %d \n", num);
printf ("string: <%s>\n", string);
}
memset(line, 0, sizeof line);
}
printf("Does this print? \n");
return 0;
}
I didn't want 222 to be converted to a string so I added a simple isalpha() check to my code. I want an actual number for my first value and actual alphabet characters not numbers converted to a string for the second value.
Output with small tweak:
aaa aaa
line is aaa aaa
sscanf_counter: 0
BAD VALUE: 0
string: <>
111 222
line is 111 222
sscanf_counter: 2
BAD VALUE: 111
string: <222>
111 aaa
line is 111 aaa
sscanf_counter: 2
Good value: 111
string: <aaa>
Is there a way to make this error checking any better?
"%d" is not specified on overflow. Stronger error checking can be provided with strtol().
"%d %s" does not detect extraneous extra input.
To deal with extra input and still use sscanf(), see below. If sscanf_counter == 3, extra non-white-space input detected.
char dummy;
sscanf_counter = sscanf(line, "%d %s %c", &num, string, &dummy);
The test if (sscanf_counter == ...) should happen before using the variables.
printf ("sscanf_counter: %d\n", sscanf_counter);
if (sscanf_counter >= 1) printf ("num: %d\n", num);
if (sscanf_counter >= 2) printf ("string: %s\n", string);
Tip: when printing a string, consider printable sententials to help detect leading/trailing white-space issues. (Even though these are not expected with "%s".)
// printf ("string: %s\n", string);
printf ("string: <%s>\n", string);
OT: Rather than code magic numbers, use code that adapts
// memset(line, 0, 150);
memset(line, 0, sizeof line);
// while(fgets(line, 150, stdin) != NULL)
while (fgets(line, sizeof line, stdin))

scanf("%[^\n]%*c", …) in a loop

I have to program a new file in which I have to have multiple student info (like: Student_name, student_Surname, school_subject and number of student) in one line and I have to type in new students until I input END.
I have to use printf and scanf. Name, surname and subject can be multiple words When I try to use scanf("[^\n]*c", name), I can only enter info for one student and loop just ignores rest and for other students I can just type in student number which is integer.
What is wrong with my code?
int main() {
FILE *outputfile = NULL;
struct imenik {
char prezime[17 + 1];
char ime[13 + 1];
char predmet[20 + 1];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "w");
printf("Ucitaj ime ucenika: ");
scanf("%[^\n]%*c", ucenik.ime);
printf("Ucitaj prezime ucenika: ");
scanf("%[^\n]%*c", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf("%[^\n]%*c", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d", &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n", ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
fclose(outputfile);
}
The problem is here:
scanf("%d", &ucenik.bodovi);
This reads the number, but it doesn't read the newline after it. So when the loop repeats, It reads that newline as an empty line of input for the next student name.
You can change it to:
scanf("%d ", &ucenik.bodovi);
The space tells it to skip over any whitespace after the number.
But actually, it's better to put the space at the beginning of each scanf, rather than ignoring the newline at the end. See http://stackoverflow.com/questions/19499060/what-is-difference-between-scanfd-and-scanfd for the explanation. So change it to:
printf("Ucitaj ime ucenika: ");
scanf(" %[^\n]", ucenik.ime);
printf("Ucitaj prezime ucenika: ");
scanf(" %[^\n]", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf(" %[^\n]", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d", &ucenik.bodovi);
I suggest you an implementation like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define S_SIZE 32
#define T_SIZE 128
int main(void) {
FILE *outputfile = NULL;
struct imenik {
char prezime[S_SIZE];
char ime[S_SIZE];
char predmet[S_SIZE];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "a");
if (outputfile == NULL) {
perror("Fopen");
exit(EXIT_FAILURE);
}
char tmp[T_SIZE];
while (1) {
printf("Enter info separated with spaces: ");
fgets(tmp, T_SIZE, stdin);
if (strcmp(tmp, "END\n") == 0) {
break;
}
sscanf(tmp, "%s %s %s %d", ucenik.ime, ucenik.prezime, ucenik.predmet, &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n", ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
}
fclose(outputfile);
return 0;
}
Your line:
scanf("%d", &ucenik.bodovi);
leaves a newline in the input stream. This gets picked up by the next call to scanf(), which immediately exits, also leaving the newline behind, and so on. Do not try adding a trailing whitespace character to the format string, as some suggest: "%d ". This will consume the newline at the end of your input, and wait for more input, until a non-whitespace character or EOF is encountered.
The easiest solution is to do what you have already been doing to discard newlines:
scanf("%d%*c", &ucenik.bodovi);
Note that you should specify a maximum width in format strings when using scanf() to read into a string to avoid buffer overflow:
scanf("%13[^\n]%*c", ucenik.ime);
Also, you should be checking outputfile to be sure that the file has opened successfully.
One way to implement the loop would be to place the first call to scanf() outside of the loop, then use strcmp() in the while statement to check for "END". At the end of the loop, duplicate the first call to scanf():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *inputfile = NULL;
FILE *outputfile = NULL;
struct imenik {
char prezime[17 + 1];
char ime[13 + 1];
char predmet[20 + 1];
int bodovi;
} ucenik;
outputfile = fopen("imenik.txt", "w");
/* Did file open successfully? */
if (outputfile == NULL) {
perror("Unable to open file:");
exit(EXIT_FAILURE);
}
/* Specify maximum widths in calls to scanf() */
printf("Ucitaj ime ucenika: ");
scanf("%13[^\n]%*c", ucenik.ime);
while (strcmp(ucenik.ime, "END") != 0) {
printf("Ucitaj prezime ucenika: ");
scanf("%17[^\n]%*c", ucenik.prezime);
printf("Ucitaj predmet: ");
scanf("%20[^\n]%*c", ucenik.predmet);
printf("\nUcitaj broj bodova (0-50): ");
scanf("%d%*c", &ucenik.bodovi);
fprintf(outputfile, "%s | %s | %s | %d\n",
ucenik.ime, ucenik.prezime, ucenik.predmet, ucenik.bodovi);
printf("Ucitaj ime ucenika: ");
scanf("%13[^\n]%*c", ucenik.ime);
}
fclose(outputfile);
return 0;
}

Reading in a variable length string user input in C

I am trying to read in a variable length user input and perform some operation (like searching for a sub string within a string).
The issue is that I am not aware how large my strings (it is quite possible that the text can be 3000-4000 characters) can be.
I am attaching the sample code which I have tried and the output:
char t[],p[];
int main(int argc, char** argv) {
fflush(stdin);
printf(" enter a string\n");
scanf("%s",t);
printf(" enter a pattern\n");
scanf("%s",p);
int m=strlen(t);
int n =strlen(p);
printf(" text is %s %d pattrn is %s %d \n",t,m,p,n);
return (EXIT_SUCCESS);
}
and the output is :
enter a string
bhavya
enter a pattern
av
text is bav 3 pattrn is av 2
Please don't ever use unsafe things like scanf("%s") or my personal non-favourite, gets() - there's no way to prevent buffer overflows for things like that.
You can use a safer input method such as:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
You can then set the maximum size and it will detect if too much data has been entered on the line, flushing the rest of the line as well so it doesn't affect your next input operation.
You can test it with something like:
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
In practice you shouldn't bother too much to be precise. Give yourself some slack to have some memory on the stack and operate on this. Once you want to pass the data further, you can use strdup(buffer) and have it on the heap. Know your limits. :-)
int main(int argc, char** argv) {
char text[4096];
char pattern[4096];
fflush(stdin);
printf(" enter a string\n");
fgets(text, sizeof(text), stdin);
printf(" enter a pattern\n");
fgets(pattern, sizeof(pattern), stdin);
int m=strlen(text);
int n =strlen(pattern);
printf(" text is %s %d pattrn is %s %d \n",text,m,pattern,n);
return (EXIT_SUCCESS);
}
Don't use scanf or gets for that matter because as you say, there is not real way of knowing just how long the input is going to be. Rather use fgets using stdin as the last parameter. fgets allows you to specify the maximum number of characters that should be read. You can always go back and read more if you need to.
scanf(%s) and gets read until they find a terminating character and may well exceed the length of your buffer causing some hard to fix problems.
The main problem in your case is having char arrays of unknown size. Just specify the array size on declaration.
int main(int argc, char** argv) {
int s1[4096], s2[4096];
fflush(stdin);
printf(" enter a string\n");
scanf("%s", s1);
printf(" enter a pattern\n");
scanf("%s", s2);
int m = strlen(s1);
int n = strlen(s2);
printf(" text is %s of length %d, pattern is %s of length %d \n", s1, m, s2, n);
return (EXIT_SUCCESS);
}

Unusual Behaviour while passing an array to a function

#include <stdio.h>
#define SIZE 5
void func(int*);
int main(void)
{
int i, arr[SIZE];
for(i=0; i<SIZE; i++)
{
printf("Enter the element arr[%d]: ", i);
scanf("%d", &arr[i]);
}//End of for loop
func(arr);
printf("The modified array is : ");
for(i=0; i<SIZE; i++)
printf("%d ", arr[i]);
return 0;
}
void func(int a[])
{
int i;
for(i=0; i<SIZE; i++)
a[i] = a[i]*a[i];
}
Output :::
While I'm entering integer elements the output is OK.But as I entered a float value like 1.5, it didn't ask for other elements and the O/P is as shown in the figure.I think it should implicitly typecast 1.5 to 1 but it didn't happen..can u plz tell why this happened ? All the info about the compiler is shown in the figure.
When you scanf("%d") a value like 1.5 the scanning will stop at the decimal point and return 1.
The next time you call scanf, the pointer will still point to the decimal point and your scan will return immediately because there are no digits there to scan.
You should be checking the return value from scanf - it gives you the number of items successfully scanned which will be 1 initially for the 1 before the decimal point, and 0 from then on.
As an aside, scanf stands for "scan formatted" and I'll guarantee you won't find anything more unformatted than user input.
Investigate looking into fgets for line input. Here's a copy of a function I often use for such purposes:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
Once you get a line in with that function, you can sscanf it to your heart's content, handling errors much easier.
What's happening is that scanf stops reading an integer when it sees the '.' character, and leaves it in the input buffer. Then subsequent calls to scanf fail because the next character is '.' and not something parseable as an integer.
How do you fix this? The first step is to forget you ever heard of scanf and always use fgets to read whole lines of input, then process them after you read them into a string buffer. You can use sscanf for this purpose, but a robust function like strtol would be a lot better.
Problem with buffer - I think the remaining part (.5) remains on the buffer.
use flushall(); after your scanf("%d..

Resources