File handling program not working as expected in C - c

FILE *mails;
FILE *tempmails;
mails = fopen("mailer.txt", "r");
tempmails = fopen ("tempmailer.txt" , "a+");
char line[200],templine[200];
char blnklne[]="\n";
while(fgets(line, sizeof line, mails) != NULL)
{
int flag=0;
while(fgets(templine, sizeof line, tempmails) != NULL)
{
if((strcmp(line,templine)==0) || (strcmp(line,blnklne)==0))
{
flag = 1;
}
}
if(flag == 0)
{
fputs(line, tempmails);
}
}
fclose(mails);
fclose(tempmails);
tempmails = fopen ("tempmailer.txt", "r");
remove("mailer.txt");
FILE *newmails;
newmails = fopen("mailer.txt", "a");
while(fgets(templine, sizeof line, tempmails) != NULL)
{
fputs(templine, newmails);
}
fclose(newmails);
fclose(tempmails);
remove("tempmailer.txt");
I have written the above C code for the following purposes:
Have to read each line from mailer.txt and check if a line is blank or repeated and if both conditions are false have to enter it to a temp file tempmailer.txt
Remove the file mailer.txt and then create a new one and copy enter it into the new file one by one and then remove tempmailer.txt.
But on running what actually happens is:
Copies from mailer.txt to tempmailer.txt ALL the lines irrespective of any conditions given(undesired)
Deletes mailer.txt and creates a new mailer.txt(desired)
Copies from tempmailer.txt to the new file as such(desired)
Deletes tempmailer.txt(desired)
Whatever I do, I can't erradicate this problem. The OS is linux. Please help me. Thanks in advance.

Reset tempmails to the beginning of the file before starting each 2nd loop.
while(fgets(line, sizeof line, mails) != NULL)
{
int flag=0;
rewind(tempmails); /* go back to the begining */
while(fgets(templine, sizeof line, tempmails) != NULL)
{
/* ... */
}
}

You need to seek to the beginning of the file before the second while loop.
As it stands, your second while loop will never find any matching lines because it will always be pointed to the end of the file.

The repeat-detection code is very strange, it's reading from both files at the same time. You can't read from a file opened for append. Try mode a+.
This is solvable with a trivial shell script, do you really have to write it in C?

Maybe this part of code is the reason why you got your question 1
while(fgets(line, sizeof line, mails) != NULL)
{
int flag=0;
while(fgets(templine, sizeof line, tempmails) != NULL)
{
if((strcmp(line,templine)==0) || (strcmp(line,blnklne)==0))
{
flag = 1; /* this part may be not correct */
}
}
if(flag == 0)
{
fputs(line, tempmails);
}
}
If the program finds a line that makes if condition true, then the flag is set to 1, but next line maybe not make if condition true, and you program can not set the flag to 0.So you will never put the mismatch lines which are after the the matched line into the tempmails.

Disclaimer: This is not really an answer, but can definitely aid in debugging!
After the following lines, you should check if the pointers are NULL or not:
mails = fopen("mailer.txt", "r");
tempmails = fopen ("tempmailer.txt" , "a+");
if (mails == NULL) printf("Error: could not open file");
if (tempmails == NULL) printf("Error: could not open file");
Now you can at least know if it can open and read the files. To check whether fgets works, and isn't giving you errors, use ferror or feof.
You should add the same NULL checks for every time you call fopen on a FILE handle.

Related

C - Parse file and write to separate files based on the last field

The software intends to read from a csv styled file (it's delimited by space not by a comma) and split the initial file into two new ones. The two files are determined by the last field, which is a binary value. As it stands, it currently reads the file character by character. I want it to recognize the space, and only run the individual character check on the very last field. To my understanding, strtok() will come in handy, but I'm struggling to find a way to incorporate that into the existing software.
Any help would be greatly appreciated :)
/*
* C program to parse a file, and split it into two based on the final line of input
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Function declarations */
int isMale(signed char _line);
int isFemale(signed char _line);
int isMale(signed char _line)
{
}
int isFemale(signed char _line)
{
}
int main()
{
/* File pointer to hold reference to different files */
FILE * fPtrIn, // Input file
* fPtrMale, // Males of school age
* fPtrFemale, // Females of school age
* fPtrMisc; // Data not within the given parameters
// current_char is the current character being read
// success stores the read status
char current_char;
int success;
// Open all files to perform read/write.
fPtrIn = fopen("data/example.txt", "r");
fPtrMale = fopen("data/males.txt" , "w");
fPtrFemale = fopen("data/females.txt" , "w");
fPtrMisc = fopen("data/erroneus.txt", "w");
// fopen() return NULL if unable to open file in given mode.
if(fPtrIn == NULL || fPtrMale == NULL || fPtrFemale == NULL || fPtrMisc == NULL)
{
// Unable to open file, exit software
printf("Unable to open file.\n");
printf("Please check whether file exists and you have read/write privilege.\n");
exit(EXIT_FAILURE);
}
// File open success message
printf("File opened successfully. \n\n");
// Read an integer and store read status in success.
while (fscanf(fPtrIn, "%d", &current_char) != -1)
{
// Write each one to separate file
if (isMale(current_char))
fprintf(fPtMale, "%d\n", current_char);
else if (isFemale(current_char))
fprintf(fPtrFemale, "%d\n", current_char);
else
fprintf(fPtrMisc, "%d\n", current_char);
}
// Done with all files, hence close all.
fclose(fPtrIn);
fclose(fPtrMale);
fclose(fPtrFemale);
fclose(fPtrMisc);
printf("Data written to files successfully.");
return 0;
}
You should
Read lines via fgets()
Copy the line read because strtok() will modify original buffer.
parse fields via strtok()
Judge and output according to the parsed field.
// hoping that too long lines won't come
char line[102400], line_parse[102400];
// Read an integer and store read status in success.
while (fgets(line, sizeof(line), fPtrIn) != NULL)
{
char *last_field, *ret;
// Copy the line for parsing
strcpy(line_parse, line);
// Separate the line into tokens
last_field = ret = strtok(line_parse, " ");
while (ret != NULL)
{
last_field = ret;
ret = strtok(NULL, " ");
}
// Get the first character of the last field
if (last_field == NULL) current_char = '\0'; else current_char = last_field[0];
// Write each one to separate file
if (isMale(current_char))
fputs(line, fPtrMale);
else if (isFemale(current_char))
fputs(line, fPtrFemale);
else
fputs(line, fPtrMisc);
}

C - fgets skips CR character

I have a c code, simply reads a line from a txt file. The file has only one line which is as below:
The code snippet to read this line is:
int** readFile(char* filename){
int col=0, row =0;
int i=0;
int* numList[2048];
for(int i = 0; i<2048; i++)
numList[i] = (int*) malloc(6*sizeof(int));
if(NULL == numList){
printf("Memory error!");
}
char * token = NULL;
char currentLine[25] = {'\0'};
FILE* file = fopen(filename, "r");
if(NULL != file){
printf("File is opened successfully\n");
if( NULL != fgets (currentLine, 60, file) )
{
int i = 0;
while (NULL != currentLine[i]){
printf("%d ", currentLine[i]);
i++;
}
}
}
else
{
printf("File I/O Error");
return NULL;
}
fclose(file);
return numList;
}
When this code runs, I get the following output:
I observed something suspicious, which is, as you can see in the first screenshot (Content of txt file), Notepad++ shows CR LF at the end of the line. But in the output, I see 10 as the last character which is LF.
Probably I am missing a very primitive point but, I couldn't understand why CR character is not there.
Needless to say, platform is windows and this is a console program.
Thanks&Regards.
You're opening the file in text mode. This mode ensures you can handle text files the same on any platform.
C specifies '\n' as the end of line. In Windows, the end of line is the sequence "\r\n". C (in this case, the standard library implementing stdio) will automatically translate this for you. Reading from a file on Windows in text mode will give you just \n for \r\n.
If you want to see exactly the byte contents of the file, you have to open it in binary mode instead:
FILE* file = fopen(filename, "rb");

C - Why is fp == NULL true after fopen(filename, "r")?

I am trying to read the number of lines of a file in Ubuntu. For my code I'm using CodeBlocks.
This is the code I've made.
int countlines()
{
// count the number of lines in the file called filename
FILE *fp = fopen("words", "r");
int ch=0;
int lines=0;
if (fp == NULL){
return 0;
}
lines++;
while(!feof(fp))
{
ch = fgetc(fp);
if(ch == '\n')
{
lines++;
}
}
fclose(fp);
return lines;
}
If I call countlines(), the return value is a 0, that is because he checks if fp==NULL, and that is true.
I placed words in the same folder as my main. The executable file is in Projectfolder/bin/Debug.
Words looks like this:
"albatros",
"olifant",
"kantklos",
"robijn",
"internet"
The final goal is to fill an array with the words of the file words, without using #include "words".
Check what the working directory is set to. It might not be pjt/bin/Debug. Also, try specifying full path to the file.
if (fp == NULL){
return 0;
}
fp is checked with NULL, because, fopen returns pointer, if it succeed, it will be non-NULL, so if fp == NULL, then file open does not succeed. That's why program cannot proceed, and just return.
Hmmm!!! It could have been the fact that the file extension for "words" was not specified. Otherwise, I couldn't find anything else wrong with the program.

fgets doesn't move file pointer

I have a question which maybe fairly simple. I have a file input.txt which is:
cat input.txt
testsuite1
test1
summary information of test
FAIL
testsuite2
test1
summary info ya
PASS
I am writing a program just to read each of these strings into variables and do further processing. What is the best way to do it? I am currently doing:
main() {
FILE *fp;
char testsuite[100],testname[100],summary[100],result[100];
fp = fopen("input.txt", "r");
while(1) {
if(fgets(testsuite,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(testname,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(summary,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(result,99,fp) == NULL)
{
ferror(fp);
break;
}
printf("testsuite: %s testname:%s summary:%s result:%s \n",testsuite,testname,summary,result);
}
fclose(fp);
}
Is there a better way to do it? The problem I am currently facing is that, if input.txt contains even one blank line, the blank like is read into a variable. Whats the best way to avoid it?
Thanks!
You should write your own function that skips empty lines (e.g. called getline()) and use it instead of fgets():
char *getline(char *buf, int size, FILE *fp)
{
char *result;
do {
result = fgets(buf, size, fp);
} while( result != NULL && buf[0] == '\n' );
return result;
}
You could now refine that function to also skip lines that consist of blanks only or whatever you need.
You can remove all blank lines of your files before your loop while.
After the open you parse the whole file and remove the blank ;).
But it don't seems like the best way to do it.
Overwise you can check after each fget if your variables are empty, and in this case, fget again.
Hope that will be helpfull.
If you do this, you will not be able to use the strings you read once loop quits, since each loop overwrites each string in the buffer. However, you could store your strings in a struct array:
typedef struct {
testsuite[100];
testname[100];
summary[100];
result[100];
}test;
test test_array[2];
int main(){
int iIndex=0;
FILE* fpPtr=NULL;
fpPtr = fopen("input.txt", "r");
if(fpPtr==NULL){ //<--- it is very important to check if fopen fails
perror("fopen");
}
for(iIndex=0; iIndex<2; iIndex++){ // 2 because it is the number of elements in test_array
if(fgets(test_array[i].testsuite,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].testname,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].summary,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].result,99,fp) == NULL)
{
ferror(fp);
break;
}
}
}
You can detect blank lines by checking for a newline character at position 0:
fgets(cBuffer, sizeof(cBuffer), fpPtr);
//<-- if the file was created on windows, check for '\r' instead, since a new line in windows is \r\n
if(cBuffer[0]=='\n')
{
printf("blank line"\n);
}

fclose causing exc_bad_access

I can't figure out why this fclose() in my c program is causing bad access. It was working fine and then I changed the if condition to only print when the strings do not equal eachother and suddenly it started causing problems. apart from the bad access error, it is also not printing anything to "newfile.txt"
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main()
{
FILE * cFile;
FILE *outputfile;
FILE *newfile;
cFile = fopen("input.in", "r");
if (cFile == NULL){
printf("bad input file");
}
newfile = fopen("newfile.txt", "w+");
if (newfile == NULL){
printf("bad newfile");
}
char tempstring[15];
char tempstring2[15];
//get each line in the cFile
while (fscanf(cFile, "%15s", tempstring) != EOF) {
outputfile = fopen("outputlotnum.txt", "r"); //open/(or reopen) outputfile to check lines
if (outputfile == NULL){
printf("bad outputfile");
}
//get each line in the outputfile
while(fscanf(outputfile, "%15s", tempstring2) != EOF){
//if the line from cFile doesn't match the line from outputfile,
//then go ahead and print the line to the newfile.txt
if (strcmp(tempstring, tempstring2) != 0){
fprintf(newfile,"%15s \n", tempstring2);
}
//else don't print anything and continue on to the next line
}
fclose(outputfile); //close the outputfile after checking all the lines for a match
}
fclose(newfile); //throws bad access
fclose(cFile);
return 0;
}
Some reasons for library functions seg faulting include passing bad parameters into the function or that you have a memory scribbler. I suspect that in your case you have overflowed one or both temp string arrays on the stack and have corrupted the file handles. It's generally not a safe operation to fscanf/scanf into a buffer unless you can guarantee that the string you read will fit into that buffer.
To confirm this you could print out the file handles immediately after open, and again before close. They should be the same. If they are not then you have accidentally overwritten them.

Resources