Scanf Validation - c

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

Related

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

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

Save structs in a file

I'm doing a program to save a list of contacts in a file whit structs. I've tried a lot of things but when I try go read the file to the program, it doesn't read anything.
This is my program without opening files and saving to files:
#include <stdio.h>
#include <stdlib.h>
struct agenda {
int idContacte;
char name[50];
struct agenda *nextContacte;
};
struct agenda *pAgenda;
struct agenda *pFirst = NULL;
struct agenda *pIndex;
void insert();
void show();
int main()
{
//Menu
int opc;
while(1){
printf("1.Insert Contact.\n");
printf("2.Show Contacts.\n");
printf("3.Exit\n");
scanf("%d", &opc);
switch(opc){
case 1:
insert();
break;
case 2:
show();
break;
case 3:
return 0;
}
}
}
void insert(){
pAgenda = (struct agenda *)malloc(sizeof(struct agenda));
printf("Insert ID: ");
scanf("%d", &pAgenda->idContacte);
printf("Insert the name: ");
scanf("%s", pAgenda->name);
printf("\n");
if (pFirst==NULL || pAgenda->idContacte < pFirst->idContacte)
{
pAgenda->nextContacte=pFirst;
pFirst=pAgenda;
}
else if (pAgenda->idContacte > pFirst->idContacte){
pIndex=pFirst;
while(pIndex->nextContacte && pIndex->nextContacte->idContacte < pAgenda->idContacte)
{
pIndex = pIndex->nextContacte;
}
pAgenda->nextContacte = pIndex->nextContacte;
pIndex->nextContacte = pAgenda;
}
}
void show(){
pIndex = pFirst;
while(pIndex && pIndex->idContacte <= 100) {
printf("\nID: %d", pIndex->idContacte);
printf("\nNAME: %s", pIndex->name);
printf("\n\n");
pIndex = pIndex->nextContacte;
}
}
Can you help me how can I get contact at start of the program from a file, and then when insert a contact, rewrite the file and insert all the contacts again in the file?
When you end your program you should do the following
int save_list(struct agenda *head) {
FILE *save = fopen("file.name", "wb");
if(!save) return -1;
while(head) {
fwrite(head, sizeof *head - sizeof head, 1, save);
head = head->nextContacte;
}
fclose(save);
/* Somebody would free list memory after this function execution */
return 0;
}
At the start of your program you should do the following
struct agenda *restore_list() {
FILE *restore= fopen("file.name", "rb");
struct agenda *head = NULL;
struct agenda *cur = head;
struct agenda temp;
if(!restore) return head;
while( fwrite(&temp, sizeof temp - sizeof head, 1, save) == 1) {
struct agenda *node = malloc( sizeof(struct agenda) );
if(NULL == node) {
/* Handle out of memory error here, free list */
return NULL;
}
*node = temp;
node->nextContacte = NULL;
if(head) {
cur->nextContacte = node;
cur = node;
} else {
/* First node */
head = cur = node;
}
}
fclose(restore);
return head;
}

Having an issue with link lists in c

I am having problems with some code I have to add the option to input a person into my structure link list. I can add the person to the first node with an integer for an identifier but then when I come to add another it only asks for the integer not for the other details. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include "linkedlist.h" /* conatins structure definition */
/* Function Prototypes
Note that variable names have been removed as they are
not actually required - they are optional
*/
int fnTotalList(struct listnode *);
struct listnode *fnAddItem(struct listnode *, int);
void fnPrintList(struct listnode *);
int fnMenu(void);
struct listnode *fnRemoveEndItem(struct listnode *, int *);
struct listnode *fnRemoveStartItem(struct listnode *, int *);
void fnSearchList(struct listnode *, int);
int main(int argc, char *argv[])
{
struct listnode *ptrHead = NULL;
struct listnode *ptrTemp = NULL;
int nChoice = 0;
int nRun = 1;
int nItem = 0;
while(nRun)
{
nChoice = fnMenu();
switch(nChoice)
{
case 1: /* Add an item */
printf("Please enter an integer : ");
scanf("%d", &nItem);
ptrHead = fnAddItem(ptrHead,nItem);
break;
case 2: /* Print the list */
fnPrintList(ptrHead);
printf("The list total is %d\n", fnTotalList(ptrHead));
break;
case 3: /* Remove an end item */
ptrHead = fnRemoveEndItem(ptrHead, &nItem);
if(nItem == -9999)
printf("Nothing to remove - empty list\n\n");
else
printf("The removed value is %d\n\n", nItem);
break;
case 4: /* Remove a start item */
ptrHead = fnRemoveStartItem(ptrHead, &nItem);
if(nItem == -9999)
printf("Nothing to remove - empty list\n\n");
else
printf("The removed value is %d\n\n", nItem);
break;
case 5: /* Search the list */
printf("Please enter the search value : ");
scanf("%d", &nItem);
fnSearchList(ptrHead, nItem);
break;
case 6: /* Exit program */
nRun = 0; /* set to zero to stop the while loop */
break;
}
}
return 0;
}
struct listnode *fnAddItem(struct listnode *ptrH, int nNumber)
{
struct listnode *ptrTemp = NULL;
if(ptrH == NULL)
{
/* Special case - list empty */
ptrH = (struct listnode *)malloc(sizeof(struct listnode));
if(ptrH == NULL)
{
printf("Adding to empty list - malloc has failed\n");
exit(1);
}
/* malloc has worked - set values */
(*ptrH).nVal = nNumber;
printf("Please Enter First , Second & Last Name : ");
scanf("%s %s %s",(*ptrH).arcFirstName,(*ptrH).arcMiddleName,(*ptrH).arcLastName);
printf("Please Enter Sex M or F : ");
scanf("%s", (*ptrH).cSex);
printf("DOB - DDMMYYYY\n");
scanf("%i %i %i", &nD, &nM, &nY);
(*ptrH).strDOB.nDay=nD;
(*ptrH).strDOB.nMonth=nM;
(*ptrH).strDOB.nYear=nY;
ptrH->ptrNext = NULL; /* This is important as it signals
the last node within the list */
}
else
{
/* There are items already in the list
need to locate the end - use a while loop
to step through looking for ptrNext to
equal NULL */
ptrTemp = ptrH; /* Use a temp pointer */
while(ptrTemp->ptrNext != NULL)
{
/* As ptrNext has a value there is a node
hanging off it */
ptrTemp = ptrTemp->ptrNext;
}
/* ptrTemp is now pointing at the last node
within the list
Now, create a new node that "hangs off"
ptrNext within this last node */
ptrTemp->ptrNext = (struct listnode *)malloc(sizeof(struct listnode));
if(ptrTemp->ptrNext == NULL)
{
printf("Adding to end of list - malloc has failed\n");
exit(1);
}
ptrTemp->ptrNext->nVal = nNumber;
ptrTemp->ptrNext->ptrNext = NULL;
}
return ptrH; /* This is really only needed when adding the first item
to the list - but have to do it in all cases to avoid
error messages */
}
int fnMenu(void)
{
int nChoice;
printf("Choices menu\n\n");
printf("1.\tAdd an item\n");
printf("2.\tPrint list\n");
printf("3.\tRemove an end item\n");
printf("4.\tRemove a start item\n");
printf("5.\tSearch for a value\n");
printf("6.\tQuit\n\n");
printf("Please enter a choice :");
scanf("%d", &nChoice);
return nChoice;
}
void fnPrintList(struct listnode *ptrH)
{
if(!ptrH)
{
printf("\n\n\tEmpty list\n");
}
else
{
while(ptrH)
{
printf("%d\n", ptrH->nVal);
ptrH = ptrH->ptrNext;
}
printf("\nEnd of list\n\n");
}
}
struct listnode *fnRemoveEndItem(struct listnode *ptrH, int *ptrNum)
{
/* There are two special cases ...
1. When the list is empty
2. When there is only one node within the list
*/
struct listnode *ptrTemp = NULL;
if(!ptrH)
{
/* The list is empty */
*ptrNum = -9999; /* A value to signal empty list */
}
else if(!ptrH->ptrNext)
{
/* There is only one node in the list
as ptrNext within the first node
is NULL
*/
*ptrNum = ptrH->nVal;
free(ptrH); /* This releases the memory allocated
by malloc() back to the heap */
ptrH = NULL; /* As this was the last item to remove
need to return NULL so that ptrHead
is set to NULL */
}
else
{
/* There are more than one nodes in the list,
need to step through to find the last but
one node
*/
ptrTemp = ptrH;
while(ptrTemp->ptrNext->ptrNext)
{
ptrTemp = ptrTemp->ptrNext;
}
/* ptrTemp is now pointing to the last but
one node so can delete the last one
*/
*ptrNum = ptrTemp->ptrNext->nVal;
free(ptrTemp->ptrNext);
ptrTemp->ptrNext = NULL; /* Set to NULL as this is
now the last node
*/
}
return ptrH;
}
struct listnode *fnRemoveStartItem(struct listnode *ptrH, int *ptrNum)
{
struct listnode *ptrTemp = NULL;
if(!ptrH)
{
/* Empty list */
*ptrNum = -9999;
return ptrH;
}
else
{
ptrTemp = ptrH->ptrNext;
*ptrNum = ptrH->nVal;
free(ptrH);
return ptrTemp;
}
}
void fnSearchList(struct listnode *ptrH, int nSearchVal)
{
struct listnode *ptrTemp = ptrH;
int nCount = 0;
if(!ptrH)
{
/* Empty List */
printf("\n\nEmpty List \n\n");
}
else
{
while(ptrTemp->ptrNext)
{
if(ptrTemp->nVal == nSearchVal)
{
printf("The value %d has been located\n", ptrTemp->nVal);
nCount++;
}
ptrTemp = ptrTemp->ptrNext;
}
if(!nCount)
printf("\t\tValue not found within the list\n");
else
printf("\t\tA total of %d were found\n", nCount);
}
printf("The list totals %d\n", fnTotalList(ptrH));
}
int fnTotalList(struct listnode *ptrH)
{
struct listnode *ptrTemp = ptrH;
int nTotal = 0;
if(ptrTemp)
{
while(ptrTemp)
{
nTotal += ptrTemp->nVal;
ptrTemp = ptrTemp->ptrNext;
}
}
return nTotal;
}
In the function fnAddItem, there are two cases, one is when the pointer is NULL, that is List Empty and you are adding the first node correctly.
Another one is when there is already some node, you are traversing to the last and adding one node there, but did not ask for input. Thats why for 2nd node onwards you don't have other details.
After you malloc in the else part, you have to take input as you did in the if part.
struct listnode *fnAddItem(struct listnode *ptrH, int nNumber)
{
struct listnode *ptrTemp = NULL;
if(ptrH == NULL)
{
/* Special case - list empty */
ptrH = (struct listnode *)malloc(sizeof(struct listnode));
if(ptrH == NULL)
{
printf("Adding to empty list - malloc has failed\n");
exit(1);
}
/* malloc has worked - set values */
(*ptrH).nVal = nNumber;
printf("Please Enter First , Second & Last Name : ");
scanf("%s %s %s",(*ptrH).arcFirstName,(*ptrH).arcMiddleName,(*ptrH).arcLastName);
printf("Please Enter Sex M or F : ");
scanf("%s", (*ptrH).cSex);
printf("DOB - DDMMYYYY\n");
scanf("%i %i %i", &nD, &nM, &nY);
(*ptrH).strDOB.nDay=nD;
(*ptrH).strDOB.nMonth=nM;
(*ptrH).strDOB.nYear=nY;
ptrH->ptrNext = NULL; /* This is important as it signals
the last node within the list */
}
else
{
/* There are items already in the list
need to locate the end - use a while loop
to step through looking for ptrNext to
equal NULL */
ptrTemp = ptrH; /* Use a temp pointer */
while(ptrTemp->ptrNext != NULL)
{
/* As ptrNext has a value there is a node
hanging off it */
ptrTemp = ptrTemp->ptrNext;
}
/* ptrTemp is now pointing at the last node
within the list
Now, create a new node that "hangs off"
ptrNext within this last node */
ptrTemp->ptrNext = (struct listnode *)malloc(sizeof(struct listnode));
if(ptrTemp->ptrNext == NULL)
{
printf("Adding to end of list - malloc has failed\n");
exit(1);
}
/* malloc has worked - set values */
ptrTemp->ptrNext->nVal = nNumber;
printf("Please Enter First , Second & Last Name : ");
scanf("%s %s %s",ptrTemp->ptrNext->arcFirstName,ptrTemp->ptrNext->arcMiddleName,ptrTemp->ptrNext->arcLastName);
printf("Please Enter Sex M or F : ");
scanf("%s", ptrTemp->ptrNext->cSex);
printf("DOB - DDMMYYYY\n");
scanf("%i %i %i", &nD, &nM, &nY);
ptrTemp->ptrNext->strDOB.nDay=nD;
ptrTemp->ptrNext->strDOB.nMonth=nM;
ptrTemp->ptrNext->strDOB.nYear=nY;
ptrTemp->ptrNext->ptrNext = NULL; /* This is important as it signals
the last node within the list */
}
return ptrH; /* This is really only needed when adding the first item
to the list - but have to do it in all cases to avoid
error messages */
}
It is a bad design though, you should malloc once, take the inputs and fill the structure and then add it in appropriate place to the list. In that way you can omit a huge part of redundant code in the function.

Library is empty then seg fault

Hey guys im doing a project and I keep getting "Library is empty" and then a seg fault, running trough this with gdb its telling me that the error is in my count_list function. But i cannot seem to figure out why? any tips would be appreciated its killing me to be so close to finished and get hung up on this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Assume max char count in file */
#define MAX 20
/* library struct - DO NOT CHANGE */
typedef struct library
{
char *genre;
char *band;
char *album;
float rating;
struct library *next;
}Library;
/* Function Prototypes - DO NOT CHANGE */
Library *Read_File(FILE *);
void Print(Library *);
Library *Create_List(Library *, Library *);
Library *Create_Album(char *, char *, char *, float);
Library *Merge(Library *, Library *);
int Count_List(Library *);
void Split_List(Library *, Library **, Library **);
Library *Merge_Sort(Library *);
Library *Delete_Genre(Library *);
void Free_Entry(Library *);
Library *Clean(Library *);
/* MAIN
* Error check file parameter
* Call Read_File to fill our list
* Print our list
* Merge Sort the linked list (by genre)
* Delete a genre
* Free the list
*/
int
main(int argc, char **argv)
{
if(argc != 2)
{
printf("Not enough arguments.\n");
return 0;
}
FILE *fp = NULL;
if((fp = fopen(argv[1], "r")) == NULL)
{
printf("File can not be opened.\n");
return 0;
}
Library *Head = NULL;
Head = Read_File(fp);
Print(Head);
Merge_Sort(Head);
Print(Head);
Head = Delete_Genre(Head);
Print(Head);
Head = Clean(Head);
Print(Head);
return 0;
}
/* Clean()
* Delete the linked list, recursively
*/
Library *
Clean(Library *Head)
{
if(Head) return NULL;
Library *Tmp = Head->next;
Free_Entry(Head);
Clean(Tmp->next);
}
/* Free_Entry()
* wrapper function to free a struct Library
*/
void
Free_Entry(Library *Entry)
{
free(Entry);
}
/* Delete_Genre()
* Deletes a genre inputted by user
* Logic:
* prompt user for genre input
* traverse list deleting all structs that contain the genre
*/
Library *
Delete_Genre(Library *Head)
{
if(!Head)
{
printf("List Empty.\n");
return NULL;
}
char *input = malloc(MAX * sizeof(char *));
Library *Current = Head;
Library *Tail = NULL;
printf("Which genre would you like to delete?\n");
scanf("%s", input);
while(Current)
{
if(strcmp(Current->genre, input))
{
if(Current = Head)
{
Head = Head->next;
Free_Entry(Current);
Current = Head;
}
else
Tail->next = Current->next;
}
else
Current = Current->next;
}
}
/* Read_File()
* Open file fp
* Create a struct from information in text file
* Link our list with newly created struct
*/
Library *
Read_File(FILE *fp)
{
Library *Head, *Entry;
Head = Entry = NULL;
char *genre, *band, *album;
float rating;
while(1)
{
fscanf(fp, "%s %s %s %f", &genre, &band, &album, &rating);
if(!feof(fp))
break;
Entry = Create_Album(genre, band, album, rating);
Head = Create_List(Entry, Head);
}
return Head;
}
/* Print()
* Print the linked list
*/
void
Print(Library *Head)
{
if(!Head)
{
printf("Library is empty.\n");
return;
}
while(Head)
{
printf("%20s %20s %20s %20.2f \n",
Head->genre, Head->band, Head->album, Head->rating);
Head = Head->next;
}
printf("\n\n");
//return Head;
}
/* Create_Album
* Create a struct and assign the given args to it as appropriate
*/
Library *
Create_Album(char *genre, char *band, char *album, float rating)
{
Library *Entry = malloc(sizeof(Library));
strcpy(Entry->genre, genre);
strcpy(Entry->band, band);
strcpy(Entry->album, album);
Entry->rating = rating;
Entry->next = NULL;
return Entry;
}
/* Create_List()
* Push Entry onto our List
*/
Library *
Create_List(Library *Head, Library *Entry)
{
if(!Head)
return Entry;
Entry->next = Head;
return Entry;
}
/* Merge_Sort()
* Recursively split our list between Left and Right
* Merge our Left and Right lists
*/
Library *
Merge_Sort(Library *Head)
{
Library *Tmp = Head;
Library *Left, *Right, *Result;
Left = Right = Result = NULL;
int count = Count_List(Head);
if(count = 1)
return Tmp;
Left = Merge_Sort(Left);
Right = Merge_Sort(Right);
Result = Merge(Left, Right);
return Result;
}
/* Split_List()
* split our list in half
*/
void
Split_List(Library *Head, Library **Left, Library **Right)
{
int size = Count_List(Head);
int i;
Library *Tmp = Head;
*Left = Head;
for(i=1; i<size/2; ++i)
Tmp=Tmp->next;
*Right = Tmp->next;
Tmp->next = NULL;
}
/* Merge()
* Merge two linked lists Left and Right together in sorted order
*/
Library *
Merge(Library *Left, Library *Right)
{
Library *Result, *Tmp;
Result = Tmp = NULL;
if(strcmp(Left->genre, Right->genre) <= 0)
{
Result = Left;
Left = Left->next;
}
else
{
Result = Right;
Right = Right->next;
}
Tmp = Result;
while(Left != NULL && Right != NULL)
{
if(Left != NULL && Right!= NULL)
{
if (strcmp(Left->genre, Right->genre) <= 0)
{
Tmp->next = Left;
Left = Left->next;
}
else
{
Tmp->next = Right;
Right = Right->next;
}
Tmp = Tmp->next;
}
}
return Result;
}
/* Count_List()
* Count the number of elements in a linked list
*/
int
Count_List(Library *Head)
{
Library *Tmp = Head;
int count = 0;
while(Tmp->next != NULL)
{
count++;
Tmp = Tmp->next;
}
}
Observations,
Count_List() should count each element on list, your version only counts starting at the second item on the list. And it should always return an int,
int
Count_List(Library *Head)
{
int count = 0;
Library *Tmp = Head;
if(!Tmp) return(count);
while(Tmp != NULL)
{
count++;
Tmp = Tmp->next;
}
return(count);
}
Inside Read_File() you call Create_List(Entry,Head), but your function signature for Create_List(Head,Entry); which do you intend? Probably (Head,Entry). Use fgets and sscanf to Read_File,
Library *
Read_File(FILE *fp)
{
Library *Head, *Entry;
Head = Entry = NULL;
char genre[100], band[100], album[100];
float rating;
char line[100];
while(fgets(line,sizeof(line),fp)
{
sscanf(line,"%s %s %s %f", genre, band, album, &rating);
Entry = Create_Album(genre, band, album, rating);
Head = Create_List(Head,Entry);
}
return Head;
}
Looking at Create_List(), you seem to be implementing the List as a stack (push Entry onto head of list),
Library *
Create_List(Library *Head, Library *Entry)
{
if(!Head)
return Entry;
Entry->next = Head;
return Entry;
}
Create_Album() needs to check for successful malloc before assigning values to member variables,
Library *Entry=NULL;
if( !(Entry=(Library*)malloc(sizeof(Library))) )
{
printf("error creating album\n");fflush(stdout);
return Entry;
}
Speaking of Library struct, you declare the members genre, band, album as pointers, but you need space to copy memory, example,
typedef struct library
{
char genre[50];
char band[50];
char album[50];
float rating;
struct library *next;
}Library;
My suggestion would be to build constructor and destructor functions LibraryNew, LibraryDel.
Check for (argc<2) arguments (your message says not enough, instead of need 2,
if(argc < 2)
{
printf("Not enough arguments.\n");
return 0;
}
And that fixes the biggest problems,
./library music.x 2
line:Rock Antrax Party 1.2
Rock,Antrax,Party,1.200000
Rock,Antrax,Party,1.200000
added: Rock,Antrax,Party,1.200000
Rock Antrax Party 1.20
Rock Antrax Party 1.20
Which genre would you like to delete?
your function doesn't return a number (so some unexpected value would be really returned to the caller). you need to add the return statement.
int Count_List(Library *Head)
{
Library *Tmp = Head;
int count = 0;
while(Tmp->next != NULL)
{
count++;
Tmp = Tmp->next;
}
}
some other issues you would get if you turn on the warning option of your compiler:
if(Current = Head) would you expect == ?
fscanf(fp, "%s %s %s %f", &genre, &band, &album, &rating);
should be
fscanf(fp, "%s %s %s %f", genre, band, album, &rating);
if(count = 1) // == ?
Delete_Genre() /Clean() don't have return
You forgot to actually return something from Count_List.
int Count_List(Library *Head)
{
Library *Tmp = Head;
int count = 0;
while(Tmp->next != NULL)
{
count++;
Tmp = Tmp->next;
}
return count;
}

fprintf output is returning unpredictable results

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

Resources