Saving unwanted data to an error file - c

Hi I currently have a piece of code that grabs names from a file and then saves it to another.
However I would now like to save any invalid information to a fixed error file and was wondering how I'd go about it
My code:
Struct:
struct Person{
char fName[16]; //string to store the persons first name
char lName[21]; //string to store the persons last name
};
Main
int main(){
int recordCount = 0; //used to keep track of the number of records currently in memory
struct Person *records;
records = malloc(sizeof(struct Person));
records = open(&recordCount, records);
records = addRecord(&recordCount, records);
save(recordCount, records);
return 0; //End the program and return 0 to the operating system
}
open(&recordCount, records) function:
struct Person* open(int *rCount, struct Person *records){
FILE *recordFile;
char fileName[30] = {'\0'};
int i = *rCount;
char test;
puts("Enter a filename to open :");
scanf("%s", fileName);
if((recordFile = fopen(fileName,"r"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
exit(1);
}
else{
test = fscanf(recordFile,"%s %s", records[i].fName,records[i].lName);
while(test!= EOF){
i++;
records = realloc(records,(i+1)*sizeof(struct Person));
test = fscanf(recordFile,"%s %s", records[i].fName,records[i].lName);
}
fclose(recordFile); // close the file
}
*rCount = i;
return records; //add i (records read from the file) to rCount (the current record count)
}
addRecord(&recordCount, records) function
struct Person* addRecord(int* rCount, struct Person *records){
int valid = 0; //used to indicated valid input
int length = 0; //used to store the string lengths
int i = 0; //used in the for loops
char fNameTest[16]; //temporary storage of input to be checked before adding to records
char lNameTest[21]; //temporary storage of input to be checked before adding to records
//Checking the length of data input for fName
do{
length = strlen(fNameTest);
if(length < 16){
for(i=0;i<=length;i++)
records[*rCount].fName[i] = fNameTest[i]; //if correct insert the record at the index determined by rCount
valid=1;
}
else{
valid = 0;
}
}while(valid!=1);
//Checking the length of data input for lName
do{
length = strlen(lNameTest);
if(length < 21){
for(i=0;i<=length;i++)
records[*rCount].lName[i] = lNameTest[i]; //if correct insert the record at the index determined by rCount
valid=1;
(*rCount)++; //At this point ID,fName and lName have been stored so increment rCount
}
else{
valid = 0;
}
}while(valid!=1);
records = realloc(records,((*rCount)+1)*sizeof(struct Person));
return records; //return rCount as the new updated recordCount
}
save(recordCount, records) function
void save(int rCount, struct Person *records){
FILE *recordFile; //file handle
char fileName[30] = { '\0'}; //string to store the file name
int i;
puts("Enter a filename to save the records :"); //ask the user for the filename
scanf("%s", fileName); //store the filename: data input should be checked
//here in your program
//try and open the file for writing and react accordingly if there is a problem
if((recordFile = fopen(fileName,"w"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
}
else{ //the file opened so print the records array of Person's to it
for(i=0;i<rCount;i++){
fprintf(recordFile,"%s %s\n",records[i].fName,records[i].lName);
}
fclose(recordFile); //close the file
printf("Records saved to file: %s\n",fileName);
}
}
I was thinking of removing the do-while loops in the addRecords function and replacing them with if statements. And then finally an if statement to check the value of valid. And then if valid=0 point to a function or save the errorfile directly there.
However I am unsure if this is the best way to go (or if my thought process would even work) and wondered if anyone could help.
Edit: Decided to add the type of data I'm dealing with incase anyone wants to create a .txt and run the program
Bob Jones
Franklin Davies
James Donut
EDIT Following the answer below I have updated my code (edited segments below)
EDITED saveFunction
void save(int rCount, struct Person *records){
FILE *recordFile; //file handle
char fileName[30] = { '\0'}; //string to store the file name
int i;
puts("Enter a filename to save the records :"); //ask the user for the filename
scanf("%s", fileName); //store the filename: data input should be checked
//here in your program
//try and open the file for writing and react accordingly if there is a problem
if((recordFile = fopen(fileName,"w"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
}
else{ //the file opened so print the records array of Person's to it
char fileName[sizeof (struct Person) * 2]; // twice needed size
while (fgets(fileName, sizeof fileName, recordFile) != NULL) {
struct Person P;
int n; // Save index where scanning stopped
int cnt = sscanf(fileName,"%15s%21s %n", P.fName, P.lName, &n);
if (cnt != 2 || fileName[n]) {
errorLine(fileName);
// do not increment i;
} else {
// Good to keep
// realloc memory as needed here
records[i] = P;
i++;
}
}
errorLine function:
void errorLine(char *fileName)
{
FILE *errorFile;
//try and open the file for writing and react accordingly if there is a problem
if((errorFile = fopen("error.txt","w"))==NULL){
printf("Couldn't open the file:\n");
}
else{ //the file opened so print the records array of Person's to it
for(i=0;i<rCount;i++){
fprintf(errorFile,"%i %s %s\n",records[i].fName,records[i].lName);
}
fclose(errorFile); //close the file
printf("Records saved to file: %s\n",fileName);
}
}
No doubt I probably implemented the answer incorrectly and now get an error:
error: expected declaration or statement at end of input
Which is found on my last line of the program

Need to limit length of input before attempting to save in structure.
else {
char buffer[sizeof (struct Person) * 2]; // twice needed size
while (fgets(buffer, sizeof buffer, recordFile) != NULL) {
struct Person P;
int n; // Save index where scanning stopped
int cnt = sscanf(buffer,"%15s%21s %n", P.fName, P.lName, &n);
if (cnt != 2 || buffer[n] || MaybeAddtionalTests(&P)) {
SaveBadLine(buffer);
// do not increment i;
} else {
// Good to keep
// realloc memory as needed here
records[i] = P;
i++;
}
}
fclose(recordFile); // close the file

Related

How do I read properly from a binary file?

I already cut my code to minimum and I think that is everything I need for my problem.
I want the user to be able to read this structure:
typedef struct {
char movieTitle[30];
unsigned int yearPublished;
char director[50];
char genre[50];
float profit;
} movie_t;
from a binary file that has already 4 movies in it, but should also be able to store max 100 movie structures like defined here:
//global var.
// ================================================================
#define MAX_STORAGE 100
movie_t movieData[MAX_STORAGE];
movie_t movieRecord;
unsigned int movieCount = 0;
With my code that I already wrote below, I can't somehow read all movies out of the file, because my "count checker" tells me every-time that just one movie was read. Also just one movie is showing in my console output code below my "readFile" function.
// main functions --- read from file
// ================================================================
int
readFile(const char* fileName)
{
//open file
FILE* read = fopen(fileName, "rb");
if (!read)
{
printf("ERROR: Could not open the file!\n");
return -1;
}
else
{
printf("%s were opened successfully.\n\n", fileName);
}
//read from file
int count = 0;
while (!feof(read))
{
size_t count = fread(&movieRecord, sizeof(movieRecord), 1, read);
if (count == 0)
{
printf("ERROR: Read process was unsuccessful or incomplete!\n");
}
if (count == 1)
{
printf("Successfully read %i movie.\n", count);
}
else
{
printf("Successfully read %i movies.\n", count);
}
return count;
}
fclose(read);
return 0;
}
This is the console output where ALL movies from the file should be showing up. Also they should be showing with a number (Num.) from 1 - 100.
// main functions --- console Output
// ================================================================
void
consoleOutput(movie_t movieData2, unsigned index)
{
printf("MOVIE DATA Num. %u\n\n", index);
printf("Movie title : %s\n", movieData2.movieTitle);
printf("Publishing year : %u\n", movieData2.yearPublished);
printf("Director : %s\n", movieData2.director);
printf("Genre : %s\n", movieData2.genre);
printf("Profit : %.2f\n", movieData2.profit);
}
This is how my main function looks like if you would like to see it:
// MAIN
// ================================================================
int main(void)
{
// defaultname for file
char fileName[50] = "movies.dat";
// variable for loop
int stopLoop = 0;
// loop
do {
// Output menu
printf("\nMENU:\n");
printf("(a) Show all movies\n");
printf("(o) Read moviefile\n");
printf("(q) Exit programm\n");
printf("\nYour choice: ");
// User input
char ch = _getch();
printf("%c\n\n", ch);
// Switch case for user input
switch (ch)
{
case 'q': // Exit programm
stopLoop = 1;
break;
case 'a': // Show all movies
consoleOutput(movieRecord, movieCount = readFile(fileName));
break;
case 'o': // Read moviefile
readFile(fileName);
break;
default:
printf("==> Invalid input!\n");
}
} while (!stopLoop);
return 0;
}
Side-note: because the user is able to input new movies, they should be able to save that data to the same file from where they read it. But that's something I want to test myself first, before I ask around for help.
You are returning from your loop body after reading only one entry. If you really wish to read all the entries in the file, you'll need to change your reading loop to reading into your array, which you can in fact get rid of all together thanks to how fread works:
// main functions --- read from file
// ================================================================
int
readFile(const char* fileName)
{
//open file
FILE* read = fopen(fileName, "rb");
if (!read)
{
printf("ERROR: Could not open the file!\n");
return 0; // note that since you'll probably assign the output to movieCount, it might be better to return 0 on failure
}
else
{
printf("%s were opened successfully.\n\n", fileName);
}
// Here's where the problem, you only ever read out one movie entry into movieRecord and returned
// You can use fread to read out the entire file into the array instead
// It would also be better not to use a global variable for this, instead taking in a pointer to an movie_t array to readFile instead but I left it using the global as per the original program
size_t count = fread(movieData, sizeof(movie_t), MAX_STORAGE, read);
if (ferror(read))
{
printf("ERROR: Read process was unsuccessful or incomplete!\n");
fclose(read);
return 0;
}
if (count == 1)
{
printf("Successfully read %i movie.\n", count);
}
else
{
printf("Successfully read %i movies.\n", count);
}
fclose(read);
return count;
}
From here, you'll have movieData populated with the data from your file and should adjust the rest of your program accordingly.

Is it possible to copy a searched string from one file and print into another?

The following function is only used to display certain areas of a file. In this case I am trying to copy every line that has the word "EMPTY" from the main file to another file. Other than by opening a file to write to I use for char arrays to look for the proper string needed. At this point, I try to use the data from that file(In which the string was searched for) and try to copy it into another file. At this point some of the new file prints to the screen which is the first part at the top under where I created the file but when I try to add the string from the other file they do no print. Can you print certain string fro one file to another?
void emptySeats(void)
{
int position = 0;
int AvalabileOne = 0;
int countGone = 0;
int confirm = 0;
char testOne[] = "EMPTY";
char StrOne[10], StrTwo[10], StrThree[10], StrFour[10];
FILE *fEmptyseatArrangement;
fEmptyseatArrangement = fopen("airlineEmptySeatingArrangment.txt", "w+");
fprintf(fseatArrangement, "\t\t\tEcono-Airlines Passangers System\n\n\t Seat Number\t Seatavalability Last Name First Name\n");
do
{
fseatArrangement = fopen("airlineSeatingArrangment.txt", "r");
fseek(fseatArrangement, 102, SEEK_SET);
while (AvalabileOne < FULL)
{
fscanf(fseatArrangement, "%s%s%s%s\n", &StrOne, &StrTwo, &StrThree, &StrFour);
if (strcmp(StrThree, testOne))
{
fprintf(fEmptyseatArrangement, "\t\t%s\t\t%s\t\t%s\t\t%s\n", StrOne, StrTwo, StrThree, StrFour);
countGone = countGone + 1;
}
AvalabileOne = AvalabileOne + 1;
}
fclose(fEmptyseatArrangement);
fclose(fseatArrangement);
fEmptyseatArrangement = fopen("airlineEmptySeatingArrangment.txt", "r");
while (fgets(econoAirEmptySeatArrangement, 1000, fEmptyseatArrangement) != NULL)
printf("%s", econoAirEmptySeatArrangement);
fclose(fEmptyseatArrangement);
printf("There are %d seats vacant at the moment\n", FULL - countGone);
printf("Enter Zero(0) Key to return to menu at anytime.");
scanf(" %d", &position);
if (position == 0)
{
system("cls");
menu();
}
else
{
system("cls");
printf("INVALID INPUT! Please try again.\n");
}
} while (AvalabileOne != 0);
system("pause");
return;
}

File being read, but not saved

I am currently writing a program to read a file and then save the information read to a new file. However when writing the second file no data is saved.
I am using a struct to help break up the text file that I want to use
struct file{
int source;
int destination;
int type;
int port;
char data[50];
};
After reading the file I have created a function to break up the data and print it to the screen
int parseFile(int countData, struct file *storedData)
{
FILE *in_File;
char buff[1000];
while(fgets(buff, 1000, in_File)!=NULL)
{
printf("%s", buff);
storedData[countData].source = atoi(strtok(buff, ":"));
storedData[countData].destination = atoi(strtok(0, ":"));
storedData[countData].type = atoi(strtok(0, ":"));
storedData[countData].port = atoi(strtok(0, ":"));
strcpy(storedData[countData].data, strtok(0, ":\n") );
}
}
and finally I created a function to save the file
void saveFile(int countData, struct file *storedData)
{
FILE *in_File;
char fileLocation[40];
int i = 0;
printf("\nEnter a File Name to save:");
scanf("%s", fileLocation);
if ((in_File = fopen(fileLocation, "w")) == NULL){
puts(" \n Could not point to the file.");
}else{
for(i=0;i<countData;i++)
{
fprintf(in_File, "%04d:%04d:%04d:%04d:%s \n",
storedData[i].source,
storedData[i].destination,
storedData[i].type,
storedData[i].port,
storedData[i].data );
}
}
fclose(in_File);
}
In the main function I used malloc to allocate the size of the struct
int main()
{
struct file *storedData;
storedData = malloc(sizeof(struct file));
int countData = 0;
banner();
readFile(countData, storedData);
parseFile(countData, storedData);
saveFile(countData, storedData);
return 0;
}
When getting the data and running it through my parseFile function each line is written out to me line by line
Example of data output:
0001:0002:0003:0021:CLS
0003:0004:0002:0180:100000000000000000030
0006:0003:0002:0041:100000000000000000019
0006:0002:0002:0060:100000000000000000020
However when saved to a file none of this output is stored and I was wondering what I could do to fix it
EDIT:
Here is the readFile function:
void readFile(int countData, struct file *storedData)
{
FILE *in_File;
char fileLocation[40];
printf("\nEnter file name: \n");
scanf("%s", fileLocation);
in_File = fopen(fileLocation, "r");
if(!in_File)
{
printf("\nError!\n");
}
}
storedData = malloc(sizeof(struct file));
Allocates enough for ONE file record.
Your routine parseFile() would write over that record repeatedly, but as it never increments countData it doesn't write any -- although even if it did, the parent routines would not receive your updated countData, as you would have had to pass an int * of &countData to let the parseFile() routine increment it.
Since for(i=0;i<countData;i++) is present, you never even read a single line, since 0 < 0 is false.
If you make that change, as soon as you hit the second record, you will overwrite memory and coredump because you only allocated one record worth of space in main()
Also in parseFile(), you have to open the file before reading it! Something like:
in_File = fopen(inputFileName, "r");
[edit] I see you updated with readFile() -- it needs to return the open FILE * for use by parseFile, and you will need to pass that FILE * to parseFile to use.

How to store data from files to an array in C

So, basically this code below need the user to login first, then after the user login it will show the user details like the one stored in the user.txt. after that i dunno how to retrieve back the files from the files then return it as an array, so that i can update e.g change the name of the user, or delete the user details by taking the array index
here is my code
#include <stdio.h>
#include <string.h>
typedef struct {
char fullname[30];
char dob [10];
int contactNo;
int postcode;
}userDetails;
int main ()
{
char username [15];
char pwd [20];
char user_pass [30];
char userfile [100];
FILE *user;
FILE *admin;
userDetails myUser;
admin = fopen ("admin.txt","r");
printf("Please enter your Username\n");
scanf("%s",username);
printf("Please enter your Password\n");
scanf("%s",pwd);
user_pass[strlen(username) + strlen(pwd) + 2];
sprintf(user_pass, "%s;%s", username, pwd);
while (fgets(userfile, 100, admin) != NULL) {
if (strcmp(userfile, user_pass) == 0) {
printf("Authentication as %s successful\n", username);
size_t nread; // Printing the user information
user = fopen("user.txt", "r");
printf("\nHere is the registered user:\n");
if (user) {
while ((nread = fread(myUser.fullname, 1, sizeof myUser.fullname, user)) > 0)
fwrite(myUser.fullname, 1, nread, stdout);
if (ferror(user)) {
}
fclose(user);
}
}
else{
printf("Please enter correct username and password\n");
}
}
}
and let say in the user.txt the file is stored in a format like this
john;12/12/1990;+6017012682;57115
paul;12/12/1221;+60190002122;100022
max;12/11/1990;+60198454430;900000
jamie;12/05/2000;+60190001231;18000
Thank you
how do you read a data from a files and store it to an array, then read specific stored data in the array to be edited?
Steps to store data:
1) - Declare the type(s) of storage variables needed to support your concept. Array of struct perhaps.
2) - Open file ( FILE *fp = fopen("file path", "r"); )
3) - Loop on fgets() to read each line (record) of file
4) - Parse lines, perhaps using strtok and place elements of each line into storage variable you created above.
5) - close file ( fclose(fp); )
The get record part can be done by selecting a record, and returning a re-concatenated string composed of each field of the original record. The prototype could look like this:
void GetRecord(RECORD *pRec, int rec, char *recordStr);
Where storage would be created as an array of struct, and the struct would accommodate the 4 fields you cited, eg:
John;12/12/1990;+6017012682;57115 //example record with 4 fields
#define MAX_RECORDS 10 //arbitrary value, change as needed
typdef struct {
char name[260];
char date[11];
char num1;
char num2;
} RECORD;
RECORD record[MAX_RECORDS];//change size to what you need, 10 is arbitrary for illustration
Code Example to read data into records , and retrieve a record, could look like this:
(example only, very little error checking)
void GetRecord(RECORD *pRec, int rec, char *record);
int main(void)
{
FILE *fp = {0};
char recStr[260];
char *buf;
char line[260];
int i;
char strArray[3][7];//simple array, 3 string of 7 char each (enough for NULL terminator)
i = -1;
fp = fopen ("admin.txt", "r");
if(fp)
{
while (fgets (line, 260, fp))//will continue to loop as long as there is a new line
{
i++;
if(i >= MAX_RECORDS) break;//reached maximum records defined, time to leave
buf = strtok(line, ";");
if(buf)
{
strcpy(record[i].name, buf);
buf = strtok(NULL, ";");
if(buf)
{
strcpy(record[i].date, buf);
buf = strtok(NULL, ";");
if(buf)
{
record[i].num1 = atoi(buf);
buf = strtok(NULL, ";");
if(buf)
{
record[i].num2 = atoi(buf);
}
}
}
}
}
}
fclose(fp);
// 2nd argument valid values range from 1 - n (not 0 - n)
GetRecord(record, 3, recStr); //read third record into string "rec"
return 0;
}
void GetRecord(RECORD *pRec, int rec, char *record)
{
int r = rec - 1;//adjust for zero indexed arrays
if((r >= MAX_RECORDS) || (r < 0))
{
strcpy(record, "index error");
return;
}
sprintf(record, "%s;%s;%d;%d", pRec[r].name, pRec[r].date, pRec[r].num1, pRec[r].num2);
}
Note: "coz [you were] rushing and just copy the code, and accidentaly delete the important things",
I have not adhered strictly to your variable names. Adjust what I have done to meet your needs.
Results with your input file look like this:

Trying to read text file into array without repeats in C

This is for a beginner's C programming unit. I'm trying to read a text file containing MAC addresses and the data they received, separate out the relevant data (address and number of packets), copy the addresses to an array without repeating any of them and sum the associated number of packets if an identical address is encountered.
I can read the file in just fine, and get the bits of each line I want without issue, but when I try to check each address read against those already in the array I hit a problem. Depending on the location of the integer counting the number of full lines, the program either fails to recognise identical strings and prints them all as they are in the file, or prints them over one another in addresses[0], leaving me with only the last address. I'm stumped and need some fresh eyes on this - any suggestions would be greatly appreciated.
My code follows:
static void readadds(char filename[])
{
FILE* packetfile = fopen(filename, "r");
FILE* datafile = fopen("packdata.txt", "w+");
// Open file from input; create temporary file to store sorted data.
char line[100];
char addresses[500][18];
int datasize[500];
int addressno = 0;
// Create storage for lines read from text file, addresses and related data.
if(packetfile != NULL)
{
while(fgets(line, sizeof line, packetfile) != NULL)
{
int linenum = 0;
char thisadd[18];
int thisdata;
//Create arrays to temp store data from each line
sscanf(line, "%*s %*s %s %i", thisadd, &thisdata);
for(int i = 0; i < 500; i++)
{
if(strcmp(thisadd, addresses[i]) == 0)
{ //check if the address is already in the array
int x = datasize[i];
datasize[i] = x + thisdata; //sum packet data if address already exists
printf("Match!\n");
break;
}
else
{
strcpy(addresses[linenum], thisadd); //initialize new address
datasize[linenum] = thisdata; //initialize assoc. data
linenum++;
addressno++;
printf("Started!\n");
break;
}
}
}
for(int i = 0; i <= addressno; i++)
{
printf("%s %i\n", addresses[i], datasize[i]);
fprintf(datafile,"%s %i\n", addresses[i], datasize[i]);
}
}
fclose(packetfile);
fclose(datafile);
}
This version prints over addresses[0]. If linenum is replaced by addressno in the for() loop, identical strings are not recognised. My dataset is arranged like this:
1378251369.691375 84:1b:5e:a8:bf:7f 68:94:23:4b:e8:35 100
1378251374.195670 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 397
1378251374.205047 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 397
1378251374.551604 00:8e:f2:c0:13:cc 00:11:d9:20:aa:4e 157
1378251375.551618 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.552697 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.553957 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
1378251375.555332 84:1b:5e:a8:bf:7c cc:3a:61:df:4b:61 37
I'm almost certain this is what you're trying to do. The logic to add a new entry was incorrect. You only add one if you have exhausted searching all the current ones, which means you need to finish the current for-search before the add.
Note: Not tested for compilation, but hopefully you get the idea.
static void readadds(char filename[])
{
// Open file from input; create temporary file to store sorted data.
FILE* packetfile = fopen(filename, "r");
FILE* datafile = fopen("packdata.txt", "w+");
// Create storage for lines read from text file, addresses and related data.
char addresses[500][18];
int datasize[500];
int addressno = 0;
if (packetfile != NULL)
{
char line[100];
while(fgets(line, sizeof line, packetfile) != NULL)
{
char thisadd[18];
int thisdata = 0;
//Create arrays to temp store data from each line
if (sscanf(line, "%*s %*s %s %i", thisadd, &thisdata) == 2)
{
// try to find matching address
for(int i = 0; i < addressno; i++)
{
if(strcmp(thisadd, addresses[i]) == 0)
{
//check if the address is already in the array
datasize[i] += thisdata;;
printf("Match!\n");
break;
}
}
// reaching addressno means no match. so add it.
if (i == addressno)
{
printf("Started!\n");
strcpy(addresses[addressno], thisadd); //initialize new address
datasize[addressno++] = thisdata; //initialize assoc. data
}
}
else
{ // failed to parse input parameters.
break;
}
}
for(int i = 0; i <= addressno; i++)
{
printf("%s %i\n", addresses[i], datasize[i]);
fprintf(datafile,"%s %i\n", addresses[i], datasize[i]);
}
}
fclose(packetfile);
fclose(datafile);
}

Resources