How can I create a BST by reading from a text file? - c

I have to create a database of students, that contains their ID, name, surname, and grade. This information is read from a txt file that looks like this:
AE797989 Spears Michael 10.00
AA566734 Walsh Brad 10.00
AE808090 Jones Dimitris 5.00
...
and contains 19 students
I have to read each line of the file and create a binary search tree based on their ID. There seems to be a problem when I'm creating a node, because when I try to search a student I can't. Here's my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
struct node
{
struct node *left;
char ID[100];
char NAME[100];
char LAST_NAME[100];
float Grade;
struct node *right;
};
struct node *newNode(char, char, char, float);
struct node *insertNode(struct node node, char id, char name, char last_name, float grade);
void search(struct node *root, char *ID);
void deleteFromBST(char *ID);
int main()
{
char ID[100];
int insertDone = 0;
int ch;
while (1) {
printf("\n1. Insertion\t2. Deletion\n");
printf("3. Searching\t4. Display In Order\n5. Edit\t 6. Exit\n");
printf("Enter your choice:");
scanf("%d", &ch);
switch (ch) {
case 1:
if (insertDone)
puts("Inserton was already done");
else {
struct node* insertNode(struct node *node,char *id, char *name, char *last_name, float grade)
{
if (node == NULL)
return newNode(*id,*name,*last_name,grade);
if ( strcmp(id , node->ID) < 0)
node->left = insertNode(node->left,id,name,last_name,grade);
else if ( strcmp( id , node->ID) >= 0)
node->right = insertNode(node->right,id,name,last_name,grade);
return node;
}
insertDone = 1;
}
break;
case 2:
break;
case 3:
printf("Enter the AM to search:");
scanf("%99s", ID);
void search(struct node *root, char *ID)
{
int flag=0;
if (!root)
{
printf("Search element unavailable in BST\n");
return;
}
while (root != NULL) {
if (strcmp(root->ID, ID) == 0) {
printf("Student ID : %s\n", root->ID);
printf("First Name : %s\n", root->NAME);
printf("Last Name : %s\n", root->LAST_NAME);
printf("grade : %lg\n", root->Grade);
flag = 1;
break;
}
else if (strcmp(ID , root->ID) > 0)
{
return search(root->right,ID);
}
else if(strcmp(ID , root->ID) < 0)
{
return search(root->left,ID);
}
if (!flag)
printf("Search element unavailable in BST\n");
}
}
break;
case 4:
//display();
break;
case 5:
break;
case 6:
exit(0);
default:
printf("U have entered wrong option!!\n");
break;
}
}
struct node* newNode(char *id, char *name, char *last_name, float grade)
{
struct node *newnode = malloc(sizeof(struct node));
struct node Node;
FILE *fp;
fp = fopen ("Foitites-Vathmologio-DS.txt","rb");
if (fp == NULL)
{
fprintf(stderr,"Could not open file");
return;
}
char line[4096];
while (fgets(line, sizeof line,fp))
{
size_t len = strlen(line);
if (len && (line[len - 1] == '\n'))
{
/* incomplete line */
if (sscanf(line,"%99s %99s %99s %f",Node.ID, Node.NAME, Node.LAST_NAME, &Node.Grade) != 4)
{
puts("invalid file");
return;
}
strcpy(newnode->ID , id);
strcpy(newnode->NAME , name);
strcpy(newnode->LAST_NAME , last_name);
newnode->Grade = grade;
newnode->left = newnode->right = NULL;
return newnode;
}
}
fclose(fp);
}
return 0;
}
I get no error messages.. thank you for your time!

If you get no error message with this code, I would suggest you to use a different compiler. Mine chokes in main at:
switch (ch) {
case 1:
if (insertDone)
puts("Inserton was already done");
else {
struct node* insertNode(struct node *node, char *id, char *name,
char *last_name, float grade) // ERROR HERE
{
if (node == NULL)
It looks that you have copied the definition of the function instead of just calling it.
My problem is that you managed to write many different errors in a single program. And the global design of how the program should be structured is not clear: it looks like you started coding without first writing on a paper (yes papers and pencils are still very good tools for beginners) what each function should do, what was its its inputs and what should be its outputs and eventually what data it was including (for example what part is in charge of the file name). Of course, I could write a BST program for you, but you would not learn anything from that.
So here are some hints:
in a BST, you insert new data under existing nodes so you will need a function insertNode with following input parameters: the current root node (or NULL at first time), the id, name, last_name and grade to insert. You should build a new copy of the input strings (strdup is your friend). This function will allocate a new structure, fills is fields, and either return it if the current root was NULL, or insert it at its correct place in the existing tree
you want to process all lines from a file. You will need a function that open the file, read it line by line and will use previous one to insert the new record in the BST
BTW a function definition is something like
struct node *insert(struct node *root, const char id*, const char *name, const char *last_name, float grade) {
struct node * newnode = malloc(sizeof *newnode);
...
return root;
}
outside of any other function definition, while a function call will be like:
struc node *root = NULL;
char id[100], name[100], last_name[100];
float grade;
...
if (sscanf(line,"%99s %99s %99s %f",id, name, last_name, &grade)) != 4)
{
puts("invalid file");
return;
}
root = insert(root, id, name, last_name, grade); // here is the function call

Related

Hashtable & BST Implementation

I'm working on an assignment that can accept commands from keyboard to insert people into a hashtable. After someone is inserted into the hastable, they can be "friended" with another person in the table. The way I have to store who is friends with who is a binary search tree. What I have to do is for the hashtable the first part of the node would be the person's name, then then next is a pointer to the bst for that person's friends, and finally the end is a pointer to the next node for chaining if there is a collision. Here is a visual example...
I have been able to insert people into my table, but the problem that I can not figure out is how to access the BST and add in friends for that person. Here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structures
struct linkedList{
char *name;
struct linkedList *next;
struct linkedList *tree;
};
typedef struct linkedList list;
struct hashTable{
int size;
list **table;
};
typedef struct hashTable hash;
struct bst{
char *val;
struct bst *l;
struct bst *r;
};
int main(){
char input[50];
char *ch, cmd_str[50], name[30];
// Make hash table for names
hash *profiles;
profiles = createHashTable(1001);
while(1){
// Get keyboard input
fgets(input, 50, stdin);
input[strlen(input)-1] = '\0';
// parse the input
ch = strtok(input, " ");
strcpy(cmd_str,ch);
if(strcmp("CREATE", cmd_str) == 0){
ch = strtok(NULL, " \n");
insertPerson(profiles, ch);
}
else if(strcmp("FRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
strcpy(name, ch);
ch = strtok(NULL, " \n");
friendPerson(profiles, name, ch);
}
else if(strcmp("UNFRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
}
else if(strcmp("LIST", cmd_str) == 0){
ch = strtok(NULL, " \n");
printFriends(profiles, ch);
}
else if(strcmp("QUERY", cmd_str) == 0){
}
else if(strcmp("BIGGEST-FRIEND-CIRCLE", cmd_str) == 0){
}
else if(strcmp("INFLUENTIAL-FRIEND", cmd_str) == 0){
}
else if(strcmp("EXIT", cmd_str) == 0){
printf("\nExiting...\n");
return 0;
}
else{
printf("\nBad Command.\n");
}
}
}
// Creates Hash Table
hash *createHashTable(int size){
int i;
hash *new_table;
if((new_table = malloc(sizeof(hash))) == NULL)
return NULL;
if((new_table->table = malloc(sizeof(list *) * size)) == NULL)
return NULL;
for(i=0; i < size; i++)
new_table->table[i] = NULL;
new_table->size = size;
return new_table;
}
// hashing function
int keyHash(char *name){
int c;
unsigned long key;
while(c = *name++)
key = ((key<<5) + key) + c;
return key%1000;
}
// insert a person into the hash table
void insertPerson(hash *profiles, char *name){
struct linkedList *item = (struct linkedList*)malloc(sizeof(struct linkedList));
int hash_val = keyHash(name);
item->name = name;
item->next = NULL;
item->tree = new_tree;
// Collision case
if(profiles->table[hash_val] != NULL){
while(profiles->table[hash_val]->next != NULL){
profiles->table[hash_val] = profiles->table[hash_val]->next;
}
profiles->table[hash_val]->next = item;
}
// Empty cell
else{
profiles->table[hash_val] = item;
}
}
// friend two people inside the hash table
void friendPerson(hash *profiles, char *name, char *_friend){
int hash1 = keyHash(name);
int hash2 = keyHash(_friend);
// check if the names are already in system
if(!profiles->table[hash1]){
printf("%s is not yet in the system", name);
return;
}
if(!profiles->table[hash2]){
printf("%s is not yet in the system", _friend);
return;
}
// add first friend
if(strcmp(profiles->table[hash1]->name, name) == 0){
insertBST(profiles->table[hash1]->tree, _friend);
}
else{
while(profiles->table[hash1]->next != NULL){
if(strcmp(profiles->table[hash1]->name, name) == 0)){
break;
}
profiles->table[hash1] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash1]->tree, _friend);
}
// add second friend
if(strcmp(profiles->table[hash2]->name, _friend) == 0){
insertBST(profiles->table[hash2]->tree, name);
}
else{
while(profiles->table[hash2]->next != NULL){
if(strcmp(profiles->table[hash2]->name, name) == 0)){
break;
}
profiles->table[hash2] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash2]->tree, name);
}
}
// creates a new bst node
struct bst *newBSTNode(char *name){
struct bst *temp = (struct bst* )malloc(sizeof(struct bst));
temp->val = strdup(name);
strcpy(temp->val, name);
temp->l = temp->r = NULL;
return temp;
}
// Inserts the a friend into a BST
struct bst *insertBST(struct bst *node, char *name){
if(!node)
return newBSTNode(name);
else{
if(strcmp(name, node->val) < 0){
node->l = insertBST(node->l, name);
}
else if(strcmp(name, node->val) > 0){
node->r = insertBST(node->r, name);
}
}
return node;
}
// Inorder print of names
void inorder(struct bst *root){
if(!root){
inorder(root->l);
printf("%s ", root->val);
inorder(root->r);
}
}
// Sends to function to print names
void printFriends(hash *profiles, char *name){
int hash_val = keyHash(name);
inorder(profiles->table[hash_val]->tree);
}
How would I be able to access the BST of said person? The struct bst *tree = profiles->table[hash1]->tree; was my previous attempt, but it was more of a shot in the dark. Thanks in advance!
Update: Okay, so I have been able to add friends (I think) and now I'm trying to print them with void printFriends(). However when I run the function nothing prints out. Would anyone know where I'm messing it up? I've updated the code above.
Your linkedList stores the name and a tree pointer. But the type of tree is linkedList. Change that to struct bst *. You'll have to reorder the declarations, or insert a forward declaration.
Implement a search. You check if the hash buckets are empty, but you don't search for the matching name.
Once you find a matching name in the bucket, the same node contains the aforementioned tree pointer. Insert the friend in the tree. Depending on your logic, you may or may not want to insert a backreference in the other person's tree. (If Alice is friends with Bob, does that make Bob friends with Alice automatically? Or wait for confirmation?)

Pointers and binary search tree

I am working on a program that uses a binary search tree (as an exercise).
My problem is that when I try to add a customer(in the middle of my code lines 65-69) I get an error that BS_node is undeclared, though I insert struct BST_node *root in this function..
Part of my code is below, just for the readers to read it easier, if requested I can upload the full code ! Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 50
void flush();
struct customer {
char *name;
char *address;
char *email;
};
struct double_linked_list {
struct customer *data;
struct double_linked_list *previous;
struct double_linked_list *next;
};
struct double_linked_list *customers_head=0;
struct BST_node {
struct double_linked_list *data;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *BST_email_root = 0;
struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root==NULL)
return NULL;
if (strcmp(email,root->data->data->email)==0)
return root;
else
{
if (strcmp(email,root->data->data->email)==-1)
return BST_find_customer(root->left,email);
else
return BST_find_customer(root->right,email);
}
}
void find_customer() {
char email[MAX_STRING];
struct double_linked_list *l;
struct BST_node *b;
printf("Give the email of the customer (up to %d characters) : ", MAX_STRING-1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b==0)
printf("There is no customer with this email.\n");
else
{
l = b->data;
printf("Customer found! \n");
printf("Name : %s\n", l->data->name);
printf("Address : %s\n", l->data->address);
printf("Email : %s\n", l->data->email);
}
}
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL);
{
root = (BST_node *) malloc (sizeof(BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if (strcmp(l->data->email,root->data->data->email)==-1)
root->left =new_BST_node(root->left,l);
else root->right =new_BST_node(root->right,l);
return root;
};
struct double_linked_list *new_customer()
{
char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
struct BST_node *b;
struct double_linked_list *l;
struct customer *c;
printf("\nADDING NEW CUSTOMER\n=\n\n");
printf("Give name (up to %d characters): ", MAX_STRING-1);
gets(name);
printf("Give address (up to %d characters): ", MAX_STRING - 1);
gets(address);
printf("Give email (up to %d characters): ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b)
{
printf("Duplicate email. Customer aborted.\n");
return 0;
}
c = (struct customer *) malloc(sizeof(struct customer));
if (c == 0)
{
printf("Not enough memory.\n");
return 0;
}
c->name = strdup(name); // check for memory allocation problem
if (c->name == 0) return 0;
c->address = strdup(address); // check for memory allocation problem
if (c->address == 0) return 0;
c->email = strdup(email); // check for memory allocation problem
if (c->email == 0) return 0;
l = (struct double_linked_list*) malloc(sizeof(struct double_linked_list));
if (l == 0)
{
printf("Not enough memory.\n");
free(c->name);
free(c->address);
free(c->email);
free(c);
return 0;
}
l->data = c;
l->previous = 0;
l->next = customers_head;
if (customers_head)
customers_head->previous = l;
customers_head = l;
BST_email_root = new_BST_node(BST_email_root, l);
return l;
}
void displaymenu() {
printf("\n\n");
printf("1. New customer\n");
printf("2. Find customer using email\n");
printf("0. Exit\n\n");
printf("Give a choice (0-6) : ");
}
void flush()
{
char ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
int main() {
int choice;
do {
displaymenu();
scanf("%d", &choice);
flush();
switch (choice) {
case 1:
new_customer();
break;
case 2:
find_customer();
break;
} while (choice != 0);
return 0;
}
On the line 69, you have to specify struct BST_node instead of BST_node:
root = (struct BST_node *) malloc (sizeof(struct BST_node ));
As for the rest of the code: read the manual for gets, it's clearly a function one should not use, I'd advise replacing it with fgets. There's also a little closing bracket missing in your final switch (line 178).

Segmentation fault while using malloc

As an exercise I am trying to work on a Binary search tree!
I have created the code and it seems to run, but when I try to add a customer it crashes. After debugging the code I get a segmentation fault in line 82, where I try to allocate memory to root... Researching for a while I see that it is something related to memory, but can't figure what is going on with my code... Any suggestions about what is causing this failure when trying to allocate memory?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 50
void flush();
struct customer {
char *name;
char *address;
char *email;
};
struct double_linked_list {
struct customer *data;
struct double_linked_list *previous;
struct double_linked_list *next;
};
struct double_linked_list *customers_head = 0;
struct BST_node {
struct double_linked_list *data;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *BST_email_root = 0;
struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root == NULL)
return NULL;
if (strcmp(email, root->data->data->email) == 0)
return root;
else {
if (strcmp(email, root->data->data->email) == -1)
return BST_find_customer(root->left, email);
else
return BST_find_customer(root->right, email);
}
}
void find_customer() {
char email[MAX_STRING];
struct double_linked_list *l;
struct BST_node *b;
printf("Give the email of the customer (up to %d characters) : ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b == 0)
printf("There is no customer with this email.\n");
else {
l = b->data;
printf("Customer found! \n");
printf("Name : %s\n", l->data->name);
printf("Address : %s\n", l->data->address);
printf("Email : %s\n", l->data->email);
}
}
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left = new_BST_node(root->left, l);
else
root->right = new_BST_node(root->right, l);
return root;
};
struct double_linked_list *new_customer() {
char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
struct BST_node *b;
struct double_linked_list *l;
struct customer *c;
printf("\nADDING NEW CUSTOMER\n=\n\n");
printf("Give name (up to %d characters): ", MAX_STRING - 1);
gets(name);
printf("Give address (up to %d characters): ", MAX_STRING - 1);
gets(address);
printf("Give email (up to %d characters): ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b) {
printf("Duplicate email. Customer aborted.\n");
return 0;
}
c = (struct customer *)malloc(sizeof(struct customer));
if (c == 0) {
printf("Not enough memory.\n");
return 0;
}
c->name = strdup(name); // check for memory allocation problem
if (c->name == 0)
return 0;
c->address = strdup(address); // check for memory allocation problem
if (c->address == 0)
return 0;
c->email = strdup(email); // check for memory allocation problem
if (c->email == 0)
return 0;
l = (struct double_linked_list*)malloc(sizeof(struct double_linked_list));
if (l == 0) {
printf("Not enough memory.\n");
free(c->name);
free(c->address);
free(c->email);
free(c);
return 0;
}
l->data = c;
l->previous = 0;
l->next = customers_head;
if (customers_head)
customers_head->previous = l;
customers_head = l;
BST_email_root = new_BST_node(BST_email_root, l);
return l;
}
void displaymenu() {
printf("\n\n");
printf("1. New customer\n");
printf("2. Find customer using email\n");
printf("0. Exit\n\n");
printf("Give a choice (0-6) : ");
}
void flush() {
char ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
int main() {
int choice;
do {
displaymenu();
scanf("%d", &choice);
flush();
switch (choice) {
case 1:
new_customer();
break;
case 2:
find_customer();
break;
}
} while (choice != 0);
return 0;
}
Codeblocks debugger gives the following information
Active debugger config: GDB/CDB debugger:Default
Building to ensure sources are up-to-date
Selecting target:
Debug
Adding source dir: C:\debug\
Adding source dir: C:\debug\
Adding file: C:\debug\bin\Debug\debug.exe
Changing directory to: C:/debug/.
Set variable: PATH=.;C:\Program Files\CodeBlocks\MinGW\bin;C:\Program Files\CodeBlocks\MinGW;C:\Windows\System32;C:\Windows;C:\Windows\System32\wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\ATI Technologies\ATI.ACE\Core-Static;C:\Users\baskon\AppData\Local\Microsoft\WindowsApps
Starting debugger: C:\Program Files\CodeBlocks\MINGW\bin\gdb.exe -nx -fullname -quiet -args C:/debug/bin/Debug/debug.exe
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 7.6.1
Child process PID: 5908
Program received signal SIGSEGV, Segmentation fault.
In ?? () ()
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
At C:\debug\main.c:82
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
The call stack is the following
There are multiple problems in your code:
You have a classic bug here:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
The ; at the end of the if statement line is parsed as an empty statement. The subsequent block, introduced by the { will always be executed.
You can avoid this kind of silly bug by always using braces for your compound statements and placing them on the same line as the beginning of the statement, not on the next line. This is close to the original K&R style used by the creators of the C language more than 40 years ago.
The type for variable ch in function flush should be int to allow proper distinction of all values returned by getc(): all values of unsigned char plus the special value EOF:
void flush(void) {
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
continue;
}
}
Note that you should make the empty statement more explicit as I did above, to avoid confusion and bugs such as the previous one.
You should not use the obsolete unsafe function gets(): Use fgets() and strip the trailing newline with strcspn().
When comparing strings with strcmp(), you should only rely on the sign of the return value. In functions BST_find_customer() and new_BST_node(), you compare with -1: this is unreliable. Use if (strcmp(email, root->data->data->email) < 0) instead.
In function new_BST_node(), You do not return root when you create a new node in the tree. Here is a corrected version:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL) {
root = malloc(sizeof(*root));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
return root;
}
if (strcmp(l->data->email, root->data->data->email) < 0) {
root->left = new_BST_node(root->left, l);
} else {
root->right = new_BST_node(root->right, l);
}
return root;
}
Note that this is causing your bug as you probably have an infinite recursion here.
Finally a couple pieces of advice:
use NULL instead of 0 when comparing pointers to the null pointer. It is more readable.
avoid naming a variable l as this name is graphically too close to 1 with the fixed pitch fonts used in programming environments. Sometimes it is almost indistinguishable.
Ok, so after testing everything i found out what is wrong however i can't figure out why.. Any Suggestions??
I think that strcmp returns values of either 0 or -1 or 1.
But there was the problem, if i didn't define exactly if strcmp ==1 or if strcmp ==-1 ...i had an infinite loop as it seems (i used a printf command to see what is going on, and i discovered the bug..)
By changing
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root = (struct BST_node *) malloc (sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left =new_BST_node(root->left,l);
else
root->right =new_BST_node(root->right,l);
return root;
};
to
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root= (struct BST_node *)malloc(sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if ((strcmp(l->data->email, root->data->data->email))==-1)
root->left =new_BST_node(root->left,l);
else if ((strcmp(l->data->email, root->data->data->email)) ==1)
root->right =new_BST_node(root->right,l);
return root;
};
everything works fine..
But why didnt the other code work? I am pretty sure it is the same...

Read data from file into structure

I am working on a program that can process structure items in linkedlist/nodes.
I have most of the functions running fine, however am stuck on how to read from a txt file into a structure (the readFromFile function).
I have been reading around but am still quite confused, mainly on how to write this as a function instead of in main, and also reading into a structure
any help would be appreciated.
EDIT:
I cannot seem to get the functions in the answers to work at the moment, so I am changing to trying to make the program read from txt in main.
I could open the file, but the problem is:
How do I read data into my linked list?
(code has been modified)
The text file I am reading from is formatted like this:
#1 Flat Blade Screwdriver
12489
36
.65
1.75
#2 Flat Blade Screwdriver
12488
24
.70
1.85
#1 Phillips Screwdriver
12456
27
0.67
1.80
#2 Phillips Screwdriver
12455
17
0.81
2.00
Claw Hammer
03448
14
3.27
4.89
Tack Hammer
03442
9
3.55
5.27
Cross Cut Saw
07224
6
6.97
8.25
Rip Saw
07228
5
6.48
7.99
6" Adjustable Wrench
06526
11
3.21
4.50
My program so far:
#include "stdafx.h"
#include <stdlib.h>
typedef struct inventory
{
char invName[36];
int invPartNo;
int invQOH;
float invUnitCost;
float invPrice;
}stock;
struct NODE
{
union
{
int nodeCounter;
void *dataitem;
}item;
struct NODE *link;
};
struct NODE *InitList();
void DisplayNode(struct inventory *);
struct inventory * ReadData(FILE *);
void DisplayList(struct NODE *);
struct NODE* GetNode(FILE *);
void Add2List(struct NODE *, struct NODE *);
struct NODE* SearchList(struct NODE *, int );
void DeleteNode(struct NODE *, int );
int main(int argc, char* argv[])
{
struct NODE *header;
header = InitList();
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
gets(file_name);
fp = fopen(file_name,"r"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF )
{
//what to put here?
}
fclose(fp);
DisplayList(header);
return 0;
}
struct NODE *InitList()
{
struct NODE *temp = (struct NODE*)malloc(sizeof NODE);
temp->item.nodeCounter = 0;
temp->link = NULL;
return temp;
}
void Add2List(struct NODE *start, struct NODE *NewNode)
{
struct NODE *current = start;
while (current->link != NULL)
current = current->link;
current->link = NewNode;
NewNode->link = NULL;
start->item.nodeCounter++;
}
struct NODE* GetNode(FILE *fptr)
{
struct NODE *temp = (struct NODE*)malloc(sizeof NODE);
temp->item.dataitem = ReadData(fptr);
temp->link = NULL;
return temp;
}
void DisplayList(struct NODE *start)
{
struct NODE *current = start->link;
while (current != NULL)
{
DisplayNode((struct inventory *)current->item.dataitem);
current = current->link;
}
}
void DisplayNode(struct inventory *stuff)
{
/*
char invName[36];
int invPartNo;
int invQOH;
float invUnitCost;
float invPrice;
*/
printf("Name: %s", stuff->invName);
printf("Part Number: %d", stuff->invPartNo);
printf("Quantity on hand: %d", stuff->invQOH);
printf("Unit Cost: %0.2f", stuff->invUnitCost);
printf("Price %0.2f", stuff->invPrice);
}
struct inventory * ReadData(FILE *fptr)
{
struct inventory *temp = (struct inventory *)malloc(sizeof inventory);
if(fptr==stdin)
printf("Enter item name: ");
fscanf_s(fptr, "%s", temp->invName);
if(fptr==stdin)
printf("Enter item part number: ");
fscanf_s(fptr, "%d", &temp->invPartNo);
if(fptr==stdin)
printf("Enter item quantity on hand: ");
fscanf_s(fptr, "%d", &temp->invQOH);
if(fptr==stdin)
printf("Enter item unit cost: ");
fscanf_s(fptr, "%f", &temp->invUnitCost);
if(fptr==stdin)
printf("Enter item price: ");
fscanf_s(fptr, "%f", &temp->invPrice);
return temp;
}
struct NODE* SearchList(struct NODE *start, int oldData)
{
struct NODE* current = start;
struct inventory * st = (struct inventory *)current->link->item.dataitem;
while (st->invPartNo != oldData && current != NULL)
{
current = current->link;
if(current->link)
st = (struct inventory *)current->link->item.dataitem;
}
return current;
}
void DeleteNode(struct NODE *start, int oldData)
{
struct NODE *current, *oldNode;
current = SearchList( start, oldData);
oldNode = current->link;
current->link = oldNode->link;
free(oldNode);
start->item.nodeCounter -= 1;
}
You can use fscanf() and fgets() to read the data as,
void readFromFile( )
{
stock array[20];
int i,j;
i=0;
fp = fopen("input.txt", "r");
if( fp != NULL ){
while ( !feof(fp ) ){
fgets(array[i].invName,sizeof array[i].invName,fp);
fscanf(fp,"%d %d %f %f ",&array[i].invPartNo,&array[i].invQOH,&array[i].invUnitCost,&array[i].invPrice);
i++;
}
}
The array[] will have the data and i will be number of struct data read.
Here all spaces in fscanf() are put to skip the [enter] character since the data is in different lines.
read about fscanf() with its format matching and fgets() it can help in reading files.
To avoid feof() can use,
while (fgets(array[i].invName,sizeof array[i].invName,fp)) {
fscanf(fp,"%d %d %f %f ",&array[i].invPartNo,&array[i].invQOH,&array[i].invUnitCost,&array[i].invPrice);
i++;
}
for This particular file format.
The algorithm:
Open the text file in 'text' 'read' mode.
Create an array of stock structures, if you know number of items beforehand, else use a linked list with each node of type stock.
To read data from file to corresponding field you can use fscanf .
When you think you have finished reading data, close the file.
Notes:
The file pointer is automatically incremented so you need not worry about incrementing it to read next set of data.
Do not forget to close the file.
To check whether the file handling functions are working fine, do check the return value of all the functions.
Important:
Since your invPartNo field in the file has integer data starting with 0, you may not want to read it as integer, otherwise it will be treated as "octal number" not a decimal number.
Your _tmain could look like below, this code assumes that the contents in the file are complete (i.e. contains the correct number of lines):
int _tmain(int argc, _TCHAR* argv[])
{ struct NODE *header = InitList();
if (argc > 1)
{ FILE *f;
if ((f = fopen(argv[1], "rt") == NULL)
{ printf(_T("Could not open file %s\n"), argv[1]);
return 1;
}
while (!feof(f))
Add2List(header, GetNode(f));
fclose(f);
}
else
{ int PCounter = 2;
while (PCounter--)
Add2List(header,GetNode(stdin));
}
DisplayList(header);
return 0;
}
EDIT:
Run the program from the command-prompt and pass the file name as a parameter

Scanf Validation

Can someone help me validate the inputs for the Scanf's i have below. I want the programme to ask for the data to be re-entered if the Scanf's are within an incorrect range or not an interger. I put in a do while loop before with an if statement but when i compiled it the first printf and scanf just looped
#include <stdio.h>
#include <stdlib.h>
int MenuLoop = 0;
int MaxPackets = 4;
int currentPackets= 0;
int menu;
/*********************************************************
* Node to represent a Cat which includes a link reference*
* a link list of nodes with a pointer to a Cat Struct *
* would be better but this is for illustartion only! *
**********************************************************/
struct Packet {
int Source;
int Destination;
int Type;
int Port;
char *Data;
struct Packet *next; // Link to next Cat
};
typedef struct Packet node; // Removes the need to constantly refer to struct
/*********************************************************
* Stubs to fully declared functions below *
**********************************************************/
void outputPackets(node **head);
void push(node **head, node **aPacket);
node* pop(node **head);
void AddPacket();
void AddPacket();
void SavePacket();
void ShowCurrent();
void ExitProgramme();
main() {
do{
Menu();
} while(menu<4);
}
void AddPacket(){
int option;
/*********************************************************
* pointers for the link list and the temporary P to *
* insert into the list *
**********************************************************/
node *pPacket, *pHead = NULL;
/*********************************************************
* Create a cat and also check the HEAP had room for it *
**********************************************************/
pPacket = (node *)malloc(sizeof(node));
if (pPacket == NULL)
{
printf("Error: Out of Memory\n");
exit(1);
}
currentPackets++;
printf("Enter Source Number between 1-1024:\n");
scanf("%i", &pPacket->Source);
printf("Enter Destination Number between 1-1024:\n");
scanf("%i", &pPacket->Destination);
printf("Enter Type Number between 0-10:\n");
scanf("%i", &pPacket->Type);
printf("Enter Port Number between 1-1024:\n");
scanf("%i", &pPacket->Port);
printf("Enter Data Numberbetween 1-50:\n");
scanf("%s", &pPacket->Data);
printf("Do you want to Enter another Packet?");
pPacket->next = NULL;
/*********************************************************
* Push the Cat onto the selected Link List, the function *
* is written so the program will support multiple link *
* list if additional 'pHead' pointers are created. *
* Who says you cannot herd cats! *
**********************************************************
* NOTE: The push parameters are using references to the *
* pointers to get round the pass by value problem caused *
* by the way C handles parameters that need to be *
* modified *
**********************************************************/
push(&pHead, &pPacket);
pPacket = (node *)malloc(sizeof(node));
if (pPacket == NULL)
{
printf("Error: Out of Memory\n");
exit(1);
}
outputPackets(&pHead);
/*********************************************************
* Display the Link List 'pHead' is passed as a reference *
**********************************************************/
return 0;
do{
if(currentPackets == MaxPackets);
{
printf("Packet limit reached please save\n");
}
}while(currentPackets<MaxPackets);
return 0;
}
void outputPackets(node **head)
{
/*********************************************************
* Copy Node pointer so as not to overwrite the pHead *
* pointer *
**********************************************************/
node *pos = *head;
/*********************************************************
* Walk the list by following the next pointer *
**********************************************************/
while(pos != NULL) {
printf("Source: %.4i Destination: %.4i Type: %.4i Port: %.4i \n", pos->Source, pos->Destination, pos->Type, pos->Port);
pos = pos->next ;
}
printf("End of List\n\n");
}
void push(node **head, node **aPacket)
{
/*********************************************************
* Add the cat to the head of the list (*aCat) allows the *
* dereferencing of the pointer to a pointer *
**********************************************************/
(*aPacket)->next = *head;
*head = *aPacket;
}
node *pop(node **head)
{
/*********************************************************
* Walk the link list to the last item keeping track of *
* the previous. when you get to the end move the end *
* and spit out the last Cat in the list *
**********************************************************/
node *curr = *head;
node *pos = NULL;
if (curr == NULL)
{
return NULL;
} else {
while (curr->next != NULL)
{
pos = curr;
curr = curr->next;
}
if (pos != NULL) // If there are more cats move the reference
{
pos->next = NULL;
} else { // No Cats left then set the header to NULL (Empty list)
*head = NULL;
}
}
return curr;
}
void SavePacket(){
FILE *inFile ;
char inFileName[10] = { '\0' } ;
printf("Input file name : ") ;
scanf("%s", inFileName) ;
//Open file
inFile = fopen(inFileName, "w+");
if (!inFile)
{
fprintf(stderr, "Unable to open file %s", &inFile);
exit(0);
}
//fprintf(inFile, "Source: %i Destination: %i Type: %i Port: %i \n", pos->Source, pos->Destination, pos->Type, pos->Port);
fclose(inFile);
}
void ShowCurrent(){
}
void ExitProgramme(){}
void Menu(){
printf("********Welcome****** \n");
printf("Creator Ben Armstrong.\n\n");
printf("*Please Choose an option*\n");
printf("1. Add a new packet\n");
printf("2. Save current packet to file\n");
printf("3. Show current list of packets\n");
printf("4. Exit\n");
scanf("%i", &menu);
switch(menu)
{
case 1:
AddPacket();
break;
case 2:
SavePacket();
break;
case 3 :
ShowCurrent();
break;
case 4 :
ExitProgramme();
break;
}
}
This is my full code as u can see im trying to implement a link list which the data has to be validated for
Use the following macro
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
You find in this topic the macro explaination
Example of using it :
int main()
{
.......
printf("Enter Source Number between 1-1024:\n");
SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Source, (pPacket->Source>=1 && pPacket->Source<=1024);
printf("Enter Destination Number between 1-1024:\n");
SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Destination, (pPacket->Destination>=1 && pPacket->Destination<=1024);
printf("Enter Type Number between 0-10:\n");
SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Type, (pPacket->Type>=0 && pPacket->Type<=10);
printf("Enter Port Number between 1-1024:\n");
SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Port, (pPacket->Port>=1 && pPacket->Port<=1024);
printf("Enter Data Numberbetween 1-50:\n");
SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Data, (pPacket->Data>=1 && pPacket->Data<=50);
}
Here is one approach using strtol:
#include <stdlib.h>
#include <stdio.h>
struct Packet {
int Source;
int Destination;
int Type;
int Port;
int Data;
};
void func(struct Packet *pPacket) {
char entry[100];
int i;
char *tail;
do {
printf("Enter Source Number between 1-1024:\n");
scanf("%99s", entry);
i = strtol(entry, &tail, 0);
} while (*tail || i < 1 || i > 1024);
pPacket->Source = i;
}
int main(int argc, char* argv[])
{
struct Packet pPacket;
func(&pPacket);
printf("pPacket->Source is now %i.\n", pPacket.Source);
return 0;
}

Resources