fprintf output is returning unpredictable results - c

My fprintf() is returning unpredictable results. I think it is returning the memory address number instead of the data inside the memory address. Can someone have a look at my code and check it out? When I used the &source within the fprintf() I'm told it is undeclared and when I declare it in the top of the function it doesn't work.
#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(Source, Destination, Type, Port, Data){
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 Data: %s \n", Source, Destination, Type, Port, Data);
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;
}
}

Here's part of your problem...
inFile = fopen(inFileName, "w+");
if (!inFile)
{
fprintf(stderr, "Unable to open file %s", &inFile);
exit(0);
}
I'm pretty sure you mean...
inFile = fopen(inFileName, "w+");
if (!inFile)
{
fprintf(stderr, "Unable to open file %s", inFileName );
exit(0);
}
Also note that &inFile is the address of the inFile variable, not the value stored in the FILE pointer.
Additionally, you declare your function prototype for saving the data as follows...
void SavePacket(Source, Destination, Type, Port, Data)
which says you're passing in a Source, a Destination, a Type, a Port and a Data argument, but apparently you mean those to be the names, not the types, so the compiler is assuming they are all integers. You need to give them a type and a name...
void SavePacket( int Source, int Destination, int Type, int Port, char* Data)
and now you can print them...
fprintf(
inFile, "Source: %i Destination: %i Type: %i Port: %i Data: %s \n",
Source, Destination, Type, Port, Data
);
But you have a much bigger mess going on, as you're declaring that SavePacket() should receive arguments, but you don't pass arguments to it when you call it...
case 2:
SavePacket();
break;
Which should be passing in the variables you need to print. Something like...
case 2:
SavePacket(
somePacket->Source, somePacket->Destination, somePacket->Type,
somePacket->Port, somePacket->Data
);
break;
But, you could make that easier this way...
void SavePacket( struct Packet* packet )
{
...
fprintf(
inFile, "Source: %i Destination: %i Type: %i Port: %i Data: %s \n",
packet->Source, packet->Destination, packet->Type,
packet->Port, packet->Data
);
}
And then call it by passing in the packet...
case 2:
{
struct Packet somePacket;
GetPacketDataFromSomewhere( &somePacket );
SavePacket( &somePacket );
break;
}

Related

Alphabetize and word frequency from a file using strtok in C

My goal is to analyze a text file, tokenize each word, then alphabetize each word with its word frequency.
Example:
Input: The house is on the ground on earth.
Output:
earth - 1
ground - 1
house - 1
is - 1
on - 2
the - 2
I have been able to open the file, read the file line by line, tokenize each word, converted the tokens to lowercase. I am stuck grouping and alphabetizing each token.
#include <stdio.h>
#include <stdlib.h>
void lower_string(char s[]);
int main()
{
FILE *file;
//char path[100];
char ch[100];
int characters;
/* Input path of files to merge to third file
printf("Enter source file path: ");
scanf("%s", path);
file = fopen(path, "r");*/
file = fopen("test.txt", "r"); //testing w.o repeated input
/* Check if file opened successfully */
if (file == NULL)
{
printf("\nUnable to open file.\n");
printf("Please check if file exists and you have read privilege.\n");
exit(EXIT_FAILURE);
}
const char delim[] = " ,.;!?[\n]";
char *token;
int tokenNum;
while (fgets(ch, sizeof(ch), file) != NULL)
{
lower_string(ch);
token = strtok(ch, delim);
while (token != NULL)
{
printf("Token:%s\n", token);
token = strtok(NULL, delim);
tokenNum++;
}
}
printf("%d\n", tokenNum); //total words testing
/* Close files to release resources */
fclose(file);
return 0;
}
void lower_string(char s[])
{
int c = 0;
while (s[c] != '\0')
{
if (s[c] >= 'A' && s[c] <= 'Z')
{
s[c] = s[c] + 32;
}
c++;
}
}
I have been looking into building and manipulating an ordered linked list of integers and binary search tree of integers. I'm having a hard time figuring out where I should begin to implement these features. So far i have been looking at the code below for ordered linked list.
#include <stdio.h>
#include <stdlib.h>
//These structures are declared globally so they are available to all functions
//in the program.
typedef struct list_node_s
{ //defines structure of one node
int key; //key value - here an integer
int count; //frequency key value encountered in input
struct list_node_s *restp; //pointer to the next node in list = NULL if EOL
} list_node_t;
typedef struct //defines head of list structure
{
list_node_t *headp; //pointer to first node in list, NULL if list is empty
int size; //current number of nodes in the list
} ordered_list_t;
//Prototypes
list_node_t * insert_in_order (list_node_t * old_listp, int new_key);
void insert (ordered_list_t * listp, int key);
int delete (ordered_list_t * listp, int target);
list_node_t * delete_ordered_node (list_node_t * listp, int target,int *is_deleted);
void print_list (ordered_list_t * listp);
#define SEND -999 //end of input sentinal
int main (void)
{
int next_key;
ordered_list_t my_list = {NULL, 0};
printf("\n\nProgram to build, display and manipulate (delete) an Ordered Linked List \n");
printf("\nAdapted from code in \"Problem Solving and Programming in C\" by J.R. Hanly and E.B. Koffman\n\n");
printf ("enter integer keys - end list with %d\n", SEND);
/* build list by in-order insertions*/
for (scanf ("%d", &next_key);
next_key != SEND;
scanf ("%d", &next_key))
{
insert (&my_list, next_key);
}
/* Display completed list */
printf ("\nOrdered list as built:\n");
print_list(&my_list);
/* Process requested deletions */
printf("enter key value for node to be removed from list or %d to end > ", SEND);
for (scanf ("%d", &next_key);
next_key != SEND;
scanf ("%d", &next_key))
{
if (delete (&my_list, next_key))
{
printf ("%d deleted.\n New list:\n", next_key);
print_list (&my_list);
}
else
{
printf ("No deletion. %d not found\n", next_key);
}
printf ("enter key value for node to be removed from list or %d to end > ", SEND);
}
return (0);
}
/* prints contents of a linked list Display the elements in the list pointed to by the pointer list.*/
void print_list (ordered_list_t * listp)
{
list_node_t * tmp;
for (tmp = listp->headp; tmp != NULL; tmp = tmp->restp)
printf ("key = %d; count = %d\n", tmp->key, tmp->count);
printf ("\n\n");
}
//Inserts a new node containing new_key into an existing list and returns a pointer to the first node of the new list
list_node_t * insert_in_order (list_node_t * old_listp, int new_key)
{
list_node_t * new_listp;
if (old_listp == NULL) //check for end of list (EOL)
{
new_listp = (list_node_t *) malloc (sizeof (list_node_t));
new_listp->key = new_key;
new_listp->count = 1;
new_listp->restp = NULL;
}
else if (old_listp->key == new_key) //check for matching key, increment count
{
old_listp->count++;
new_listp = old_listp;
}
else if (old_listp->key > new_key) //Next node key value > new key, so insert new node at current location
{
new_listp = (list_node_t *) malloc (sizeof (list_node_t));
new_listp->key = new_key;
new_listp->count = 1;
new_listp->restp = old_listp;
}
else
{
new_listp = old_listp;
new_listp->restp = insert_in_order (old_listp->restp, new_key);
}
return (new_listp);
}
//inserts a node into an ordered list_node_t
void insert (ordered_list_t * listp, int key)
{
++(listp->size);
listp->headp = insert_in_order (listp->headp, key);
}
//deletes the first node containing the target key from an ordered list; returns 1
//if target found & deleted, 0 otherwise (means target not in list)
int delete (ordered_list_t * listp, int target)
{
int is_deleted;
listp->headp = delete_ordered_node (listp->headp, target, &is_deleted);
if (is_deleted)
--(listp->size); //reduce current node count (size); keep size of list current
return (is_deleted);
}
/* deletes node containing target key from a list whose head is listp; returns a pointer
to the modified list (incase it is the first node, pointed to by listp), frees
the memory used by tyhe deleted node and sets a flag to indicate success (1) or
failure (0; usually means no such node found).
*/
list_node_t * delete_ordered_node (list_node_t * listp, int target, int *is_deleted)
{
list_node_t *to_freep, *ansp;
// if list empty, nothing to do; return NULL
printf ("check for empty list; target: %d \n", target);
if (listp == NULL)
{
*is_deleted = 0;
ansp = NULL;
}
//if first node is to be deleted, do it; relink rest of list to list header struct
else if (listp->key == target)
{
printf ("at first node; target: %d \n", target);
*is_deleted = 1;
to_freep = listp; //keeps track of node memory location to be freed
ansp = listp->restp;
free (to_freep); //release the memory of the deleted node for reuse
}
//if target exists, it is further down the list (recursive step), make recursive call
//to move down the list looking for the target value
else
{
printf ("chase down list to find: %d \n", target);
ansp = listp;
ansp->restp = delete_ordered_node (listp->restp, target, is_deleted);
}
return (ansp);
}
I'm finding it hard to implement that with strtok.
12/4 EDIT:
added: Nodes for BST.
Questions-
Don't know if key needs to be tracked.(I assume it'll be useful to pull specific words).
Where/how would I add the logic to alphabetize the tree.(study sources appreciated)
How do I pass each word through this tree?
#define WLENGTH 100
//Base Node info
struct node
{
char word[WLENGTH];
int key;
int freq;
struct node *left, *right;
};
//Function to create a new node
struct node *newNode(char wordn, int item, int freqn)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
temp->word = wordn;
temp->key = item;
temp->freq = freqn;
temp->left = temp->right = NULL;
return temp;
}
//Function to place nodes in order
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d ", root->key);
inorder(root->right);
}
}
/*Function to insert a new node with given key*/
struct node* insert(struct node* node, int key)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key);
/* Otherwise, recur down the tree */
if (key < node->key)
node->left = insert(node->left, key);
else if (key > node->key)
node->right = insert(node->right, key);
/* return the (unchanged) node pointer */
return node;
}
At the request of the OP, here is a bit of code to bulk load an entire text file for processing:
FILE *mustOpen( char *fname, char *mode ) {
FILE *fp = fopen( fname, mode );
if( fp == NULL ) {
fprintf( stderr, "Cannot open '%s'\n", fname );
exit( EXIT_FAILURE );
}
return fp;
}
// Passed the path to a file, opens, measures and bulk loads entire file (plus terminating '\0')
char *loadFile( char *fname ) {
FILE *fp = mustOpen( fname, "rb" );
fseek( fp, 0, SEEK_END );
size_t size = ftell( fp );
fseek( fp, 0, SEEK_SET );
char *buf;
if( ( buf = malloc( size + 1) ) == NULL )
fprintf( stderr, "Malloc() failed\n" ), exit( EXIT_FAILURE );
if( fread( buf, sizeof *buf, size, fp ) != size )
fprintf( stderr, "Read incomplete\n" ), exit( EXIT_FAILURE );
fclose( fp );
*(buf + size) = '\0'; // xtra byte allows strXXX() to work
return buf; // pointer to heap allocated buffer containing file's bytes
}
Remember to free() the buffer when done with its contents.
With the entire text loaded (and NULL terminated), here is a way to skip along the entire "string" finding each "word" (as defined by the delimiters):
for( char *cp = buf; (cp = strtok( cp, delim )) != NULL; cp = NULL ) {
/* process each single "word" */
}
Since the "text" is in memory, instances of each of the "words" are in memory, too. All that's needed is populating a BST with nodes that 'point to' one instance of each "word" and a counter that counts multiple occurrences of each word.
Finally, an "in order" traversal of the BST will give an alphabetised list of words and their frequency in the text.
Be sure to compartmentalize each of the functions. The "blocks" of functionality can then be re-used in other projects, and, who knows?... You may want to first load a dictionary and only report the words (and locations) that do not appear in the dictionary (typos?). The code that handles the BST "structure" (searching, adding, traversing) should be somewhat independent of what "information fields" comprise each node.

How to store the contents of a CSV file in a Linked List?

I am trying to insert the contents from a csv file into a linklist using C. However, I am getting quite a few garbage outputs. The source code is given below.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct product *customer_head;
struct customer
{
long long int c_id;//first 6 characters=date & next 6 characters=time & next characters=counter no & city code
/*Compulsory Fields (Cannot be Skipped)*/
char name[57];
long long int ph_no;//10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[58];
char city[25];
char state_code[2];
char pin[6];
char email[60];
struct customer *next;
};
struct customer * load()
{
FILE * cust=fopen("customer_db.csv","r");
struct customer *temp,*ptr;
customer_head=NULL;
char str[208];
char *token,*eptr1,*eptr2;
int line_cnt=0,i=0;
while(fgets(str,234,cust)!=NULL)
{
line_cnt=0;
i=0;
ptr=(struct customer *)malloc(sizeof(struct customer));
for(;str[i];i++)
{
if(str[i]=='\n')
{
str[i]='\0';
i=0;
break;
}
}
token=strtok(str,",");
while(token!=NULL)
{
if(line_cnt==0)
ptr->c_id=strtoll(token,&eptr1,10);
else if(line_cnt==1)
ptr->ph_no=strtoll(token,&eptr2,10);
else if(line_cnt==2)
sprintf(ptr->name,"%s",token);
else if(line_cnt==3)
sprintf(ptr->address,"%s",token);
else if(line_cnt==4)
sprintf(ptr->city,"%s",token);
else if(line_cnt==5)
sprintf(ptr->state_code,"%s",token);
else if(line_cnt==6)
sprintf(ptr->pin,"%s",token);
else
sprintf(ptr->email,"%s",token);
line_cnt++;
token=strtok(NULL,",");
}
if(customer_head==NULL)
customer_head=ptr;
else
temp->next=ptr;
temp=ptr;
}
}
int print(struct customer *h)
{
while(h->next!=NULL)
{
printf("\nCustomer ID: ");
printf("%lld",h->c_id);
printf("\nName: ");
puts(h->name);
printf("Phone Number: ");
printf("%lld",h->ph_no);
printf("\nAddress: ");
puts(h->address);
printf("City: ");
puts(h->city);
printf("State Code: ");
puts(h->state_code);
printf("PIN: ");
puts(h->pin);
printf("Email: ");
puts(h->email);
h=h->next;
}
printf("\nCustomer ID: ");
printf("%lld",h->c_id);
printf("\nName: ");
puts(h->name);
printf("Phone Number: ");
printf("%ld",h->ph_no);
printf("\nAddress: ");
puts(h->address);
printf("City: ");
puts(h->city);
printf("State Code: ");
puts(h->state_code);
printf("PIN: ");
puts(h->pin);
printf("Email: ");
puts(h->email);
return 1;
}
int main()
{
load();
print(customer_head);
}
I am also attaching the csv file here. In order for the program to be less complicated I have removed the headings from my csv file. They are in the order
Customer_ID,Phone_Number,Name,Address,City,State_Code,PIN,Email
1403201156540201,2226179183,Katherine_Hamilton,87_Thompson_St.,Fremont,IA,502645,k_hamilton#gmail.com
2204201532220103,8023631298,Marc_Knight,-,-,-,-,-
0305201423120305,8025595163,Albie_Rowland,-,Hamburg,NY,140752,-
0607201232220901,4055218053,Grant_Phelps,-,-,-,-,-
The dashes(-) indicate that those fields should remain empty.
The output is as follows:
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA502645k_hamilton#gmail.com
PIN: 502645k_hamilton#gmail.com
Email: k_hamilton#gmail.com
Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -
Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY140752-
PIN: 140752-
Email: -
Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -
As you can see, the contents are getting merged in quite a few places. I don't understand why.
Since from the comments you know that your declaration of your character arrays suffer from one-too-few character, at least in the case of char state_code[2]; leaving your array without a nul-terminating character leading to Undefined Behavior, you should ensure you have valid storage for all your input. (don't skimp on buffer size)
In general, you are making things a bit harder on yourself than it needs to be. Rather than attempting to use strtok() and count field and handle each field in a 8-part chain of if, else if ..., you have fixed input fields, so just parse the data with sscanf() and validate the number of conversions to confirm a successful parse, e.g.
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
Here, list_t is just an additional "wrapper" struct that holds a head and tail pointer for your linked list. This allows you to declare multiple lists in the scope needed and allows the same O(1) insertion by having the tail pointer always point to the last node in your list (your temp). Here, head and tail are just part of the wrapper and passed as a parameter rather than having to declare the list-pointer as global (bad practice). Each of the nodes in your list and the wrapper struct can be written as:
#define BYTE8 8 /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024
typedef struct node_t { /* list node */
/* 6 characters=date & 6 characters=time & counter no & city code */
long long int c_id;
/*Compulsory Fields (Cannot be Skipped)*/
char name[BYTE64];
long long int ph_no; //10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[BYTE64];
char city[BYTE32];
char state_code[BYTE8];
char pin[BYTE8];
char email[BYTE64];
struct node_t *next;
} node_t;
typedef struct { /* list wrapper with head & tail pointers */
node_t *head, *tail;
} list_t;
Then rather than writing your load() to contain both the FILE and list operations, keep your list operations separate. Simply create an add() function to add a node to your list, e.g.
/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
node_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
*node = *data; /* initialize members values */
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
Now your load function need only read each line from the file and parse the line before calling add() passing a pointer to a struct of data along with the list pointer as parameters. Your load() function reduces to:
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
(note: when using strtok() or sscanf(), there is no need to strip the trailing '\n' from your input string -- simply include that as a delimiter for strtok() or exclude it from the conversion with sscanf())
Further, you don't need multiple calls to puts() and printf() to print each node's worth of data in your list. Look at how many function calls you make to print your data. You only need ONE call to printf(), e.g.
/** print all nodes in list */
void prn_list (list_t *l)
{
if (!l->head) {
puts ("list-empty");
return;
}
for (node_t *n = l->head; n; n = n->next)
printf ("\nCustomer ID: %lld\n"
"Name: %s\n"
"Phone Number: %lld\n"
"Address: %s\n"
"City: %s\n"
"State Code: %s\n"
"PIN: %s\n"
"Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
n->state_code, n->pin, n->email);
}
In main() simply declare an instance of your list_t wrapper, open/validate your FILE and then pass a pointer to the list and file-stream to your list_from_csv() (your load()) and then print the list and finally free all memory you have allocated and you are done. (yes, the memory will be freed on exit, but develop good habits early -- it won't be long before you are using allocate memory in function where a failure to free before return results in a memory-leak)
int main (int argc, char **argv) {
list_t list = { .head = NULL, .tail = NULL };
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!list_from_csv (&list, fp))
return 1;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
prn_list (&list);
del_list (&list);
}
Putting it altogether, you would have something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BYTE8 8 /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024
typedef struct node_t { /* list node */
/* 6 characters=date & 6 characters=time & counter no & city code */
long long int c_id;
/*Compulsory Fields (Cannot be Skipped)*/
char name[BYTE64];
long long int ph_no; //10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[BYTE64];
char city[BYTE32];
char state_code[BYTE8];
char pin[BYTE8];
char email[BYTE64];
struct node_t *next;
} node_t;
typedef struct { /* list wrapper with head & tail pointers */
node_t *head, *tail;
} list_t;
/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
node_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
*node = *data; /* initialize members values */
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
/** print all nodes in list */
void prn_list (list_t *l)
{
if (!l->head) {
puts ("list-empty");
return;
}
for (node_t *n = l->head; n; n = n->next)
printf ("\nCustomer ID: %lld\n"
"Name: %s\n"
"Phone Number: %lld\n"
"Address: %s\n"
"City: %s\n"
"State Code: %s\n"
"PIN: %s\n"
"Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
n->state_code, n->pin, n->email);
}
/** delete all nodes in list */
void del_list (list_t *l)
{
node_t *n = l->head;
while (n) {
node_t *victim = n;
n = n->next;
free (victim);
}
}
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
int main (int argc, char **argv) {
list_t list = { .head = NULL, .tail = NULL };
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!list_from_csv (&list, fp))
return 1;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
prn_list (&list);
del_list (&list);
}
Example Use/Output
With your input file in dat/customer_list.txt, running the program you would receive:
$ ./bin/customer_list dat/customer_list.txt
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton#gmail.com
Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -
Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY
PIN: 140752
Email: -
Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/customer_list dat/customer_list.txt
==14823== Memcheck, a memory error detector
==14823== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14823== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14823== Command: ./bin/customer_list dat/customer_list.txt
==14823==
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton#gmail.com
<snipped rest>
==14823==
==14823== HEAP SUMMARY:
==14823== in use at exit: 0 bytes in 0 blocks
==14823== total heap usage: 7 allocs, 7 frees, 6,728 bytes allocated
==14823==
==14823== All heap blocks were freed -- no leaks are possible
==14823==
==14823== For counts of detected and suppressed errors, rerun with: -v
==14823== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
While you could cure a significant part of your problem just by ensuring you have adequate storage for each string, take the time to think through approaching the parse of values with sscanf() and since you control the conversion, there is no need to remove the trailing '\n' from the line read from the file. (just don't include the newline in the value parsed from your input string) If you did want to parse the '\n' from the end, you should be using, e.g.
str[strcspn (str, "\n")] = 0;
Lastly with both the format-string used with sscanf() and with strcspn() above, make sure you understand exactly how they work, see man 3 scanf and man 3 strspn
Let me know if you have further questions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum operations {EXIT, ADD_BOOK, ISSUE_BOOK, RETURN_BOOK, DISPLAY_BOOKS,
SORT_BOOKS, DISPLAY_BOOK_SUBJECTWISE};
typedef enum operations MENU;
typedef struct book
{
int bookId;
char bookName[30];
char subject[30];
char author[30];
float price;
}BOOK;
typedef struct node
{
struct node *prev;
BOOK info;
struct node *next;
}NODE;
NODE *head=NULL;
NODE *issuehead=NULL;
static int counter=0;
MENU menu_function()
{
int choice;
printf(" 1. Add Book\n");
printf(" 2. Issue Book\n");
printf(" 3. Return Book\n");
printf(" 4. Display Book\n");
printf(" 5. Sort Book\n");
printf(" 6. Display Books Subject-wise\n");
printf(" 0. EXIT\n");
printf(" Enter your choice::");
scanf("%d",&choice);
if(choice < 0 || choice > 6)
{
printf(" Error: Enter valid choice\n");
}
return choice;
}
void FreeList()
{
while(CountNodes(head))
{
DeleteBook();
}
while(CountNodes(issuehead))
{
DeleteIssues();
}
}
int CountNodes(NODE *trav)
{
int count=0;
while(trav!=NULL)
{
count++;
trav=trav->next;
}
return count;
}
void DeleteBook()
{
NODE *temp=head;
head = head->next;
free(temp);
temp=NULL;
}
void DeleteIssues()
{
NODE *temp=issuehead;
issuehead = issuehead->next;
free(temp);
temp=NULL;
}
void AcceptData(BOOK *book)
{
book->bookId=++counter;
getchar();
printf(" Enter Book name::");
scanf("%[^\n]s",&book->bookName);
getchar();
printf(" Enter Subject::");
scanf("%[^\n]s",&book->subject);
getchar();
printf(" Enter author::");
scanf("%[^\n]s",&book->author);
printf(" Enter price::");
scanf("%f",&book->price);
}
void DisplayData(BOOK book)
{
printf(" %d\t\t",book.bookId);
printf(" %s\t\t",book.bookName);
printf(" %s\t\t",book.subject);
printf(" %s\t\t",book.author);
printf(" %g\n",book.price);
}
NODE *CreateNode()
{
NODE *temp;
temp = (NODE *) malloc(sizeof(NODE));
temp->next=NULL;
temp->prev=NULL;
return temp;
}
void AddtoBooklist(BOOK book)
{
NODE *new_node;
new_node=CreateNode();
new_node->info=book;
if(head == NULL)
{
head=new_node;
}
else
{
new_node->next=head;
head->prev=new_node;
head=new_node;
}
}
void DisplayBooks(NODE *trav)
{
if(trav==NULL)
{
printf(" Book list is empty...\n");
}
else
{
printf(" Available Books\n");
while(trav!=NULL)
{
DisplayData(trav->info);
trav=trav->next;
}
printf("\n");
}
}
void IssueBook()
{
NODE *trav=head, *prev=NULL;
NODE *temp, *right;
int bookId;
printf(" Enter Book ID::");
scanf("%d",&bookId);
while(bookId != trav->info.bookId)
{
prev=trav;
trav=trav->next;
if(trav==NULL)
{
printf(" Book not found...\n");
break;
}
}
if(trav==head)
{
temp = trav;
head->prev=NULL;
head = head->next;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
else if(trav->next==NULL)
{
temp=trav;
prev->next=NULL;
trav->prev=NULL;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
else
{
temp=trav;
right=trav->next;
prev->next=right;
right->prev=prev;
trav->next=NULL;
trav->prev=NULL;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
}
void IssueAtFirst(NODE *temp)
{
if(issuehead == NULL)
{
issuehead=temp;
temp->next=NULL;
temp->prev=NULL;
temp=NULL;
}
else
{
temp->next=issuehead;
temp->prev=NULL;
issuehead=temp;
temp=NULL;
}
}
void ReturnBook()
{
NODE *trav=issuehead, *prev=NULL;
NODE *temp, *right;
int bookId;
printf(" Enter Book ID::");
scanf("%d",&bookId);
while(bookId != trav->info.bookId)
{
prev=trav;
trav=trav->next;
if(trav==NULL)
{
printf(" Book not found...\n");
break;
}
}
if(trav==issuehead)
{
temp = trav;
issuehead->prev = NULL;
issuehead = issuehead->next;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
else if(trav->next==NULL)
{
temp=trav;
prev->next=NULL;
trav->prev=NULL;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
else
{
temp=trav;
right=trav->next;
prev->next=right;
right->prev=prev;
trav->next=NULL;
trav->prev=NULL;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
}
void ReturnAtFirst(NODE *temp)
{
if(head == NULL)
{
head=temp;
temp->next=NULL;
temp->prev=NULL;
temp=NULL;
}
else
{
head->prev=temp;
temp->next=head;
temp->prev=NULL;
head=temp;
temp=NULL;
}
}
void SortBooks()
{
NODE *trav=head,*right=head->next;
BOOK temp;
while(trav->next!=NULL)
{
right=trav->next;
while(right!=NULL)
{
if(trav->info.bookId > right->info.bookId)
{
temp = trav->info;
trav->info = right->info;
right->info = temp;
}
right=right->next;
}
trav=trav->next;
}
}
void AddBooksToFile()
{
NODE *trav=head;
FILE *fp;
fp=fopen("Booklist.dat","wb");
if(fp!=NULL)
{
while(trav!=NULL)
{
fwrite(&trav->info, sizeof(BOOK),1,fp);
trav=trav->next;
}
}
fclose(fp);
}
void AddIssuesToFile()
{
NODE *trav=issuehead;
FILE *fp=issuehead;
fp=fopen("Issuelist.dat","wb");
if(fp!=NULL)
{
while(trav!=NULL)
{
fwrite(&trav->info, sizeof(BOOK),1,fp);
trav=trav->next;
}
}
fclose(fp);
}
void ReadIssuesFromFile()
{
BOOK book;
FILE *fp;
fp=fopen("Issuelist.dat","rb");
if(fp!=NULL)
{
while((fread(&book,sizeof(BOOK),1,fp))!=0)
{
AddtoIssuelist(book);
}
}
fclose(fp);
}
void ReadBooksFromFile()
{
BOOK book;
FILE *fp;
fp=fopen("Booklist.dat","rb");
if(fp!=NULL)
{
while((fread(&book,sizeof(BOOK),1,fp))!=0)
{
AddtoBooklist(book);
}
}
fclose(fp);
}
void AddtoIssuelist(BOOK book)
{
NODE *new_node;
new_node=CreateNode();
new_node->info=book;
if(issuehead == NULL)
{
issuehead=new_node;
}
else
{
new_node->next=issuehead;
issuehead->prev=new_node;
issuehead=new_node;
}
}
void DisplaySubjectWise(NODE *head)
{
NODE *trav=head;
char subject[30];
printf(" Enter subject::");
scanf("%s",&subject);
while(trav!=NULL)
{
if(stricmp(subject, trav->info.subject)== 0)
{
DisplayData(trav->info);
}
trav=trav->next;
}
}
int main()
{
MENU choice;
int data;
BOOK book;
ReadBooksFromFile();
ReadIssuesFromFile();
while((choice=menu_function())!=EXIT)
{
switch(choice)
{
case ADD_BOOK:
AcceptData(&book);
AddtoBooklist(book);
printf(" Book added to library successfully...\n");
break;
case ISSUE_BOOK:
if(head==NULL)
{
printf(" No Books are available now...\n");
break;
}
else
{
IssueBook();
}
break;
case RETURN_BOOK:
if(issuehead==NULL)
{
printf(" No Books are issued...\n");
break;
}
else
{
ReturnBook();
}
break;
case DISPLAY_BOOKS:
DisplayBooks(head);
DisplayBooks(issuehead);
printf("\n");
break;
case SORT_BOOKS:
if(head==NULL)
{
printf(" No Books to sort...\n");
break;
}
SortBooks();
break;
case DISPLAY_BOOK_SUBJECTWISE:
if(head==NULL)
{
printf(" No Books to display...\n");
break;
}
DisplaySubjectWise(head);
break;
}
}
AddBooksToFile();
AddIssuesToFile();
FreeList();
return 0;
}
for your reference

C programming. File I/O, Link List and Struct

I have an assignment that requires me to edit a C program provided to me so that it can read from a text document where each line looks like:
int%char%char%Double%int%int%int
with any number of lines and an empty line at the end of the file.
This text file is passed to this program:
#include <stdlib.h>
#include <stdio.h>
struct node{
int element;
struct node * next;
};
// node structure
struct node * head = NULL; // head node
void add_node(int num) {
if (head == NULL){
head = (struct node *) malloc(sizeof(struct node));
head->element = num;
}
else{
struct node * p = head;
while(p->next != NULL)
p = p->next;
p->next = (struct node *) malloc(sizeof(struct node));
p->next->element = num;
}
}
void print_list() {
struct node * p = head;
while(p != NULL){
printf("%d ", p->element);
p = p->next;
}
}
void free_list() {
struct node * p = head;
while(head != NULL){
p = head->next;
free(head);
head = p;
}
}
int main(int argc, char const *argv[]) {
int n, i;
for (i = 0; i < 10; i++) {
scanf("%d", &n);
add_node(n);
}
print_list();
free_list();
return 0;
}
I need to edit this program to include the 7 fields from the file (ID, Category, Detail, Amount, Year, Month, Day) in the struct node. Then have it read from the text file (File_name.txt for now) add the fields without the % separator between them in the struct node, and then print them out in order as such (RecordID: (ID) Category: (category) Amount: $(amount) Date: (Month)-(Day)-(Year) Detail: (detail)) and free all pointers before the program is terminated. I don't expect you all to do the assignment for me, its just that I have no idea how C programming works and I need to do this so if anyone can help point me in the right direction on how to go about this it would be much appreciated.
From what I see.
You'd be having to Create a struct of your own with specified variables from the file.
Read every line and intelligently parse them... the function strtok should do be able to do this in C.
Extract variable to store in created struct using a function which should not be too hard to write
And the rest you can or should be able to take care of
This might have not been as useful as you hope would buh you can try to make me understand so I can help do better
This should get you started on the right path:
int main(int argc, char const *argv[]) {
char filename[100];
printf("Enter the name of the file: ");
/*stdin is a FILE pointer to standard input */
fgets(filename, 100, stdin);
/*Now you open the file for reading "r" means read mode*/
FILE *fp = fopen(filename, "r");
/*Basic error checking*/
if (!fp) {
perror("File opening failed");
return EXIT_FAILURE; /*This is macro defined in stdlib.h*/
}
int id, year, month, day;
char category, detail;
double amt;
/* Here the fun begins. Use fscanf*/
while(fscanf(fp, "ID(%d)%%Category(%c)%%Detail(%c)%%Amount(%lf)%%Year(%d)%%Month(%d)%%Day(%d)",
&id, &category, &detail, &amt, &year, &month, &day) == 7) {
/* Do what ever you want with those values - create a node or something*/
}
/* Finally close the file */
fclose(fp);
return 0;
}
Remember that each time through the loop, the variables change.

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