i am very confused about reading from txt file - c

sorry i'm new at c
i want to read these data from txt file.
A 7
c 5
y 6
U 9
j 4
Z 3
z 5
0
here is my code
while(feof(input)==0){
char c;
int num;
fscanf(input,"%c%d",&c,&num);
printf("%c:%d\n",c,num);
}
but result in console is not same as txt file
the result is
Open file complete
A:7
:7
c:5
:5
y:6
:6
U:9
:9
j:4
:4
Z:3
:3
z:5
:0
my code is correct, isn't it?

fscanf(input,"%c%d",&c,&num);
my code is correct, isn't it
You're not eating the newlines. Change that to:
fscanf(input,"%c%d ",&c,&num);
^
As explanation, each line ends with a a character, '\n'. If you don't do anything about it, %c will try to read it and you'll get confusing results. A cheap trick is to add a blank space in fscanf which makes it eat all blanks after a %c%d couple.
EDIT
In light of comment from Peter Kowalski:
shouldn't it be fscanf(input,"%c %d ",&c,&num); ? I've put additional
space between %c and %d
This is a very good question. Thing is %d is one of the specifiers that ignore leading space. No matter how many blanks are in the stream, scanf will eat and discard them. Therefore a blank before %d is implicit.

You also need to eat the newlines.
fscanf(input,"%c%d\n",&c,&num);

Quick fix: simply adjust your printf() statement from
printf("%c:%d\n",c,num);
to
printf("%c %d",c,num);
There are other ways, like adjusting your current scanf(), which is better as it fixes the problem at the source (you are reading and keeping the newline).
Alternatively you could just read the whole line without parsing it into components and print it out.

Related

Integer taken with scanf() does not get its intended value in C

Here is my C code:
#include "stdio.h"
int main()
{
int minx, x;
printf("Enter two ints: ");
scanf( "%d-%d", &minx, &x);
printf("You wrote: minx is %d x is %d", minx, x);
}
When the input is 5-3 or 5- 3 the output is You wrote: minx is 5 x is 3 which makes sense. However, when the input is 5 -3 or 5 - 3 or 6 -4 the output is You wrote: minx is 5 x is 8. I expected - to skip white spaces, so I expected minx to be 5 and x to be 3,6 and 4 for the other input. This also happens when - in %d-%d changed to ?, *, + even with the same inputs. I know it is probably because of that space after the first int. Here it says only three format specifiers do not skip white space — Whitespace before %c specification in the format specifier of scanf function in C. Did I get this wrong? Why - does not skip leading space here? What is the actual problem here and what is the cause of it? Why is it 8? What other operators or chars can lead to similar problems?
Let's look at your scanf format specifier "%d-%d" in detail:
%d skip whitespace if necessary, then read an integer
- match a literal '-' character
%d skip whitespace if necessary, then read an integer
So the inputs 5-3 and 5- 3 both work just fine. But when the input is 5 -3 (or anything else with a space before the -) the parse fails, because scanf does not immediately see the - it expects.
If that's not what you expected, or not what you want, or if that doesn't make sense, or if that's not how you'd like scanf to work, I'm afraid that's too bad: scanf works the way it works.
How can you fix this? That depends in part on why you included the - character in your format string in the first place.
You can use %d%d or %d %d, which will simply read two integers (separated by at least one whitespace character). If there's a - character preceding the second integer, that integer will be read as negative.
You can use %d -%d, which will skip (arbitrary) whitespace before it tries to match the - character.
You can use two separate scanf calls.
If you do continue to use scanf, you really need to check its return value so that your program can detect the case that the expected inputs were not matched.
Finally, you can use something other than scanf.
My recommendation to you depends on the ultimate purpose of this program.
If it's just for learning, then minimize the amount of time you spend fussing with the way your program does input at all. For example, if you need to read an integer, use one %d. As long as you can get the numbers you need into your program (so that you can test the rest of your program), you're fine. If there are things you can type that cause scanf to get confused, just don't worry about it, just don't type those things. Don't try to do anything fancy — that's not what scanf is for.
If this is a "real" program, that does have to accept arbitrary user input, or input with a specific syntax (like with that - in the right place), and if you need to deal gracefully with incorrect input, printing appropriate errors, and not reading the wrong values or getting confused — then run, do not walk, away from scanf, and never use it again. It is effectively impossible to write a program that performs high-quality input using scanf. Not even a C expert can do it. It's simply not worth it. You will spend five times as long, and get an inferior result, than if you simply abandoned scanf and read your input a line at a time using fgets or the like, then parsed the input line (perhaps even using sscanf — but again, check its return value).
Addendum: It's true, all format specifiers — with three exceptions (%c, %[…] scan sets, and %n) — skip whitespace before beginning their work. But format specifiers are things that begin with %. Literal characters in the format string must match exactly, and there's no implicit whitespace skipping for them. If you want to skip whitespace at spots in the input other than before the % format specifiers that do it, you can include a literal whitespace character (usually a single space) in your format string.
You need to check the return value of scanf. You should be doing this, in general, for every library function you call that has a return value.
In your case, scanf would return 2 (meaning two output parameters were set) for valid input. If you get any other return value, the input does not match the format you specified, and you should ignore the contents of your output parameters minx and x.

Scanf function stops after newline and reads just a small part of input ( should ignore newline and tabs )

The whole question in a short version:
I want to load this input
4
CAAC
28 EAAEB5
F489AD95
but all I can get from it is :
4
I am trying to make from that input these params : 4 CAAC 28 EAAEB5 F489AD95
--------------- Detailed Explanation with my code ---------------------------
I am new in C language and I am trying to make an input, to go be as a string and work with it after ... I have a problem to handle "Whitespaces" such as [ "\n" , "\t" and " " ] Here is an input I gave to my Compiler :
4
CAAC
28 EAAEB5
F489AD95
there are bunch of spaces, tabs etc. The thing I want to do, is to read it and replace \n and \t ( in clode bellow i am trying to ignore it, because of right after scanf() finds \n it skips the rest of it.
This is one of the codes I tried for now:
#include <stdio.h>
int main()
{
int number;
char chr[200];
// %d -> I know that there should be number at the beginning, so until character / space appears, I want to read the number.
// scanf("%d", &number);
// ignores \n and \t and then puts it in chr
scanf(" %[^\t\n]s", &chr);
// last should be \n so this is just acheck if there is ( its gonna be in if later )
scanf("%c");
printf("\n %s", chr);
printf("\n Heythere");
return 0;
}
This is an output I have got:
4
Heythere
I have been thinking about putting it in a loop, but the problem is, that last character is "\n" and it can appear multiple times in a given string.
I am currently trying to find the best option for scanf() to read those lines and ignore new lines
/////////
In other words :
I am trying to make from that input these params : 4 CAAC 28 EAAEB5 F489AD95
Any idea how to fix it, to be able to buffer it completely ? ( also the best answer that will help me, will be the one, that will replace those "\n" and "\t" with one single " " ( space ) Thank you for your answers in advance ( also sorry if its really simple and answer like million times ... I am stuck here for a week )
You have several options:
Use official discussion thread in IS
Ask any of the consultants during their time
Alternatively, ask them for another time, if you can't come
Write an email to any of the consultants
My feelings about this post
On the face of it, all you need is a loop to read five strings:
char data[5][100];
int i;
for (i = 0; i < 5; i++)
{
if (scanf("%99s", data[i]) != 1)
{
fprintf(stderr, "Unexpected input failure (i = %d)\n", i);
exit(EXIT_FAILURE);
}
}
Now the elements of the array will contain the 5 strings ('words') you supplied.
By design, the scanf() functions largely ignore white space except to the extent it separates strings or numbers. All but three of the conversion specifiers skip over leading white space — the exceptions are %c, %[…] (scan sets), and %n.
The %99s conversion specification skips leading white space (blanks, tabs, newlines), consumes up to 99 characters that aren't white space, and stops at the first white space (or when the string is full), leaving the white space in the input stream to be processed by the next input if the string wasn't full.
Obviously, you have to work a bit harder if you don't know that there are five strings to read — but the basic idea is the same.
If you want to conserve or change newlines, tabs, blanks, then scanf() is not the correct tool for the job. It doesn't care about white space and you do — that's not going to lead to happiness. Then you use fgets() or POSIX getline() to read the lines of input, and you can process the blanks, tabs and newlines as you see fit.

scanf("%[^\n]s",a) with set size of string

So I had a code where I use
scanf("%[^\n]s",a);
and has multiple scanf to take different inputs some being string input. So I understand that scanf("%[^\n]s",a) takes input until new line has been reached, however I was wondering suppose my string can only hold up to 10 characters, then after my string has been filled, but new line hasn't been reached how can i get rid of the extra input before going to new line. I was thinking of doing getchar() until new line has been reached however in order to even check if my 10 spots has been filled I need to use getchar, so doesn't that mess up my next scanf input? Anybody have any other way to do it? Still using scanf() and getchar?
scanf("%[^\n]s",a) is a common mistake; the %[ directive is distinct from the %s directive. What you're asking from scanf is:
A group of non-'\n' characters, followed by...
A literal s character.
Perhaps you intended to write scanf("%[^\n]",a)? Note the deleted s...
You can use the * modifier to suppress assignment for a directive, for example scanf("%10[^\n]", a); followed by scanf("%*[^\n]"); to read and discard up to the next newline and getchar(); to read and discard that newline:
scanf("%10[^\n]", a);
scanf("%*[^\n]"); // read and discard up to the next newline
getchar(); // read and discard that newline
As pointed out, the two format strings could be concatenated to reduce the number of calls to scanf. I wrote my answer this way for the sake of documentation, and I'll leave it as is. Besides, I figure that attempt at optimisation would be negligible; a profiler is likely to indicate much more significant bottlenecks for optimisation in realistic scenarios.
You can use this format to hold the first 10 characters and keep the next lines of input:
scanf("%10[^\n]%*[^\n]",a);
getchar();

How to have scanf ignore extraneous text from an input file?

I'm attempting to give a program input of the following form:
11 22 #3
30 2 #^
1 4 #B asdfghj
However, there are several lines (like the last) that have extra text in them. I'm trying to have the program ignore them to no avail.
Below is my current code:
int x_coord;
int y_coord;
char type[3];
do(grid[y_coord][x_coord]=type[1]);
while(scanf("%d %d %s",&x_coord,&y_coord,type)!=EOF);{
for(i=1; i<=30;i++){
for(j=1; j<=30;j++){
printf("%c",grid[i][j]);
}
printf("\n");
}
}
I've tried to add an extra parameter%*s to scanf to attempt to catch any extra text, but I couldn't get it to run.
Does anyone have any suggestions on how to handle the extra text in the input file?
Your loop seems very oddly formed.
do(grid[y_coord][x_coord]=type[1]);
while(scanf("%d %d %s",&x_coord,&y_coord,type)!=EOF);
Is y_coord, x_coord and type initialized properly for the assignment to work?
Also, scanf() will return the number of elements successfully scanned. You can use that for additional error checking.
In any case, if your input is well-formed, then you can use the following format string:
scanf("%d %d %s%*[^\n]%*c",&x_coord,&y_coord,type)
After parsing the first three arguments, this will discard anything that is not a newline character, and then discard the newline itself.
Using scanf() is error prone because badly formed input can cause scanning to jam or unexpected errors as unintended portions of the input get interpreted incorrectly. For line delimited input, it is better to read in the entire line first with fgets() and then parse the line with sscanf().

Write int structure data type to file in c

A bit of background to my program. I'm asking the user to input coordinates for two different colour crystals. This will be held in a structure and then written to file, to be read back later by the program (function yet to be written).
I have had a look on forums and blogs but I seem to be only finding results relating to character arrays, whereas I am using an int array.
My code works fine until the writing of the data to the file. (this is the snippet of code)
char fname[20];
FILE *fp;
int loop;
struct coord{
int x;
int y;
};
for(loop=0;loop<3;loop++){
printf("Enter MAGENTA X coordinate: \n");
scanf("%2d",&mg[loop].x);
printf("Enter MAGENTA Y coordinate: \n");
scanf("%2d",&mg[loop].y);
printf("\n\n");
}
for(loop=0;loop<3;loop++){
printf("Enter YELLOW X coordinate: \n");
scanf("%2d",&ylw[loop].x);
printf("Enter YELLOW Y coordinate: \n");
scanf("%2d",&ylw[loop].y);
printf("\n\n");
}
clrscr();
printf("\nDetail entered:");
printf("\n\n\tMagenta\t\tYellow\n");
for(loop=0;loop<3;loop++){
printf("\tx %d,%d y\tx %d,%d y\n",mg[loop].x,mg[loop].y,ylw[loop].x,mg[loop].y);
}
printf("\n\nPlease save your data. Enter file name: ");
gets(fname);
fp=fopen(fname,"w");
for(loop=0;loop<3;loop++){
fprintf(fp,"%d,%d ",mg[loop].x,mg[loop].y);
fprintf(fp,"%d,%d ",ylw[loop].x,ylw[loop].y);
}
fclose(fp);
Thank you in advance.
There's nothing wrong with how you write the data to the file (maybe except that you should check the return value of fopen.)
Your problems are in the input of your data from stdin. First, your read in a bunch of coordinates with scanf. scanf is not a line-based format; it treats a new-line character like any other white-space.
Then you use gets, which you really shouldn't - use fgets instead, because it allows you to specify a maximum buffer size so that you don't overflow your buffer of 20.
Okay, say you use fgets, which is a line-based format. You have to take care when mixing scanf and fgets, because they work differently. Also input from the console is usually buffered until the next newline, when it is all flushed, which can create a discrepancy between what you see on the screen and how the program processes input.
Say you read two numbers with scanf and then a filename with fgets. Your input looks like this:
1 2 \n 5 1 \n d a t a . t x t
a a b b b c
After reading the first number the input marker is after the number, before the newline. scanf skips white space before numbners read with "%d", so the second number is read in, but again, input stops before the newline. Then you read a line with fgets and read everything up to the next newline, which is nothing. The real filename would be read by the next scanning function, but there isn't any, so it's discarded.
(That's where your str != NULL is coming from: it's an assertion that has failed withinfopen`. This is nopt something that the compiler does, though. When you run the program, it has already been compiled. The run-time library does such error checking of conditions it can't know at compile time.)
(What's worse: fgets, unlike gets, retains the newline after the read string. You shoud remove that and possibly other leading and trailing white-space, too. Otherwise you'll end up with a file name that has a new-line in it, which is not funny.)
Anyway, how can you fix this? Change your scanf formats from "%d" to "%d " with a trailing space. "Space" has a meaning to scanf: read any amount of white space.
Alternatively, you could stick to scanf and read your filname with scanf("%19s ", filename). That has the benefit of reading a string without any whitespace in it.
Reportedly you have fixed this by calling fflush(stdin) before reading the filename. The behaviour of fflush on input streams is implementation-dependent and not guaranteed by the standard. If it worked for you, leave it at that.

Resources