I'm learning about file i/o in C language and I wrote this program that reads a file, and then for every even number found, it has to print * to the screen.
My problem is that my program keeps printing * forever.
I have tried different ways,some from this website, but I can't seem to understand how to read until end of a text file using EOF.
I want to learn how to read a text file until the end of the file please.
How do I read until the end of a text file? EOF in C.
int main(void)
{
int num;
FILE *ifp;
ifp = fopen("numbers.txt", "r" );
if(ifp == NULL)
{
exit(1);
}
do
{
fscanf(ifp, "%d", &num);
if(num%2 == 0)
{
printf("*\n");
}
} while(num != EOF);
fclose(ifp);
return 0;
}
you need to check the result of the scanf
do
{
int result;
result = fscanf(ifp, "%d", &num);
if(result == EOF) break;
if(result != 1)
{
printf("scanf error\n");
break;
}
if(num%2 == 0)
{
printf("*\n");
}
} while(1);
Instead, you should try while loop.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int num;
FILE *ifp;
ifp = fopen("numbers.txt", "r" );
if(ifp == NULL)
{
perror("Read");
exit(1);
}
while(fscanf(ifp, "%d ", &num) != EOF)
{
if(num % 2 != 0) // For every odd number.
{
printf("*\n");
}
}
fclose(ifp);
return 0;
}
Have you tried this:
while (!feof(ifp)) {
if (fscanf(ifp, "%d ", &num) > 0) {
if(num % 2 != 0) // For every odd number.
{
printf("*\n");
}
}
}
It's doing this because while(num != EOF) is testing whether int num, the number read from the file, is EOF, rather than whether the end of file has been reached.
To test whether the EOF flag has been set on FILE *ifp, use while(!feof(ifp)) instead.
Related
I'm studying textfile topic in C and I have got a question: what can I use instead of __fpurge(stdin); but make this function work like __fpurge(stdin); and I am not allowed to include <stdlib.h> in this program. I have read this c - need an alternative for fflush but as long as I'm not allowed to #include <stdlib.h> so I can't use strtol.
void generateBill() {
FILE *fp, *fp1;
struct Bill t;
int id, found = 0, ch1, brel = 0;
char billname[40];
fp = fopen(fbill, "rb");
printf("ID\tName\tPrice\n\n");
while (1) {
fread(&t, sizeof(t), 1, fp);
if (feof(fp)) {
break;
}
printf("%d\t", t.pid);
printf("%s\t", t.pname);
printf("%d\t\t\t\n", t.pprice);
total = total + t.pprice;
}
printf("\n\n=================== Total Bill Amount %d\n\n", total);
fclose(fp);
if (total != 0) {
//__fpurge(stdin);
printf("\n\n\n Do you want to generate Final Bill[1 yes/any number to no]:");
scanf("%d", &ch1);
if (ch1 == 1) {
brel = billFileNo();
sprintf(billname, "%s%d", " ", brel);
strcat(billname, "dat");
fp = fopen(fbill, "rb");
fp1 = fopen(billname, "wb");
while (1) {
fread(&t, sizeof(t), 1, fp);
if (feof(fp)) {
break;
}
fwrite(&t, sizeof(t), 1, fp1);
}
fclose(fp);
fclose(fp1);
fp = fopen(fbill, "wb");
fclose(fp);
}
total = 0;
}
}
for a replacement for __fpurge(stdin) suggest:
int ch;
while( (ch = getchar() ) != EOF && ch != '\n' ){;}
which only requires #include <stdio.h>
__fpurge is a non-standard function only available on some systems (glibc 2.1.95, IBM zOS...) that discards input read into the stream buffer not yet consumed by getc().
As explained in the linux manual page, Usually it is a mistake to want to discard input buffers.
You read user input with scanf(), which stops scanning input when the requested conversion is completed, for example %d stops reading the characters typed by the user when it reads a character that cannot continue the number and leaves this character in the input stream. Since stdin is usually line buffered when attached to a terminal, you should just read and discard any remaining bytes in the line input by the user after you process the input.
Here is a simple function for this purpose:
int flush_input(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
return c;
}
You would call this function after processing user input and you should test the return value of scanf() to ensure the user input had the expected syntax.
Here is a modified version of you function:
#include <errno.h>
#include <string.h>
// return a non zero error code in case of failure
int generateBill(void) {
FILE *fp, *fp1;
struct Bill t;
int id, found = 0, ch1, brel = 0;
char billname[40];
fp = fopen(fbill, "rb");
if (fp == NULL) {
fprintf(sdterr, "cannot open %s: %s\n", fbill, strerror(errno));
return 1;
}
printf("ID\tName\tPrice\n\n");
while (fread(&t, sizeof(t), 1, fp) == 1) {
printf("%d\t", t.pid);
printf("%s\t", t.pname);
printf("%d\t\t\t\n", t.pprice);
total = total + t.pprice;
}
printf("\n\n=================== Total Bill Amount %d\n\n", total);
if (total != 0) {
int res;
printf("\n\n\n Do you want to generate Final Bill[1 yes/any number to no]:");
while ((res = scanf("%d", &ch1)) == 0) {
fprintf("Invalid input. Try again\n");
flush_input(stdin);
}
flush_input(stdin);
if (res == EOF) {
fprintf("premature end of file on input\n");
fclose(fp);
return 2;
}
if (ch1 == 1) {
brel = billFileNo();
snprintf(billname, sizeof billname, "bill-%d-dat", brel);
rewind(fp);
fp1 = fopen(billname, "wb");
if (fp1 == NULL) {
fprintf(sdterr, "cannot open %s: %s\n", billname, strerror(errno));
fclose(fp);
return 1;
}
while (fread(&t, sizeof(t), 1, fp) == 1) {
fwrite(&t, sizeof(t), 1, fp1);
}
fclose(fp1);
}
}
fclose(fp);
return 0;
}
As title states, I'm trying to read numbers from an external text file and assign them to an array. I'm able to manipulate the array and write the result to another file if I manually create the array, but as is, the fscanf() is pulling garbage from the text file. This is what I currently have, I've been reading other posts here and I've changed it like 12 times now but I think I'm getting farther from the solution.
filename = argv[1];
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("\n Unable to open input file.\n\n");
helpmssg();
exitmssg();
}
while (getc(fp) != EOF){
if (fscanf(fp,"%d", &c) == 1) {
arr[i] = c;
i++;
}
}
Ideally this should scan the file specified as a command line argument for a number, assign it to the first spot of the array, and repeat until the end of file. Any help is greatly appreciated.
Text file:
12
23
99
66
47
2
-111
8
Per request adding whole main function:
void main(int argc,char** argv) {
char* filename;
char* outputfile;
char conf;
int arr[1000] = {0};
int n,a=0,d=0,h=0,i=0,c=0;
welcome();
if (argc > 4 || argc < 3) {
printf("\n Invalid number of arguments.\n\n");
helpmssg();
exitmssg();
}
else if (argc == 4) {
for (int i=3;i<argc;i++) {
if (argv[i][0] == '-') {
for(int z=1;z<strlen(argv[i]);z++) {
if (argv[i][z] == 'a') {
a=1;
}
else if (argv[i][z] == 'd') {
d=1;
}
else if (argv[i][z] == 'h') {
h=1;
}
else {
printf("\n Invalid options in 3rd argument.\n\n");
helpmssg();
exitmssg();
}
}
}
else {
printf("\n 3rd argument shoule begin with '-'\n\n");
helpmssg();
exitmssg();
}
} }
filename = argv[1];
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("\n Unable to open input file.\n\n");
helpmssg();
exitmssg();
}
while ((c=getc(fp)) != EOF){
ungetc (c,fp);
if (fscanf(fp,"%d\n", &c) == 1) {
arr[i] = c;
i++;n++;
}
}
// int arr[] = {64, 34, 25, 12, 22, 11, 90};
sort(arr, n,d);
printf("Sorted array: \n");
printArray(arr, n);
outputfile = argv[2];
fp = fopen(outputfile, "r");
if (fp != NULL ) {
printf("\n Output file already exists, would you like to overwrite it?: Y/N \n\n");
scanf("%c", &conf);
if (conf == 'N' || conf == 'n') {
helpmssg();
exitmssg();
} else {printf(" Overwritting...\n\n");}
}
fclose(fp);
fp = fopen(outputfile, "w");
for (i=0; i < n; i++) {
fprintf(fp,"%d\n",arr[i]);
}
exitmssg();
}
You could do
for(i=0; i<size ; ++i)
{
if( fscanf(fp, "%d", &arr[i])!=1 )
{
printf("\nSomething went wrong.");
break;
}
}
where size is the number of numbers stored in the array.
Use fscanf() to read the integers in each line one by one. It returns the number of successful assignments which in this case should be 1 in each iteration of the loop.
In your program, you first use getc(), which reads one character, and then use fscanf() which reads only the rest.
Change while (getc(fp) != EOF) to while ((c = getc(fp)) != EOF).
Add ungetc (c, fp); below it in the loop and before the if statement.
Change if (fscanf(fp,"%d", &c) == 1) { to if (fscanf(fp,"%d\n", &c) == 1) {
The problem: Use a c program to read a MIPS instruction file, output it to a second file (both are command line arguments) which contains the contents of the MIPS file, with line numbers. The second half is supposed to display a cross reference table, which details the identifier, the definition(a number), and the usage of that identifier, by line number, for any identifier used more than once.
Unfortunately, I've run aground, and the program not only doesnt seem to actually print anything, but it doesnt seem to make any files either. This is a bit of a last ditch effort, to see if anyone else can help me out.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*Func line takes in a file, and places a line number at the beginning of every
non blank line */
void line(FILE *input, FILE *output) {
char a, c;
int lineNum = 0;
int startOfLine = 1;
char ch;
fprintf(output, "%d ", ++lineNum);
//copy the contents of the input file into the output file
do {
a = fgetc(input);
fputc(a, output);
c = getc(input);
if(a == '\n' && c != '\n') {
if(lineNum > 9)
fprintf(output, "%d ", ++lineNum);
else
fprintf(output, "%d ", ++lineNum);
}
ungetc(c, input);
} while (a != EOF);
printf("ran line: \n");
}
/* Func cross takes in a file, and finds each identifier, marks its definition, and every
use and returns that in the output file */
void cross(FILE *input, FILE *output) {
FILE *temp = fopen("temp.txt", "a+");
int lineNum = 0;
int startOfLine = 1;
char identifier[20][10];
char a, c, i;
int j, k, p;
int size=0;
int def[20];
int use[20][50];
char tempstr[80];
fprintf(output, "Identifier\tDefinition\t Use\n");
fprintf(temp, "%d ", ++lineNum);
//copy contents of input into a temp file
do {
a = fgetc(input);
fputc(a, temp);
c = getc(input);
if(a == '\n' && c != '\n') {
if(lineNum > 9)
fprintf(temp, "%d ", ++lineNum);
else
fprintf(temp, "%d ", ++lineNum);
}
ungetc(c, input);
} while (a != EOF);
fclose(temp);
fopen("temp.txt", "r");
j=0;
//checks to see if current line has an Identifier and if so saves it to an array
//along with the line number it was defined on
while(fgets(tempstr, 80, temp)) {
if(isalpha(tempstr[4]) || tempstr[4] == '_') {
sscanf(tempstr, "%d %[0-9_A-Z_a-z_]", &def[j], identifier[j]);
j++;
size++;
}
}
fclose(temp);
fopen("temp.txt", "r");
//checks for each identifier, on every line whether or not that identifier is used
while(fgets(tempstr, 80, temp)) {
char *tempNum;
sscanf(tempstr, "%s", tempNum);
int tempN = atoi(tempNum);
int n;
p=0;
for(n=0; n<size; n++) {
if(strstr(tempstr, identifier[n]) && tempN > def[n] && tempstr[4] != '#') {
use[n][p] = tempN;
p++;
}
}
}
//writes the identifier, definition, and uses to the file
for(k=0;k<size;k++) {
fprintf(output, "%s\t\t %d\t\t ", identifier[k], def[k]);
for(p=0; p<50; p++) {
if(use[k][p] != NULL && use[k][p] < lineNum && use[k][p] > def[k])
fprintf(output,"%d ", use[k][p]);
}
fprintf(output, "\n");
}
printf("ran cross: \n");
}
/*Func both returns the file with numbered lines and a cross reference table at the bottom of the file */
void both(FILE *input, FILE *output, char *outputName) {
FILE *lineFile = fopen("line.txt", "a+");
FILE *crossFile = fopen("cross.txt", "a+");
char ch;
line(input, lineFile);
cross(input, crossFile);
while( (ch = fgetc(lineFile)) != EOF)
fputc(ch, output);
fprintf(output, "\n\t\t\tCross Reference Table\n");
while( (ch = fgetc(crossFile)) != EOF)
fputc(ch, output);
fclose(output);
printf("ran both: \n");
}
int main(int argc, char * argv[]) {
FILE *input, *output;
output = fopen(argv[4], "a+");
char outputName[50];
strcpy(outputName, argv[4]);
//Error testing
if(argc > 5)
exit(1);
if(strcmp(argv[2], "-l") != 0 && strcmp(argv[2], "-c") != 0 && strcmp(argv[2], "-b") != 0) {
printf("Incorrect flag syntax... Exiting\n");
exit(1);
}
if((input = fopen(argv[3], "r+")) == NULL) {
printf("Input file could not be opened... Exiting\n");
exit(1);
}
else {
if(strcmp(argv[2], "-l") == 0) {
line(input, output);
}
else if(strcmp(argv[2], "-c") == 0)
cross(input, output);
else {
both(input, output, outputName);
}
}
printf("ran main: \n");
return 0;
}
I have problem with getNumber function, because my output_file contains zeros. And in my opinion it should not. I want my program to print all numbers and then add them up.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getNumber(FILE *infile);
int main(int argc, char *argv[])
{
char *number, *pEnd;
FILE *infile, *outfile;
int newNumber, sum = 0;
if(argc != 3)
{
printf("Missing argument!\n");
exit(1);
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error, cannot open the outfile!\n");
abort();
}
else
{
while(!feof(infile))
{
number = getNumber(infile);
if(number == NULL)
{
free(number);
abort();
}
newNumber = strtol(number, &pEnd, 10);
sum += newNumber;
if(!*pEnd)
printf("Converted successfully!\n");
else printf("Conversion error, non-convertible part: %s", pEnd);
fprintf(outfile, "%d\n", newNumber);
free(number);
}
fprintf(outfile, "\nSum: %d\n", sum);
}
}
else
{
printf("Error, cannot open the infile!\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getNumber(FILE *infile)
{
char *number, *number2;
int length, cursor = 0, c;dwwd
number = (char*)malloc(sizeof(char)*CHUNK);
if(number == NULL)
{
printf("Error!\n");
return NULL;
}
length = CHUNK;
while(!isspace(c = getc(infile)) && !feof(infile))
{
if(isdigit(c))
{
number[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
number2 = (char*)realloc(number, cursor);
if(number2 == NULL)
{
free(number);
return NULL;
}
else number = number2;
}
}
}
number[cursor] = '\0';
return number;
}
I would be really grateful for any help.
I am also sending two files, input_file and output_file:
Your condition here:
while(!isspace(c = getc(infile)) && !feof(infile))
Breaks every time you encounter space. After that you will always print the number. That means that for every interval(also for the end of the file) that is not preceded directly with digit you will print one extra zero in the output file.
Maybe add one flag whether you entered the while at least once. If you have not - just do not print anything.
You have to add else statement to your if(isdigit(c)) to break the loop when a non digit character is found after having found a digit previously.
if(isdigit(c))
{
// your existing code
}
else if (cursor != 0)
{
break;
}
Hope this helps.
EDIT:
Just replace
fprintf(outfile, "%d\n", newNumber);
with
if(0 != newNumber) fprintf(outfile, "%d\n", newNumber);
From the strtol c library manpage:
If there were no digits at all, strtol() stores
the original value of nptr in *endptr (and returns 0)
You always assign to newNumber and don't check for the case where strtol doesn't actually return a converted number but a instead returns a 0 because it couldn't find a number. That's why you have all the zeroes in your output file.
I'm having some problems trying to run this program I am working on...The requirements say I was not allowed to use a sort function...I had do something myself....etc.
Pretty much, the program compiles but hangs after executed...I'm guessing it's stuck in an infinite loop...but I can't seem to find it... :(
This program reads to data files that will already be ordered least to greatest and merges them (ordered) into a third .txt file...
The two files are Data1.txt and Data2.txt
contains:
Data1.txt
2
2
2
2
Data2.txt
1
3
5
7
9
combine.c
#include <stdio.h>
#include <stdlib.h>
void sortData(FILE *fpData1, FILE *fpData2)
{
int n, m;
FILE *fpMerge;
fpMerge = fopen("Merge.txt", "w+");
fscanf(fpData2, "%i", &n);
fscanf(fpData1, "%i", &m);
while(n != EOF || m != EOF)
{
if(n == EOF)
{
fscanf(fpData1, "%i", &m);
while(m != EOF)
{
fprintf(fpMerge, "%i\n", m);
fscanf(fpData1, "%i", &m);
}
}
if(m == EOF)
{
fscanf(fpData2, "%i", &n);
while(n != EOF)
{
fprintf(fpMerge, "%i\n", n);
fscanf(fpData2, "%i", &n);
}
}
if(n < m)
{
fprintf(fpMerge, "%i\n", n);
fscanf(fpData2, "%i", &n);
}
if(n > m)
{
fprintf(fpMerge, "%i\n", m);
fscanf(fpData1, "%i", &m);
}
if(n == m)
{
fprintf(fpMerge, "%i\n", n);
fprintf(fpMerge, "%i\n", m);
fscanf(fpData2, "%i", &n);
fscanf(fpData1, "%i", &m);
}
}
fclose(fpMerge);
}
int main (void)
{
FILE *fpData1;
FILE *fpData2;
fpData1 = fopen("Data1.txt", "r");
if(fpData1 == NULL)
{
printf("There was an error opening the file...program terminating..\n");
exit(1);
}
fpData2 = fopen("Data2.txt", "r");
if(fpData2 == NULL)
{
printf("There was an error opening the file...program terminating..\n");
exit(1);
}
sortData(fpData1, fpData2);
fclose(fpData1);
fclose(fpData2);
return 0;
}
You don't want to compare n != EOF, but rather the return value of fscanf:
int count_1;
count_1 = fscanf(fpData1, "%i", &m);
if (count_1 == EOF) // EOF (or error)
{
// ...
}
fscanf will also return EOF on error. If you need to tell EOF and error conditions apart, use ferror(fpData1), say, and then look up the error code (stored in errno).
Your testing of EOF is not quite correct
void sortData(FILE *fpData1, FILE *fpData2)
{
int data1;
int data2;
FILE *fpMerge;
fpMerge = fopen("Merge.txt", "w+");
fscanf(fpData1, "%i", &data1);
fscanf(fpData2, "%i", &data2);
// While one file still has data
while(!feof(fpData1) && !feof(fpData2))
{
// Choose 1 file to test
// Read from that file and put into merge file until either we
// run out of data or the condition fails.
if(data1 < data2)
{
do {fprintf(fpMerge, "%i\n", data1);}
while ((fscanf(fpData1, "%i", &data1) != 0) && (data1 <= data2));
}
else
{
do {fprintf(fpMerge, "%i\n", data2);}
while ((fscanf(fpData2, "%i", &data2) != 0) && (data2 <= data1));
}
// NOTE: if fscanf() returns 0 it has failed to read (EOF)
}
// One of the files has reached the EOF
// Dump the other file.
while(fscanf(fpData1, "%i", &data1) != 0) {fprintf(fpMerge, "%i\n", data1);}
while(fscanf(fpData2, "%i", &data2) != 0) {fprintf(fpMerge, "%i\n", data2);}
}
EOF is not a character.
EOF is not an integer.
No files will ever have EOF (neither char nor int) in them.
EOF is a condition.
Files will either be on that condition or (usually) not.
You should check the return value of fscanf() to detect EOF or other problems.