Given a text file, for example:
cdcd dcdaqw cdcd KKAN 89 bxb hqhq1bhA
100uuz
cnkx
n jk xjx100mc
...
.+1+
I want to find the sum of all the numbers contained in the various strings:
In the given example, I want to sum 89 100 1 100 1.
I made many attempts at this(IE, fscanf of each string and trying to save the int values in an array), but they all failed.
So this is fairly straightforward. At every position in the file we ask "is there a number here?". If there is, print it out. If there isn't try starting at the next character.
Based on how we understand fscanf() works, we'll test each character at most twice.
Code
#include <stdio.h>
#include <stdbool.h>
int main() {
FILE * fd = fopen("in.txt", "r");
while (true) {
unsigned number;
int rc = fscanf(fd, "%u", &number);
if (rc == EOF)
break;
else if (rc == 0)
fseek(fd, 1, SEEK_CUR);
else if (rc == 1)
printf("%u\n", number);
}
}
Input File
cdcd dcdaqw cdcd KKAN 89 bxb hqhq1bhA
100uuz
cnkx
n jk xjx100mc
...
.+1+
Output
89
1
100
100
1
Next steps
It should be fairly obvious how to extend this to report the sum, instead of the numbers themselves.
You could be using strtol
You have an example at the bottom of the page which does pretty much what you want. You're only going to need to manually skip the non-digit characters
Related
Write a C program that reads from the keyboard a natural number n
with up to 9 digits and creates the text file data.out containing the
number n and all its non-zero prefixes, in a single line, separated by
a space, in order decreasing in value. Example: for n = 10305 the data
file.out will contain the numbers: 10305 1030 103 10 1.
This is what I made:
#include <stdio.h>
int main()
{
int n;
FILE *fisier;
fisier=fopen("date.in","w");
printf("n= \n");
scanf("%d",&n);
fprintf(fisier,"%d",n);
while(n!=0)
{
fisier=fopen("date.in","r");
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
}
Few things:
Function calls may return error. You need to check that every time.
fisier=fopen("date.in","w");
This should have been followed by an error check. To understand more on what it return, first thing you should do is read the man page for that function. See man page for fopen(). If there is an error in opening the file, it will return NULL and errno is set to a value which indicates what error occurred.
if (NULL == fisier)
{
// Error handling code
;
}
Your next requirement is separating the numbers by a space. There isn't one. The following should do it.
fprintf(fisier, "%d ", n);
The next major problem is opening the file in a loop. Its like you are trying to open a door which is already open.
fisier=fopen("date.in","r");
if(NULL == fisier)
{
// Error handling code
;
}
while(n!=0)
{
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
A minor issue that you aren't checking is the number is not having more than 9 digits.
if(n > 999999999)
is apt after you get a number. If you want to deal with negative numbers as well, you can modify this condition the way you want.
In a nutshell, at least to start with, the program should be something similar to this:
#include <stdio.h>
// Need a buffer to read the file into it. 64 isn't a magic number.
// To print a 9 digit number followed by a white space and then a 8 digit number..
// and so on, you need little less than 64 bytes.
// I prefer keeping the memory aligned to multiples of 8.
char buffer[64];
int main(void)
{
size_t readBytes = 0;
int n = 0;
printf("\nEnter a number: ");
scanf("%d", &n);
// Open the file
FILE *pFile = fopen("date.in", "w+");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
while(n != 0)
{
// Append to the file
fprintf(pFile, "%d ", n);
n = n / 10;
}
// Done, close the file
fclose(pFile);
printf("\nPrinting the file: ");
// Open the file
pFile = fopen("date.in", "r");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
// Read the file
while((readBytes = fread(buffer, 1, sizeof buffer, pFile)) > 0)
{
// Preferably better way to print the contents of the file on stdout!
fwrite(buffer, 1, readBytes, stdout);
}
printf("\nExiting..\n\n");
return 0;
}
Remember: The person reading your code may not be aware of all the requirements, so comments are necessary. Secondly, I understand english to a decent level but I don't know what 'fisier' means. Its recommended to name variables in such a way that its easy to understand the purpose of the variable. For example, pFile is a pointer to a file. p in the variable immediately gives an idea that its a pointer.
Hope this helps!
To draw a conclusion from all the comments:
fopen returns a file handle when successfull and NULL otherwise. Opening a file twice might result in an error (it does on my machine), such that fisier is set to NULL inside the loop. Obvioulsy fprintf to NULL wont do anything.
You only need to call fopen once, so remove it from the loop. After that it will work as intended.
It's alwas good to check if the fopen succeeded or not:
FILE *fisier;
fisier=fopen("date.in","w");
if(!fisier) { /* handle error */ }
You print no spaces between the numbers. Maybe that's intended, but maybe
fprintf(fisier,"%d ",n);
would be better.
I am working on a text file containing integers separated by spaces, for instance:
1 2 57 99 8 14 22 36 98 445 1001 221 332 225 789 1111115 147 0 1 21321564 544 489 654 61266 5456 15 19
I would like to re-format this file to only contain 5 integers in any line but the last, and at most 5 integers in the last line.
My code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f; // main file (A.txt)
FILE *g; // file copy (B.txt)
// open A.txt to read data
f = fopen("file/path/here/A.txt", "r");
if (f == NULL) {
printf("Read error.\n");
fclose(f);
return -1;
}
// open B.txt to write data
g = fopen("file/path/here/B.txt", "w");
if (g == NULL) {
printf("Write error.\n");
fclose(g);
return -2;
}
int line = 1; // first line in output file
while (!feof(f)) { // not end-of-file
char number[1000];
int i = 0;
for (i = 0; i <= 4; i++)
if (fscanf(f, "%s", number) == 1) { // one number read
fprintf(g, "%s", line + i, number);
}
line += i;
}
// close files
fclose(f);
fclose(g);
return 0;
}
When I run this in Code::Blocks, I get the 'Segmentation fault (core dumped) Process returned 139' message. I suspect that the problem lies in the 'if' statement and my use of formats. Needless to say, I'm relatively new to C. How might I fix this?
The simple reason for your segmentation fault is expression fprintf(g, "%s", line + i, number);, in which you state to pass a pointer to a string (i.e. char*), but actually pass a number (i.e. line + i); hence, the value of line + i, which is probably 1, ..., is interpreted as a pointer to memory address 1, which is not allowed to be addressed. It is as if you wrote fprintf(g, "%s", 1), which crashes, too;
So basically change this expression into fprintf(g, "%s", number);, and it should at least not crash (unless you have numbers with more than 999 digits).
There are some other issues in your code, e.g. that you open B.txt for write and assign it to g, but then you test and close the file using variable f.
But maybe above "crash solution" brings you forward, such that you can work further on your own. Note that - if B.txt failed opening, then your code would also have crashed because of passing NULL as file stream argument to fprintf.
The issue is with the use of fscanf and then fprintf.
fscanf knows how to parse a string into a number. E.g. fscanf(f, "%d", &var);. This reads a signed integer from the file handle f into the variable var. This can then be printed with fprintf.
As it stands, the first fscanf slurps the entire input into number (assuming that 1000 char is enough) and the following ones are not expected to be called
I'm a beginner in C, and I've got problem I can't figure out, and wasn't able to find a solution on other threads here.
I'm trying to read integers from a keyboard input/ txt file with the following code:
int grades[MAX_GRADES_LENGTH]={0}, histogram[HISTOGRAM_SIZE]={0};
int maxGradesHistogramBucket=0, median=0, gradesLength=0;
double avg=0.0;
int grade=0;
printf("Enter grades:\n");
while (scanf("%d",&grade) != EOF)
{
grades[gradesLength]=grade;
gradesLength=gradesLength+1;
}
I'm supposed to set these "grades" in the grades[] array and count the length of the array along the loop.
Somehow the loop is misbehaving, it seems that some inputs are ok with the loop, but for some inputs(most of them actually) the scanf() doesn't get the EOF, whether it's an actual end of file, or the ^D command in the terminal.
I've heard the scanf() is not the most reliable method to read data, but unfortunately I can't use anything else since we haven't learned any other method in class so we can only use scanf() on our homework.
I've tried to change the!= EOF with == 1 and its all the same.
for the input
100 0 90 10 80 20 70 30 60 40 50
for example it works fine.
but for the input:
0 50 100
the loop is infinite.
I'm using a macbook pro btw (if it matters).
Any ideas?
If you type a letter instead of a number, scanf() will return 0 (as in, "zero successfully converted numbers") and not EOF (as in, "there was no data left to read"). The correct test is to ensure that you got the expected number of values — in this case, 1:
while (scanf("%d", &grade) == 1)
If you need to know whether you got to EOF or got no result (but reading the rest of the line might clear the problem), then capture the return value from scanf():
int rc;
while ((rc = scanf("%d", &grade)) == 1)
{
}
if (rc != EOF)
…read the rest of the line, or at least the next character, before resuming the loop…
And, if you really want to, you could then write:
int rc;
while ((rc = scanf("%d", &grade)) != EOF)
{
if (rc == 1)
grades[gradesLength++] = grade;
else
{
printf("Discarding junk: ");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
putchar('\n');
if (c == EOF)
break;
}
}
The code in the else clause could plausibly be put into a function. It might also report the messages to standard error rather than standard output. It is courteous to let the user know what it was that you objected to. You could stop before newline with a different test (&& !isdigit(c) && c != '+' && c != '-', using isdigit() from <ctypes.h>). However, the user doesn't have a chance to re-edit the stuff they put after the letters, so you may be going to misinterpret their input. It is probably better just to throw away the rest of the line of input and let them start over again.
As chux noted, after reading a character that could be part of an integer, that character needs to be put back into the input stream. Therefore, if I were going to analyze the rest of the line and restart scanning at the first data that could actually be part of an integer, I'd consider using something like:
#include <ctype.h>
static inline int could_be_integer(int c)
{
return isdigit(c) || c == '+' || c == '-');
}
and then the else clause might be:
else
{
printf("Discarding junk: ");
int c;
while ((c = getchar()) != EOF && c != '\n' && !could_be_integer(c))
putchar(c);
putchar('\n');
if (could_be_integer(c))
ungetc(c, stdin);
else if (c == EOF)
break;
}
This gets messy, as you can see. Sometimes (as Weather Vane noted in a comment), it is easier to read a line with fgets() and then use sscanf() in a loop (see How to use sscanf() in a loop?). Be wary of suggestions about Using fflush(stdin); it isn't automatically wrong everywhere, but it won't work on a MacBook Pro under normal circumstances.
On the whole, simply ignoring the rest of the line of input is usually a better interface decision.
It works for me.
I enclosed your snippet thus:
#include <stdio.h>
#include <errno.h>
#define MAX_GRADES_LENGTH 20
#define HISTOGRAM_SIZE 20
main()
{
int grades[MAX_GRADES_LENGTH]={0}, histogram[HISTOGRAM_SIZE]={0};
int maxGradesHistogramBucket=0, median=0, gradesLength=0;
double avg=0.0;
int grade=0;
int i;
printf("Enter grades:\n");
while (scanf("%d",&grade) != EOF)
{
grades[gradesLength]=grade;
gradesLength=gradesLength+1;
}
if (errno)
perror("grade");
for (i = 0; i < gradesLength; ++i) {
printf("%d\n", grades[i]);
}
}
and ran it:
$ a.out
Enter grades:
100 0 90 10 80 20 70 30 60 40 50
100
0
90
10
80
20
70
30
60
40
50
$ a.out
Enter grades:
0 50 100
0
50
100
$
Perhaps you are looking in the wrong place. Maybe the bug is in your output routine?
Personally, if had to do this, given some ambiquity over what scanf returns when, and without rewriting it, then this small change is probably more reliable:
int i, r;
printf("Enter grades:\n");
while ((r = scanf("%d",&grade)) > 0)
I'm trying to read from a text file and write to one, but every time I execute my code, nothing happens with the text files. By "nothing happens", I mean that the program won't read my input file and no data is exported into my output file. Could someone point out why it is not working? Thanks for any help given in advance. Here is my code:
#include <stdio.h>
#include <stdlib.h>
FILE *inptr, *outptr;
int main() {
int a, b, c;
inptr = fopen("trianglein.txt","r"); //Initialization of pointer and opening of file trianglein.txt
outptr = fopen("triangleout.txt","w"); //Initialization of pointer and opening of file triangleout.txt
while((fscanf(inptr,"%d %d %d",&a, &b, &c))!= EOF){
fprintf(outptr,"\n%2d %2d %2d\n",a,b,c);
if(a+b>c && b+c>a && c+a>b){
fprintf(outptr, "This is a triangle.\n");
if(a !=b && b !=c && a!=c){
fprintf(outptr, "This is a scalene triangle.\n");
if(a==b && a==c && c==b){
fprintf(outptr, "This is an equilateral triangle.\n");
if(a*a+b*b==c*c || b*b+c*c==a*a || a*a+c*c==b*b){
fprintf(outptr, "This is a right trianlge.\n");
}
}
}
}
}
return 0;
}
trianglein.txt contents:
10 12 15
2 3 7
3 4 5
6 9 5
6 6 6
6 8 10
7 7 9
Multiple problems.
Firstly, you need to check if inptr and outptr are valid by testing against NULL.
Secondly, fscanf can return either EOF, 0 or > 0.
If your input file doesn't contain valid input.
Also there are problems in that you can get 3 ints read successfull, or 2 ints or 1 and the value of a, b and c are only optionally set.
If no conversion took place on the input then the value of zero is returned in which case the while loop will exit.
Also bear in mind that with the scanf style functions this input will succeed and return the value of 1.
"1rubbish"
I think what you may want is something like the following:
// Somewhere near the top
#include <stderr.h>
// ... other includes
const char* inname = "trianglein.txt";
const char* outname = "triangleout.txt";
// Any other stuff
// Inside main...
// Initialization of pointer and opening of file trianglein.txt
if ((inptr = fopen(inname,"r")) == 0){
fprintf(stderr, "Error opening file %s: %s", inname, strerror(inname));
return -1;
}
// Initialization of pointer and opening of file triangleout.txt
if ((outptr = fopen(outname,"w")) == 0){
fprintf(stderr, "Error opening file %s: %s", outname, strerror(outname));
return -1;
}
int result;
while(true){
result = fscanf(inptr,"%d %d %d",&a, &b, &c);
if (result == EOF)
break;
if (result < 3) // Ignore incomplete lines
continue;
// do the normal stuff
}
Your program is working fine in my system. I use Code::Blocks 10.05 on Windows 7.
The only possibility of a logical error occurs when you have the file trianglein.txt with less than 3 integer values to be read by the fscanf(). For example trianglein.txt file with values 1, 1 2, 1 2 3 4, 1 2 3 4 5 etc. will give incorrect values to the variables b and/or c. So initialize a=-1, b=-1, c=-1 before the execution of each iteration of the loop and check them after reading.
If you are running the program check the file triangleout.txt for access rights. Some times you may not have write access on that particular file.
By the way the classification logic is wrong. An equilateral triangle can not be a right angled one.
Try putting
fclose(inptr);
and
fclose(outptr);
at the end of your code.
EDIT: As suggested by icktoofay, this answer is wrong.
You have to do fclose() or fflush() in order to get the data written to the file.
Insert these code right before return 0;
fclose(inptr);
fclose(outptr);
#include <stdio.h>
int main(void)
{
clrscr();
FILE *fin;
fin=fopen("data.txt","r");
if(fin==NULL)
{
printf("can not open input fil");
return 0;
}
long data[2];
while(!feof(fin))
{
fscanf(fin,"%ld %ld",&data[0],&data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
fclose(fin);
return;
}
above is my c code for reading a table from a file.In that ..last value is printing 2 times !!!
data.txt
1 34
2 24
3 45
4 56
5 67
but I can not get proper values with broken table like below...How can I resolve it ? (here It should work where it does not find any value it should return "null space" or zero ..but not the next value..)
data.txt
1 34
2
3 45
4
5 67
as well as
data.txt
1 34
57
3 45
4
5 34
above is my c code for reading a table from a file.In that ..last value is printing 2 times !!!
The last value is printing two times due to the structure of the file reading loop. The eof() flag is not set until an attempt is made to read past the end of the file. When fscanf() reads the last two longs from the last line of the file eof() is not yet set but the next call to fscanf() fails and sets eof() but the result of fscanf() is not queried immediately, resulting the use of the previously extracted longs: check the result of all read operations immediately.
A possible solution is to read a line at a time, using fgets(), and then use sscanf() to extract the long value(s) from the read line. If fscanf() is used, it would read past the new-line character to locate the second requested long, which is not the desired behaviour.
For example:
char line[1024];
while (fgets(line, 1024, fin))
{
/* Assign appropriate default values.
sscanf() does not modify its arguments
for which it has no value to assign.
So if 'line' has a single long value
data[1] will be zero. */
long data[2] = { 0, 0 };
/* You can use 'result' if you require to take particular
action if it reads only 1, or 0, items. */
int result = sscanf(line, "%ld %ld", &data[0], &data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
(in response to question update) To differentiate between lines where second value is missing:
2
and lines where first value is missing:
57
a valid range (or some other criteria) is required to determine which value (the first or second) was missing from the line:
int result = sscanf(line, "%ld %ld", &data[0], &data[1]);
if (1 == result)
{
if (data[0] >= 1 && data[0] <= 9)
{
printf("\n%ld 0", data[0]);
}
else
{
/* Read value was the second value. */
printf("\n%ld %ld", ++last_first_value, data[0]);
}
}
where last_first_value is a long that stores the current value of the first value (either the last successfully read first value or computed from the last successfully read first value).
while(!feof(fin))
{
fscanf(fin,"%ld %ld",&data[0],&data[1]);
printf("\n%ld %ld",data[0],data[1]);
}
feof doesn't return true until after you attempt to read past the end of the file, so the loop will execute once too often. It's better to check the return value of fscanf and if it doesn't match what you expect (2 in this case), then check for EOF. Here's one possible restructuring:
int good = 1;
while (good)
{
int itemsRead = fscanf(fin, "%ld %ld", &data[0], &data[1]);
if (itemsRead == 2)
{
// process data[0] and data[1] normally
}
else
{
good = !good;
if (feof(fin))
printf("Hit end of file\n");
else if (ferror(fin))
printf("Error during read\n");
else
printf("Malformed input line\n");
}
}