How to read a .txt file from user input in C - c

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);
}

Related

File contents not filled in time to read from in C

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.

fread/fwrite not working as expected

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"
}

strange result reading a text file in a linked list in c

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.

Error in reading data from a file in a C program implementing linked list on linux

I have got stuck on this program and feeling very irritated now.
It's not showing any error but not giving correct output as well.
Please help me out.
#include<stdio.h>
struct node
{
int data;
struct node *link;
};
static int noofnodes=0;
struct node *first=NULL, *last=NULL, *next, *prev, *cur;
void insert1()
{
FILE *fp;
int flag=5;
fp=fopen("./abc.txt","r");
if(fp == NULL)
{
printf("\n not a valid file pointer");
return;
}
printf("EOF has value %d",EOF);
while(feof(fp)!= EOF )
{
cur=(struct node*)malloc(sizeof(struct node));
fscanf(fp, "%d\n",&cur->data);
if(first==NULL)
{
first=cur;
first->link=NULL;
}
else
{
next->link=cur;
}
next=cur;
}
last=cur;
fclose(fp);
printf("Data Inserted from file List_Data.txt");
}
I am calling insert1 from main() to copy the contents of file list_data.txt to my linked list node.
list_data.txt simply contains nos from 1-9 (one number in each line).
Thanks in advance.
Your I/O loop is wrong, feof() doesn't return EOF.
Don't use feof(), use fscanf() into a temporary variable and stop when it fails. In other words, check that I/O succeeds before relying on the results.
Something like:
int t;
while(fscanf(fp, "%d\n", &t) == 1)
{
/* allocate new node, set data to t ... */
}
Actually, since whitespace in the format string matches any combination of (including none) whitespace in the input, it's better to put it before the conversion:
while(fscanf(fp, " %d", &t) == 1)
{
}
This works with a general space-separated file of integers, regardless of numbers per line and so on.
Also, please don't cast the return value of malloc() in C.

error in my search linked list implementation

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) ...

Resources