The title is my best guess at the problem at the moment, but I'm not completely sure.
I'm trying to read from a file that contains numbers and strings that start with a character(only strings start with a char). This file is created earlier in the program by code that should execute before this file is needed.
main
int main(void){
//name of the file to accessed
char *fileName = "input.txt";
node *head, *tail;
node *symListHead = NULL;
head = tail = createNode();
//creates the file with no comments exits if the file is not created
if(cleanFile(fileName) == 0){
exit(1);
}
//create the head of the linked list containing all tokens
head = createSymbolList();
//this should create the file and fill in called "lexemelist.txt"
printTableAndList( head );
//create a sym list of ints for comparison to enumerated types
symListHead = generateSymList();
//recursiveParse( symListHead );
return 0;
}//end main
So on the line with printTabelAndList(head) the file "lexemelist.txt" should be created and filled. And in symListHead = generateSymList() that file should be used. But if I run the code with symListHead = generateSymList() commented out the file is created and filled as it should be, but if the line is left in the file is left empty leading and nothing is read from the empty file.
lexemelist.txt contents with the line symListHead = generateSymList(); left in
29 2 x 17 2 y 18 21 2 x 20 2 y 4 3 56 18 22 19
lexemelist.txt contents with the line symListHead = generateSymList(); removed
genetateSymList()
symNode *generateSymList(){
FILE *fp;
char buff[255];
symNode *head, *temp;
head = temp = createSymNode();
fp = fopen("lexemelist.txt" , "r");
if(fp == NULL){
printf("\nfile not found.\n");
return NULL;
}
//this line is skicped since the file is empty for some reason
while(fscanf(fp, "%s", buff) != EOF)
{
if(isalpha(buff[0]))
continue;
printf("%d", atoi(buff));
temp->sym = atoi(buff);
temp->next = createSymNode();
temp = temp->next;
}//end while
fclose(fp);
return head;
}
printTableAndList()
void printTableAndList(node *head){
FILE *tfp, *lfp;
tfp = fopen("lexemetable.txt", "w");
lfp = fopen("lexemelist.txt", "w");
fprintf(tfp , "lexeme token type\n\n");
generateTableAndList(head, tfp, lfp);
}
Never mind I forgot to close my files in the printTableAndList() function.
Related
So, i need a code to read a TXT file with 5 contents each line, and store each line values in a variable. but the number of lines in the TXT will vary. so i thought of excecuting something like this:
int counter=0;
char nome="TXT NAME.txt";
FILE *f = fopen(NAME,"r");
do{
if(!feof(p))
counter++;
}while(!feof(f));
fclose(f)
int X[counter][5];
so when declaring like this, X will have the number of lines of the file. but the issue is that to store the values, i would need to open and read the file again. is there a way to save the values while declaring the variable so i dont need to open twice ?
How to read a file in C and at the same time create a variable with the number of lines?
is there a way to save the values while declaring the variable so i dont need to open twice ?
A nice way is to read one line at a time with fgets(), copy the buffer with strdup() and save in a linked list of your creation.
Some pseudo-code to get you going.
f = open file
exit if unable to open
line_count = 0;
list = LL_Create()
char buffer[100];
while (fgets(buffer, sizeof buffer, f)) {
Maybe special handling here to deal with lines longer than 100
char *s = strdup(buffer);
LL_Append(list, s);
line_count++;
}
fclose(f);
// Use the link-list of strings
// When done
while !LL_Empty(list)
s = LL_Pop(list)
free(s);
LL_Destroy(list)
You can use realloc to gradually expand your "array".
But a simpler approach is to use a linked list, that way the list just grows as you read the file.
typedef struct
{
char data[5];
Line* next;
} Line;
Line* first = NULL;
Line* last = NULL;
char line[128];
while (fgets(line, sizeof(line), f)
{
Line* tmp = malloc(sizeof(Line));
memcpy(tmp->data,line,5);
tmp->next = NULL;
if (first == NULL)
{
first = last = tmp;
}
else
{
last->next = tmp;
last = tmp;
}
}
Now to go through the lines
for(Line* p = first; p != NULL; p = p->next)
{
p->data ...
}
I know how to hardcore a program to receive a file but when I try a similar tactic with scanf nothing happens. I mean that I have an error check that looks to see if it exist and if it has the right format but everytime I enter the filename it doens't print the printf statement below the scanf. Why is that? I also found out that I am opening the file but the while statement is infinite. Which doesn't make sense. I have tried another solution shown below but same results.
void parseFile(struct student_record_node** head)
{
FILE*input;
const int argCount = 4;
char filename[100]="";
const char rowformat[] = "%20s %20s %d %d";
struct student_record record;
struct student_record_node* node = NULL;
printf("\n Please Enter the FULL Path of the .txt file you like to load. \n");
scanf("%s",filename);
input = fopen(filename, "r");
printf("I am here");
if(input == NULL)
{
printf("Error: Unable to open file.\n");
exit(EXIT_FAILURE);
}
while(!feof(input))
{
/* creating blank node to fill repeatedly until end of document*/
memset(&record, 0, sizeof(struct student_record));
if(fscanf(input, rowformat, record.first_name_,record.last_name_,&record.student_id_,&record.student_age_) != argCount)
{
continue;
}
/* set node into the doubly linked list */
node = student_record_allocate();
/* copies values from the blank node reading from document into node in my linked list */
strcpy(node->record_->first_name_, record.first_name_);
strcpy(node->record_->last_name_, record.last_name_);
node->record_->student_id_ = record.student_id_;
node->record_->student_age_ = record.student_age_;
/* check if node right after absolute head is empty if so fills it */
if(*head == NULL)
{
*head = node;
}
else
{
printf(" stuck in loop\n");
/* if current isn't null start linking the node in a list */
appendNode(head,node);
}
}
fclose(input);
printf(" end of parsefile");
}
When I got to the parsefile() function and enter NEW.txt which is in the correct format and inside the same folder as the program itself. I know that my check is working when I enter a .txt file that doesn't exist or that is empty it gets caught like it should.
The expected behavior is that the program should load this list from new.txt and load it into a doubly linked list. Then return to a menu that gives user options. The doubly linked listed can then be manipulated such as add students manipulate data, deleting, saving and printing current roster. I have trouble using gdb with this program since I receive new.txt from parsefile.
Sample of New.txt contents. (Its just First Name, Last Name, Id, Age)
Belinda Homes 345 50
Scott Crown 456 18
Failed Solution: Using fgetc instead of feof
int c = fgetc(input);
while(c != EOF)
{
printf("\n in loop \n");
/* creating blank node to fill repeatedly until end of document*/
memset(&record, 0, sizeof(struct student_record));
if(fscanf(input, rowformat, record.first_name_,record.last_name_,&record.student_id_,&record.student_age_) != argCount)
{
continue;
}
/* set node into the doubly linked list */
node = student_record_allocate();
/* copies values from the blank node reading from document into node in my linked list */
strcpy(node->record_->first_name_, record.first_name_);
strcpy(node->record_->last_name_, record.last_name_);
node->record_->student_id_ = record.student_id_;
node->record_->student_age_ = record.student_age_;
/* check if node right after absolute head is empty if so fills it */
if(*head == NULL)
{
*head = node;
}
else
{
printf(" stuck in loop\n");
/* if current isn't null start linking the node in a list */
appendNode(head,node);
}
c = fgetc(input);
}
This is the easiest way to read from file and print out. I assume you want to print the file or do something with it.
int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF){
putchar(c);
}
fclose(file);
}
So I am trying to write a c file that has a student record database, once the file runs it is supposed to read student records from a binary file and add them to a linked list: the student struct looks like this :
typedef struct student {
char lname[10], initial, fname[10];
unsigned long SID;
float GPA;
struct student* next; /* pointer to the next student record */
} studentList;
I am using single linked lists for my data, and my code runs fine if I read and write the data with fscanf. However, once I started using fwrite and fread, everytime my program loads it would not load up the data from the text file correctly, when I check the binary file it seems it has data in it. Here is what I have for my load and write data functions:
void printRecords() {
FILE *fPointer = fopen("data.bin", "w");
studentList *newStudent = head;
while (newStudent != NULL) { /*Loop through linked list starting from head node*/
fwrite(&newStudent, sizeof(newStudent), 1, fPointer);
newStudent = newStudent->next;
}
}
void loadRecords() {
studentList *cStudent;
FILE *fPointer = fopen("data.bin", "r");
int counter = 0;
int x = 0;
int n = 0;
while (n != 0) {
printf("test\n");
if (fPointer == NULL) {
break;
}
cStudent = (studentList *)malloc(sizeof(studentList));
n = fread(&cStudent, sizeof(cStudent), 1, fPointer);
x = cStudent->GPA;
printf("%d\n", x);
if (feof(fPointer)) { break; }
if (counter == 0) {
head = cStudent;
temp = (studentList *)malloc(sizeof(studentList));
temp = cStudent;
counter++;
}
temp->next = (studentList *)malloc(sizeof(studentList));
temp->next = cStudent;
temp = temp->next;
}
fclose(fPointer);
}
so what am I doing wrong as right now it does not read anything into my list, it seems like it writes but not sure if it even writes the correct data, I have spent a long time trying to figure this out and have been stuck on it for a while now, thanks in advance.
To read write to binary files in c.
FILE *fPointer=fopen("data.bin","wb"); //to write file
FILE *fPointer=fopen("data.bin","rb"); //to read file
There are multiple problems with your code.
printRecords has problems:
you should use binary mode.
you write the contents of the pointer and some indeterminate contents instead of whet the pointer points to. This is actually undefined behavior.
you forgot to close the file.
the value written to the file for the next member is meaningless. Writing the same records may produce different file contents for different runs.
Here is a corrected version that returns the number of records written or -1 if the file could not be opened:
int printRecords(void) {
FILE *fPointer = fopen("data.bin", "wb");
studentList *sp;
int n = 0;
if (fPointer == NULL)
return -1;
/* Loop through linked list starting from head node */
for (sp = head; sp != NULL; sp = sp->next) {
n += fwrite(sp, sizeof(newStudent), 1, fPointer);
}
fclose(fPointer);
return n;
}
loadRecords has even more problems:
binary mode should be used too.
the way you test for end of file is incorrect.
the way you link records does not work either.
Here is a corrected version of loadRecords that returns the number of records read or -1 if the file could not be opened:
int loadRecords(void) {
studentList student, *newsp, *sp;
FILE *fPointer = fopen("data.bin", "rb");
int n = 0;
if (fPointer == NULL)
return -1;
while (fread(&student, sizeof(student), 1, fPointer) == 1) {
n++;
student.next = NULL; // value read from file is meaningless
newsp = malloc(sizeof(studentList));
*newsp = student;
if (head == NULL) {
head = newsp;
} else {
/* append the new record to the list */
for (sp = head; sp->next; sp = sp->next)
continue;
sp->next = newsp;
}
}
fclose(fPointer);
return n;
}
Be aware that storing binary data to the file system this way is not portable. The representation of integers and floats may differ from one platform to another, as well as alignment of the structure members, especially the next pointer which is useless in the file anyway. This file should only be read back on the same platform, with the same program that wrote it, making it a poor choice for backup or persistent storage.
There are problems in the file write function, mainly the data pointer and size:
void printRecords(){
FILE *fPointer = fopen("data.bin","wb"); // add "b" mode (MSVC)
if (fPointer == NULL) // check file opened
exit(1); // or report "Cannot open file"
studentList *newStudent = head;
while(newStudent !=NULL)
{
fwrite(newStudent, sizeof(*newStudent), 1, fPointer); // remove the & and add a *
newStudent = newStudent->next;
}
if (fclose(fPointer)) // close the file
exit(1); // or report "Failed to close file"
}
I'm very new to programming and I'm trying to load a dictionary from a text file to a linked list. I use a while loop for this but my code reads the last word twice (I also ran gdb to verify it). I guess something if my while condition is not working well but I cannot figure out why? Anyone can help me understand this?
Here is my code
char* text = "small.txt";
// open the dictionary file
FILE* fp = fopen(text, "r");
if (fp == NULL)
{
printf("Could not open %s.\n", text);
// unload();
return 1;
}
// temporary storage for current word
char curr_word [LENGTH + 1];
node * curr, * head;
head = NULL;
while (feof (fp) == 0)
{
curr = malloc(sizeof(node));
fscanf (fp, "%s", curr_word);
strcpy (curr -> word, curr_word);
curr -> next = head;
head = curr;
}
Remove any empty new line at the end of the text file.
If a new line character is present, one more iteration will be performed, fscanf will fail, and a new node containing the most recent text will be added.
My program doesn't seem to be opening the text files properly.
I have a path.txt which is a string representation of all the paths of folders and text files which I have created. When running the program however, it will not output the LINES of the text file the user asked for.
OUTPUT
enter text file
warning: this program uses gets(), which is unsafe.
a1.txt
IT should have output
This is a1
text of a1.txt:
This is a1
text file: path.txt/ this is how my folder is set up with the text files.
a/a1.txt
a/a2.txt
a/b/b3.txt
a/b/b4.txt
a/c/c4.txt
a/c/c5.txt
a/c/d/d6.txt
a/c/d/g
a/c/d/h
a/c/e/i/i7.txt
a/c/f/j/k/k8.txt
code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct sMyPath{
char *element;
struct sMyPath *next;
} tMyPath;
int main(void)
{
FILE *pFile;
pFile = fopen("path.txt", "r");
char inputstr[1024];
tMyPath *curr, *first = NULL, *last = NULL;
//get the text file, and put it into a string inputstr
if (pFile != NULL)
{
while(!feof(pFile))
{
fgets(inputstr, sizeof(inputstr), pFile);
}
fclose(pFile);
}
else
{
printf("Could not open the file.\n");
}
//using tokens to get each piece of the string
//seperate directories and text files, put it into a link list
char *token = strtok(inputstr, "/");
while (token != NULL)
{
if(last == NULL){
//creating node for directory
first = last = malloc (sizeof (*first));
first -> element = strdup (token);
first -> next = NULL;
} else {
last -> next = malloc (sizeof (*last));
last = last -> next;
last -> element = strdup (token);
last -> next = NULL;
}
token = strtok(NULL, "/");
}
//ask user for txt file
char pathU[20];
printf("enter text file\n");
gets(pathU);
//check if text file exist, if yes output entires in text file, else say no
while(first != NULL)
{
if(first -> element == pathU)
{
FILE *nFile;
char texxt[300];
nFile = fopen(pathU, "r");
while (!feof(nFile))
{
fgets(texxt, 300, nFile);
printf("%s", texxt);
}
}
else if(first == NULL)
{
printf("invalid file name\n");
}
else
{
first = first -> next;
}
}
return 0;
}
I understand two possible requirement/implementation.
1) By your implementation, every link-node will contain just filename and directory name and NOT THE PATH-NAME. If you need to store entire pathname, use '\n' as delimiter.
char *token = strtok(inputstr, "\n");
and
token = strtok(NULL, "\n");
This assumes, when your input is a/a1.txt, your current directory contains the directory a and which in-turn contains the file a1.txt.
2) Otherwise, your existing code expects a1.txt to be in current directory, though it contradicts the input file content.
Either way, this below code is culprit,
if(first -> element == pathU)
which compares the pointer and not the string. Replace it as,
if( strcmp( first -> element, pathU ) == 0 )
I could help better solution if your requirement is more clear..
The problem seems to be in the string comparison: first -> element == pathU. Here you are comparing pointers, not the characters of the strings. Use strcmp instead: if (strcmp(first -> element, pathU) == 0) ...