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.
Related
I'm trying to make two functions, a writefile and a readfile. Obviously, writefile will write to a file using the contents from the struct pokemon, and readfile will read the file line by line and get the contents of the file. For example, after writing to a file successfully with two pokemon in the struct, the text file will look like this:
30
Pikachu
12
Charizard
The read file is supposed to store the level and name in the struct, and I'm currently having trouble. I've already been told that using fgets is correct, but I'm not doing it correctly.
struct pokemon
{
int level;
char name[30];
};
int readfile(struct pokemon pokearray[], int* num, char filename[])
{
FILE * fp;
int i = 0;
fp = fopen(filename, "r");
pokearray[10].level;
if (fp == NULL)
{
printf("errorrr");
return -1;
}
while (!feof(fp))
{
fgets(pokearray[i].level, 10, fp);
}
fclose(fp);
return 0;
}
I am doing a small project for college (1st semester doing a bookstore implementation) and I have a problem with reading from a text file into a list of structs, with a two-dimensional array of characters in it that stores authors. However, it doesn't work properly (every time I launch the program it shows list is empty). Writing to a file works (I think, because it overwrites my text file with empty data).
Example data:
Adam Mickiewicz///Pan Tadeusz/Publisher 1/1833/24.99
Jules Verne///Around The World in 80 days/Publisher 1/1904/19.99
Jean-Jacques Sempe/Rene Goscinny//Little Nicholas/Publisher 2/1963/22.99
My structure:
#define AK 3 // Constant denoting max number of authors
typedef struct
{
char authors[AK][100];
char title[255];
char publisher[100];
unsigned int year;
double price;
struct Book *next;
} Book;
Book *first; // Address of the first element in a list
Reading from file:
void read_from_file(const char *path)
{
int no_of_authors;
int i;
printf("Loading...\n");
FILE *fp = fopen(path, "r"); // Opening a file
// Checking for errors
if (!fp) {
printf("Error reading from file!");
return;
}
// The loading mechanism
no_of_authors = 0;
while (!feof(fp)) {
Book *new = (Book*) malloc(sizeof(Book));
for (i = 0; i < AK; i++) {
fscanf(fp, "%s/", new->authors[i]);
}
fscanf(fp, "%s/%s/%u/%lf", new->title, new->publisher,
&new->year, &new->price);
fscanf(fp, "\n");
new = new->next;
}
fclose(fp);
printf("Loading successful.");
}
Writing to file (just in case):
void write_to_file(const char *path, Book *first)
{
int i;
printf("Saving...\n");
FILE *fp = fopen(path, "w");
Book* current = first;
if (!fp) {
printf("Error opening the file!");
dump_list(first); // Dumping the list to prevent memory leaks, this works okay
}
// Saving mechanism
while (first != NULL) {
for (i = 0; i < AK; i++) {
fprintf(fp, "%s/", current->authors[i]);
}
fprintf(fp, "%s/%s/%u/%lf", current->title, current->publisher,
¤t->year, ¤t->price);
fprintf(fp, "\n");
}
fclose(fp);
printf("Saved successfully");
}
OP's biggest failing is not checking the return value of fscanf(). Had code done so, problems would be more rapidly detected.
When is comes to reading lines of data the first consideration is:
Could input be faulty?
With learner applications this is often considered no. Input is either "good" or end-of-file. Let us not assume data is too well formated.
As it turns out, while the data file may not be faulty, the code reading it may be wrong. The subtle 2nd reason for code to check the *scanf() return values - self validation.
For line orientated data, it is much better to read is a line of data with fgets() than feof(), fscanf()... See also #Paul Ogilvie
char buf[sizeof(Book) * 2]; // Use an ample sized buffer
while (fgets(buf, sizeof buf, fp)) {
Use "%s" to read in text that does not include white-space. This will also read in '/'. Since '/' is use to delimit, "%s" is not an acceptable input specifier. Further names like "Adam Mickiewicz" include a space. A 2nd reason to not use "%s".
Consider what fscanf(fp, "%s/", new->authors[i]); is doing. "%s" scans into new->authors[i] non-white-space characters. A character after non-white-space characters is a white-space, never a '/'.
Use "%[^/]" to read in text that does not include '/'.
Use "%n" to keep track of the current scan offset.
Now parse the line.
char *p = buf;
Book *nu = malloc(sizeof *nu); // no cast needed
for (size_t i = 0; i < AK; i++) {
int n = 0;
sscanf(p, "%99[^/]/%n", nu->authors[i], &n);
if (n == 0) {
Handle_Parse_Error();
}
p += n;
}
if (sscanf(p, "%254[^/]/%99[^/]/%u/%lf",
nu->title, nu->publisher, &nu->year, &nu->price) != 4) {
Handle_Parse_Error();
}
Robust code would add checks on each member. Suit to coding goals.
if (nu->year < -6000 || nu->year > 2999) Fail_Year_Range();
Further work is needed to link data together. OP's code is unclear on this matter and so left to OP. A possible approach:
Book *read_from_file(const char *path) {
Book first; // Only the .next member is used.
first.next = NULL;
Book *current = &first;
// setup while () loop
...
while (fgets(buf, sizeof bu, fp)) {
...
Book *nu = malloc(sizeof *nu);
nu->next = NULL;
...
// parse data, fill in rest of nu->
....
current->next = nu; // update current pointer
current = nu;
}
// close up file ...
return first.next;
}
I'm having a weird bug where the text I append is being added to the beginning of a file instead of the end of it. This ends up making everything backwards.
CODE:
#include <stdio.h>
#include <stdlib.h>
//Check Values
void checkValues(int numDisks, int raidType, int chunkSize){
while (numDisks < 1 || numDisks > 9){
printf("Number inputed for numDisks is not valid, please enter a new value (1-9).\n");
scanf("%d", &numDisks);
}
while(raidType < 0 || raidType > 1){
printf("Number inputed for raidType is not valid, please enter a new value (0-1).\n");
scanf("%d", &raidType);
}
while(chunkSize < 1 || chunkSize > 512){
printf("Number inputed for chunkSize is not valid, please enter a new value (1-512).\n");
scanf("%d", &chunkSize);
}
}
//CreateFile
void createFile(int numDisks){
char raidName[5];
int counter = 1;
//Create each file
while(counter != numDisks + 1){
sprintf(raidName, "raid%d", counter); //Append counter to string
FILE *out = fopen(raidName, "w");
counter++;
}
}
//Write File
void writeFile(int numDisks, char *buffer, int counter){
char raidName[5];
sprintf(raidName, "raid%d", counter); //Append counter to string
//Write File
FILE *out = fopen(raidName, "a");
fprintf(out, "%s", buffer);
}
//Read and Write Files
void rwFile(const char *fileName, int chunkSize, int numDisks){
char buffer[10000];
int counter = 1;
//Reading File
FILE *in = fopen(fileName, "r");
if(in == NULL) return;
//Create File
createFile(numDisks);
while(fgets(buffer, chunkSize + 1, in) != NULL){
//Reset Counter
if(counter > numDisks){
counter = 1;
}
writeFile(numDisks, buffer, counter);
counter++;
}
}
int main(int argc, const char *argv[]){
//Declarations
const char *fileName = argv[1];
int numDisks = atoi(argv[2]);
int raidType = atoi(argv[3]);
int chunkSize = atoi(argv[4]);
checkValues(numDisks, raidType, chunkSize);
rwFile(fileName, chunkSize, numDisks);
}
raid1.txt:
mmmmiiiieeeeaaaa
What should be written to raid1.txt:
aaaaeeeeiiiimmmm
I have tried using fseek but to no avail. If anybody could help me out or point me in the right direction that would help. This is done in C using bash to compile and run the program. The arguments that are passed are test.txt 4 0 4.
I imagine the problem you are seeing is due to each call to writeFile is opening a fresh handle to the file, writing to it and then just returning. Once you have finished using a file handle you should close it, this will flush the file buffer to the file and free up the handle.
What I think is happening here is you are opening up a fresh handle each time and each of these is only having a small amount of data written to it, so isn't being flushed to disk. You program is then exiting and the OS is cleaning up the stale file handles flushing them to disk. As a guess I imagine it is doing that clean up in reverse order hence the appearance of your file being written backwards.
Update your writeFile to include a close and hopefully that should resolve the issue
FILE *out = fopen(raidName, "a");
fprintf(out, "%s", buffer);
fclose(out);
It might be nicer if you open the file for writing in the loop calling writeFile and pass the handle over, and then you only need to open it and close it once.
Worth adding closes elsewhere, where you have opened files too.
HTH
One more thing I see you are using address of local variables for scanf in check values(k), these are local only and Never going to be reflected in Main()
I have written a small code which takes input from the user and passes it to the system ("command>/tmp/j"), here the file j is being created but there is no information inside it related to the input present in the command.
For eg: If I have given ps -f as input to the string command, the system() should execute it and store it inside file /tmp/j, but here the file j is being created but there is no output data inside it.
I have seen many questions, but all those are using popen() and the input is predefined in them.
#include<stdio.h>
#include<sys/syscall.h>
main()
{
enum msgtype {PROCESS_LIST_REQUEST=1, PROCESS_LIST_RESPONSE, DIRECTORY_LIST_REQUEST, DIRECTORY_LIST_RESPONSE, ERROR_REQUEST};
struct head
{
int version;
int msg_length;
int header_length;
enum msgtype msg_type;
char data;
char *reqtype;
};
struct head *buf;
buf = malloc((sizeof(struct head)));
buf->reqtype=malloc(40);
char req[10];
char *command;
command = malloc((sizeof(char) * 10));
fgets(req, sizeof(req),stdin);
buf->reqtype = req;
printf("%s" , buf->reqtype); //just to make sure correct thing is present
command = buf->reqtype;
printf("%s",command);//just to make sure correct thing is present
system ("command>/tmp/j");
{
FILE *fp;
char c;
fp = fopen("/tmp/j", "r");
if (fp == NULL)
printf("File doesn't exist\n");
else {
do {
c = getc(fp);
putchar(c);
} while (c != EOF);
}
fclose(fp);
}
}
This line
system ("command>/tmp/j");
Tries to run an executable literally called command, and redirects its output to /tmp/j. The redirection happens, thus creating the file /tmp/j, but then command (whatever it may be) produces no output.
Also, this
command = malloc((sizeof(char) * 10));
followed by this
command = buf->reqtype;
causes the memory from the malloc() call to leak.
As somebody else says
system ("command>/tmp/j");
tries to run a program called 'command'. YOu need to do
char buff[256];
snprintf(buff, sizeof(buff), "%s>/tmp/j", command);
system(buff);
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