![]() |
| | #1 |
| Just because Join Date: Jan 2002
Posts: 2,502
| Contest Results - May 27, 2002 I'll begin by posting our respective opinions. (nvoigt, prelude, and me). then comes the code, then comes my last word. To a moderator, sticky this, please? For just a couple days. Also, unsticky the Sign Up thread. Last edited by ygfperson; 05-27-2002 at 06:45 PM. |
| ygfperson is offline |
| | #2 | ||
| Just because Join Date: Jan 2002
Posts: 2,502
| Nvoigt's opinion: Cicero: Quote:
Quote:
| ||
| ygfperson is offline |
| | #3 | ||
| Just because Join Date: Jan 2002
Posts: 2,502
| Prelude's opinion: Cicero: Quote:
Quote:
| ||
| ygfperson is offline |
| | #4 | ||
| Just because Join Date: Jan 2002
Posts: 2,502
| ygfperson's opinion: cicero's: Quote:
Quote:
| ||
| ygfperson is offline |
| | #5 |
| Just because Join Date: Jan 2002
Posts: 2,502
| cicero: Code: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
int total=0;
struct
{
char*name;
char*number;
}list[100];
void add_a_number()
{
int i;
for(i=0;i<total;i++)
{
if(!strcmp(list[i].name,"empty"))
{
printf("Type a name:");
gets((list[i].name=calloc(100,sizeof(char))));
printf("Type a phone number:");
gets((list[i].number=calloc(100,sizeof(char))));
}
}
printf("Type a name:");
gets((list[total].name=calloc(100,sizeof(char))));
printf("Type a phone number:");
gets((list[total].number=calloc(100,sizeof(char))));
total++;
}
void remove_a_number()
{
int i;
char*find;
printf("Type a name to remove:");
gets(find);
for(i=0;i<total;i++)
{
if(!strcmp(find,list[i].name))
{
strcpy(list[i].name,"empty");
strcpy(list[i].number,"empty");
}
}
}
void find_a_number()
{
int i;
char*find;
printf("Type a name to find:");
gets(find);
for(i=0;i<total;i++)
{
if(!strcmp(find,list[i].name))
{
printf("Item#%d\n",i);
printf("------\n");
printf("Name:%s\n",list[i].name);
printf("Number:%s\n",list[i].number);
printf("\n\n");
}
}
}
void list_all_numbers()
{
int i;
for(i=0;i<total;i++)
{
printf("Item#%d\n",i);
printf("------\n");
printf("Name:%s\n",list[i].name);
printf("Number:%s\n",list[i].number);
printf("\n\n");
}
}
int main()
{
char opt;
while(1)
{
printf("\t\t\tGod's Phonebook\n");
printf("\t\t\t---------------\n");
printf("\t\t\t1<- Add a number\n");
printf("\t\t\t2<- Remove a number\n");
printf("\t\t\t3<- Find a number\n");
printf("\t\t\t4<- List all numbers\n");
printf("\t\t\t5<- Quit\n");
scanf("%1[12345]%*c",&opt);
switch(opt)
{
case'1':
add_a_number();
break;
case'2':
remove_a_number();
break;
case'3':
find_a_number();
break;
case'4':
list_all_numbers();
break;
case'5':
exit(0);
break;
}
}
}
|
| ygfperson is offline |
| | #6 |
| Just because Join Date: Jan 2002
Posts: 2,502
| Hammer's: ioUtilities.c: Code: #include "main.h" /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: ioUtilities.c Contents: io_GetInt io_EnterToContinue io_GetYesNo io_GetLine io_WriteAllRecordsToFile io_WriteRecordToFile io_LoadAppConfig io_SaveAppConfig =============================================================================== */ static FILE *fp; /* =============================================================================== Function: ioLoadPhoneBookFromFile Args: Pointer to the node list Returns: Pointer to the node list. NULL Purpose: Loads the Record structs from the phone book file into the List =============================================================================== */ struct Node *io_LoadPhoneBookFromFile(struct Node *List) { struct Record rec, *recptr; struct Node *tmpListPtr; if ((fp = fopen(STR_FILENAME, "rb")) == NULL) { /* Failed to open database file */ printf("ERROR: Unable to open phone book file: %s\n", STR_FILENAME); return(List); } if (List) { /* List not empty, kill it before we start reloading */ (void)li_Traverse(List, free); List = li_Destroy(List); } while (fread(&rec, sizeof(struct Record), 1, fp) == 1) { if ((recptr = malloc(sizeof(struct Record))) == NULL) { /* Memory failure, don't do anymore */ perror("malloc"); break; } *recptr = rec; if ((tmpListPtr = li_Insert(List, recptr, rec_Compare)) == NULL) { printf("Error performing insert on list. Item not addded.\n"); free(recptr); /* throw record away */ } else { List = tmpListPtr; recptr->ID = gl_HighestID; recptr->Status = (unsigned char)0; } } (void)fclose(fp); gl_AppData.DataChanged = FALSE; return(List); } /* =============================================================================== Function: io_GetInt Args: maximum number for user to choose Returns: Number chosen, or -1 if x or X entered (for menu use) Notes: Assumes that 0 will never be a valid option, and will ask the user to re-enter. Purpose: Get an int from stdin (keyboard). =============================================================================== */ int io_GetInt(int Max) { int Input, len; char buffer[BUFSIZ]; for (;;) { if ((len = io_GetLine(buffer, BUFSIZ, stdin)) != 0) { if (len == 1 && (buffer[0] == 'x' || buffer[0] == 'X')) { /* Allow for xX to be entered, and return -1 */ Input = RC_BAD; break; } if ((Input = atoi(buffer)) != 0) { if (Input >= 1 && Input <= Max) { break; } } } printf("Invalid. Try again (1-%d, x to exit)>", Max); } return(Input); } /* =============================================================================== Function: io_EnterToContinue Args: None Returns: None Purpose: Simulates the good old DOS PAUSE =============================================================================== */ void io_EnterToContinue(void) { printf("---> Enter To Continue <---"); FLUSH_INPUT; } /* =============================================================================== Function: io_GetYesNo Args: String containing the prompt to be displayed Returns: TRUE if yY entered, FALSE if nN entered Purpose: Get a Y or N from stdin (keyboard) =============================================================================== */ bool_t io_GetYesNo(char *prompt) { int c; bool_t rc; for (;;) { printf("%s", prompt); c = getchar(); switch (c) { case 'y': case 'Y': rc = TRUE; break; case 'n': case 'N': rc = FALSE; break; default: if (c != '\n') FLUSH_INPUT; continue; } break; } if (c != '\n') FLUSH_INPUT; return(rc); } /* =============================================================================== Function: io_GetLine Args: buffer to place the text length of the buffer file pointer to read from. Returns: Chars read and placed into buffer Purpose: Same as fgets() but does not keep the newline character =============================================================================== */ int io_GetLine(char *buffer, int maxlen, FILE *fp) { int len = 0, c; char *ptr = buffer; char *endptr = buffer + maxlen - 1; if (fp != NULL) { while ((c = fgetc(fp)) != EOF) { if (c == '\n') break; *ptr = c; ptr++; len++; if (ptr == endptr) break; } } *ptr = '\0'; return(len); } /* =============================================================================== Function: io_WriteAllRecordsToFile Args: Pointer to list Returns: Number of items written. Purpose: Save all Record structs in the List to a disk file =============================================================================== */ int io_WriteAllRecordsToFile(struct Node *List) { unsigned char status = ST_DELETED; if ((fp = fopen(STR_FILENAME, "wb")) == NULL) { /* Failed to open database file */ printf("ERROR: Unable to open phone book file: %s\n", STR_FILENAME); return(0); } /* First delete dead records from the list, then write them to disk */ gl_AppData.MainList = li_DeleteNodeAndData(gl_AppData.MainList, &status, rec_CompareStatus); (void)li_Traverse(List, io_WriteRecordToFile); (void)fclose(fp); gl_AppData.DataChanged = FALSE; return(gl_HighestID); } /* =============================================================================== Function: io_WriteRecordToFile Args: Pointer to record structure to be written. Returns: Nothing Purpose: Sub-function to write a single Record struct to disk =============================================================================== */ void io_WriteRecordToFile(void *ptr) { struct Record *rec = ptr; if (rec->Status & ST_DELETED) return; /* Don't save deleted records */ if (fp == NULL) { fprintf(stderr, "ERROR: Attempting to write to unopened file\n"); return; } if (fwrite(rec, sizeof(struct Record), 1, fp) != 1) perror("WriteRecordToFile"); } /* =============================================================================== Function: io_LoadAppConfig Args: None Returns: Nothing Purpose: Loads the appconfig structure from disk =============================================================================== */ void io_LoadAppConfig(void) { FILE *myfp; struct appconfig tmpcfg; if ((myfp = fopen(STR_CFG_FILENAME, "rb")) == NULL) return; if (fread(&tmpcfg, sizeof(struct appconfig), 1, myfp) == 1) gl_AppCfg = tmpcfg; (void)fclose(myfp); } /* =============================================================================== Function: io_SaveAppConfig Args: None Returns: Nothing Purpose: Saves the appconfig structure to disk =============================================================================== */ void io_SaveAppConfig(void) { FILE *myfp; if ((myfp = fopen(STR_CFG_FILENAME, "wb")) == NULL) return; if (fwrite(&gl_AppCfg, sizeof(struct appconfig), 1, myfp) != 1) perror (STR_CFG_FILENAME); (void)fclose(myfp); } Code: #include "main.h" /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: ListUtilities.c Contents: li_Create nd_Create nd_Destroy li_Traverse li_Insert li_Destroy li_GetDataPtrByID li_DeleteNodeAndData li_Count =============================================================================== */ /* =============================================================================== Function: li_Create Args: None Returns: NULL pointer. Purpose: Dummy function to start off a list. =============================================================================== */ struct Node *li_Create(void) { return (NULL); } /* =============================================================================== Function: nd_Create Args: A void ptr to the data to be referenced (A record). Returns: Pointer to new node, ready for insertion into the tree. NULL if malloc fails Purpose: Creates a single node, containing a pointer to some data (Record) =============================================================================== */ struct Node *nd_Create(void *ptr, struct Node *NextNode) { struct Node *newptr; if ((newptr = malloc(sizeof(struct Node))) == NULL) { perror("nd_create, malloc"); return (NULL); } newptr->DataPtr = ptr; newptr->Next = NextNode; return(newptr); } /* =============================================================================== Function: nd_Destroy Args: A pointer to a node to be free()'d Returns: Nothing Purpose: The data the node points to is not freed by the function, only the node itself is. =============================================================================== */ void nd_Destroy(struct Node *ptr) { free(ptr); } /* =============================================================================== Function: li_Traverse Args: A pointer to the first node in the list A pointer to a function used to process each node. Returns: Number of Nodes processed Purpose: Traverse the list, sending each nodes data to a function =============================================================================== */ int li_Traverse(struct Node *List, FPTR_Action fptr_Action) { struct Node *Current = List; int Count = 0; while (Current) { fptr_Action(Current->DataPtr); Count++; Current = Current->Next; } return (Count); } /* =============================================================================== Function: li_Insert Args: A pointer to the first node in the list A pointer to the data to be referenced by the node A pointer to a function to be used for comparison. Returns: Pointer to the first node in the list NULL is nd_Create fails. Notes: The caller should use caution to ensure the List pointer is not lost if this function returns NULL. Purpose: Inserts a new node into the list in the correct sorted order. =============================================================================== */ struct Node *li_Insert(struct Node *List, void *NewData, FPTR_Compare fptr_Compare) { struct Node *newptr; struct Node *Current = List; struct Node *Previous = NULL; while (Current) { if (fptr_Compare(Current->DataPtr, NewData) > 0) break; /* Found the entry point */ Previous = Current; Current = Current->Next; } if ((newptr = nd_Create(NewData, Current)) == NULL) { /* malloc failure in nd_Create */ return (NULL); } if (Previous == NULL) List = newptr; else Previous->Next = newptr; gl_HighestID++; return (List); } /* =============================================================================== Function: li_Destroy Args: A pointer to the first node in the list Returns: Nothing Purpose: This runs through the list, destroying nodes. It does not free the data that each node points to. =============================================================================== */ struct Node *li_Destroy(struct Node *List) { struct Node *Current = List; struct Node *tmp; while (Current) { tmp = Current->Next; nd_Destroy(Current); Current = tmp; } gl_HighestID = 0; return (NULL); } /* =============================================================================== Function: li_GetDataPtrByID Args: A pointer to the first node in the list An int for the ID field. Returns: Pointer to a Record struct, allowing direct access by the caller Purpose: Gets the address of a Record structure, as *owned* by the list. =============================================================================== */ struct Record *li_GetDataPtrByID(struct Node *List, int ID) { struct Node *Current = List; struct Record *rec; while (Current) { rec = Current->DataPtr; if (rec->ID == ID) break; Current = Current->Next; } return ((Current)?Current->DataPtr:NULL); } /* =============================================================================== Function: li_DeleteNodeAndData Args: A pointer to the first node in the list A pointer to the data to be referenced by the node A pointer to a function to be used for comparison. Returns: Pointer to the first node in the list NULL is nd_Create fails. Notes: The caller should use caution to ensure the List pointer is not lost if this function returns NULL. Purpose: As the function name says! =============================================================================== */ struct Node *li_DeleteNodeAndData(struct Node *List, void *CompareData, FPTR_CompareDelete fptr_Compare) { struct Node *Current = List; struct Node *Previous = NULL; struct Node *tmp; while (Current) { if (fptr_Compare(Current->DataPtr, CompareData) > 0) { /* Found a node to remove */ if (Current == List) List = Current->Next; tmp = Current->Next; if (Previous) { Previous->Next = tmp; } free (Current->DataPtr); free (Current); Current = tmp; } else { /* No match, move on */ Previous = Current; Current = Current->Next; } } return (List); } /* =============================================================================== Function: li_Count Args: A pointer to the first node in the list Returns: Number of Nodes in list Purpose: Counts the nodes. =============================================================================== */ int li_Count(struct Node *List) { struct Node *Current = List; int Count = 0; while (Current) { Count++; Current = Current->Next; } return (Count); } /* =============================================================================== Function: li_Sort Args: A pointer to the first node in the list Function pointer used for comparisons Returns: None Purpose: Sorts the nodes, using the given function. =============================================================================== */ void li_Sort(struct Node *List, FPTR_Compare fptr_Compare) { struct Node *Current, *Next; void *Temp; bool_t StillDoingSwaps = TRUE; while (StillDoingSwaps == TRUE) { StillDoingSwaps = FALSE; Current = List; while (Current) { if ((Next = Current->Next) != NULL) { if (fptr_Compare (Current->DataPtr, Next->DataPtr) > 0) { Temp = Current->DataPtr; Current->DataPtr = Next->DataPtr; Next->DataPtr = Temp; StillDoingSwaps = TRUE; } } Current = Next; } } } Code: #include "main.h" /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: main.c Contents: Global variables main =============================================================================== */ /* =============================================================================== The following are the only global variables =============================================================================== */ int gl_HighestID; struct appdata gl_AppData; struct appconfig gl_AppCfg; /* =============================================================================== Function: main Args: From command line. - This can be empty. In this case an interactive menu is loaded. - or if present, it is taken to represent search criteria. In this case, the database is loaded, searched and the relevant records displayed, then the application terminates. Returns: An int of course! (Always 0) Don't void your main! =============================================================================== */ int main(int argc, char *argv[]) { struct Node *tmpListPtr; int i; /* * Load and setup app config */ memset (&gl_AppData, 0, sizeof(struct appdata)); memset (&gl_AppCfg, 0, sizeof(struct appconfig)); io_LoadAppConfig(); if (gl_AppCfg.LinesPerDisplay <= 0 || gl_AppCfg.LinesPerDisplay > MAX_LINES_PER_PAGE) gl_AppCfg.LinesPerDisplay = DEF_LINES_PER_PAGE; /* * Create and load the link list of Record structs */ gl_AppData.MainList = li_Create(); if ((tmpListPtr = io_LoadPhoneBookFromFile(gl_AppData.MainList)) == NULL) printf("No data loaded from phone book.\n"); else gl_AppData.MainList = tmpListPtr; /* * If we have command line args, use them as search criteria, then terminate */ if (argc > 1) { gl_AppData.SearchField = RECF_NAME; for (i = 1; i < argc; i++) { strncpy(gl_AppData.SearchText, argv[i], MAXL_NAME+1); (void)li_Traverse (gl_AppData.MainList, rec_SearchAndPrint); } (void)li_Traverse (gl_AppData.MainList, free); (void)li_Destroy (gl_AppData.MainList); return (0); } /* * Start interactive session, go into menu display until the user exits */ printf ("---> Auto-Save is %s <---\n", (gl_AppCfg.AutoSave)?"On":"Off"); ui_DisplayMenu(MainMenu); /* * Check if we need to save changes, then destory the memory we alloc'd earlier */ if (gl_AppData.DataChanged) { ui_Save(NULL); } (void)li_Traverse (gl_AppData.MainList, free); (void)li_Destroy (gl_AppData.MainList); /* * Finally save the app config for next time */ io_SaveAppConfig(); return (0); } Code: #include "main.h" /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: RecordUtilities.c Contents: rec_Compare rec_CompareID rec_CompareStatus rec_PrintShort rec_PrintLong rec_SearchAndPrint =============================================================================== */ /* =============================================================================== Function: rec_Compare Args: 2 pointers to Record struct's to be compared Returns: <0 if p1 < p2 >0 if p1 > p2 0 if p1 = p2 Purpose: Compares 2 Record struct's by the element specified in gl_AppCfg.SortField =============================================================================== */ int rec_Compare(const struct Record *rec1, const struct Record *rec2) { char Fields[2][MAXL_FIELD+1]; int len[2], i, j; /* * Set up strings for case insensative compare */ if (gl_AppCfg.SortField == RECF_ID) return ((rec1->ID > rec2->ID)); strncpy (Fields[0], rec_GetFieldPointer(rec1, gl_AppCfg.SortField), MAXL_FIELD+1); strncpy (Fields[1], rec_GetFieldPointer(rec2, gl_AppCfg.SortField), MAXL_FIELD+1); len[0] = strlen(Fields[0]); len[1] = strlen(Fields[1]); for (i = 0; i < 2; i++) { for (j = 0; j < len[i]; j++) { if (isupper(Fields[i][j])) Fields[i][j] = tolower(Fields[i][j]); } } return (strcmp(Fields[0], Fields[1])); } /* =============================================================================== Function: rec_CompareID Args: Pointer to Record struct's to be compared with ID Returns: >0 if match 0 if no match Purpose: Compares 2 Record structs by the ID element =============================================================================== */ int rec_CompareID(const struct Record *rec, void *ptr) { int *idptr = ptr; if (rec->ID == *idptr) return (1); else return (0); } /* =============================================================================== Function: rec_CompareStatus Args: Pointer to Record struct's to be compared with Status field Returns: >0 if match 0 if no match Purpose: Compares 2 Record structs by the Status element =============================================================================== */ int rec_CompareStatus(const struct Record *rec, void *ptr) { unsigned char *statusptr = ptr; if (rec->Status & *statusptr) /* bitwise comparison */ return (1); else return (0); } /* =============================================================================== Function: rec_PrintShort Args: A pointer to a Record struct to be printed Returns: Nothing Purpose: Print only a couple of fields from a single Record struct =============================================================================== */ void rec_PrintShort(void *ptr) { struct Record *rec = ptr; printf("%s%3d> %-20s %s %s\n",(rec->Status & ST_DELETED)?"Deleted>":"", rec->ID, rec->Name, rec->PhoneNum1, rec->EmailAddr); } /* =============================================================================== Function: rec_PrintLong Args: A pointer to a Record struct to be printed Returns: Nothing Purpose: Prints all fields from a single Record struct =============================================================================== */ void rec_PrintLong(void *ptr) { struct Record *rec = ptr; printf ("Record ID:\t%d %s\n", rec->ID, (rec->Status & ST_DELETED)?"(Deleted)":""); printf ("Name:\t\t%s\n", rec->Name); printf ("1st Phone:\t%s\n", rec->PhoneNum1); printf ("2nd Phone:\t%s\n", rec->PhoneNum2); printf ("3rd Phone:\t%s\n", rec->PhoneNum3); printf ("Address:\t%s\n", rec->AddrLine1); if (rec->AddrLine2[0] != '\0') printf (" \t%s\n", rec->AddrLine2); if (rec->AddrLine3[0] != '\0') printf (" \t%s\n", rec->AddrLine3); if (rec->AddrLine4[0] != '\0') printf (" \t%s\n", rec->AddrLine4); if (rec->AddrLine5[0] != '\0') printf (" \t%s\n", rec->AddrLine5); printf ("Email Addr:\t%s\n", rec->EmailAddr); printf ("Misc Data:\t%s\n", rec->Misc); } /* =============================================================================== Function: rec_SearchAndPrint Args: A pointer to a Record struct to be printed (if criteria meet) Returns: Nothing Purpose: Called during the list traversal process, this function will search a specified field for the search string stored in the global struct gl_AppData.SearchText =============================================================================== */ void rec_SearchAndPrint(void *ptr) { struct Record *rec = ptr; char *sptr, *tmp; int len, i; char rectext[MAXL_FIELD+1]; if (gl_AppData.SearchField == RECF_DUMMY) sptr = NULL; else sptr = rec_GetFieldPointer(rec, gl_AppData.SearchField); if (sptr) { strncpy(rectext, sptr, MAXL_FIELD+1); len = strlen(rectext); /* Convert data to lower case to allow for case insensative search */ for (i = 0, tmp = rectext; i < len; i++, tmp++) {if (isupper(*tmp)) *tmp = tolower(*tmp);} if (!strstr(rectext, gl_AppData.SearchText)) return; } rec_PrintShort(ptr); gl_AppData.LinesDisplayedSoFar++; if (gl_AppData.LinesDisplayedSoFar == gl_AppCfg.LinesPerDisplay) { io_EnterToContinue(); gl_AppData.LinesDisplayedSoFar = 0; } } /* =============================================================================== Function: rec_GetFieldPointer Args: A pointer to a Record struct, and a field type indicator Returns: A char pointer to the start of the field specified by the type indicator Purpose: Quick way to obtain string from the Record struct. =============================================================================== */ char *rec_GetFieldPointer(const struct Record *rec, enum RECORD_FIELDS WhichField) { char *sptr; switch (WhichField) { case RECF_NAME: sptr = (char *)rec->Name; break; case RECF_PHONENUM1: sptr = (char *)rec->PhoneNum1; break; case RECF_PHONENUM2: sptr = (char *)rec->PhoneNum2; break; case RECF_PHONENUM3: sptr = (char *)rec->PhoneNum3; break; case RECF_ADDRLINE1: sptr = (char *)rec->AddrLine1; break; case RECF_ADDRLINE2: sptr = (char *)rec->AddrLine2; break; case RECF_ADDRLINE3: sptr = (char *)rec->AddrLine3; break; case RECF_ADDRLINE4: sptr = (char *)rec->AddrLine4; break; case RECF_ADDRLINE5: sptr = (char *)rec->AddrLine5; break; case RECF_EMAILADDR: sptr = (char *)rec->EmailAddr; break; case RECF_MISC: sptr = (char *)rec->Misc; break; default: sptr = (char *)rec->Name; break; } return (sptr); } Code: #include "main.h" /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: UserInterfaceUtilities.c Contents: Menu structs ui_DisplayMenu ui_AddNewEntry ui_UpdateEntry ui_AddOrUpdateEntry ui_DeleteEntry ui_UndeleteEntry ui_SearchAll ui_SearchByID ui_DisplayAll ui_Save ui_PurgeDeleted ui_ShowInfo ui_ToggleAutoSave ui_SetLinesPerDisplay =============================================================================== */ /* =============================================================================== The following are the structs that make up the menus. =============================================================================== */ static struct menu_item OptionsMenu[] = { {"Auto-Save Setup", ui_ToggleAutoSave, NULL }, {"Set Lines Per Display", ui_SetLinesPerDisplay, NULL }, { NULL, NULL, NULL } }; static struct menu_item SearchByFieldMenu[] = { { "Search By ID", ui_SearchAll, (void *)RECF_ID }, { "Search By Name", ui_SearchAll, (void *)RECF_NAME }, { "Search By Phone Num 1", ui_SearchAll, (void *)RECF_PHONENUM1 }, { "Search By Phone Num 2", ui_SearchAll, (void *)RECF_PHONENUM2 }, { "Search By Phone Num 3", ui_SearchAll, (void *)RECF_PHONENUM3 }, { "Search By Phone Num 3", ui_SearchAll, (void *)RECF_PHONENUM3 }, { "Search By Address Line 1", ui_SearchAll, (void *)RECF_ADDRLINE1 }, { "Search By Address Line 2", ui_SearchAll, (void *)RECF_ADDRLINE2 }, { "Search By Address Line 3", ui_SearchAll, (void *)RECF_ADDRLINE3 }, { "Search By Address Line 4", ui_SearchAll, (void *)RECF_ADDRLINE4 }, { "Search By Address Line 5", ui_SearchAll, (void *)RECF_ADDRLINE5 }, { "Search By Email Address", ui_SearchAll, (void *)RECF_EMAILADDR }, { "Search By Misc Field", ui_SearchAll, (void *)RECF_MISC }, { NULL, NULL, NULL } }; static struct menu_item SortByFieldMenu[] = { { "Sort By ID", ui_SetSortBy, (void *)RECF_ID }, { "Sort By Name", ui_SetSortBy, (void *)RECF_NAME }, { "Sort By Phone Num 1", ui_SetSortBy, (void *)RECF_PHONENUM1 }, { "Sort By Phone Num 2", ui_SetSortBy, (void *)RECF_PHONENUM2 }, { "Sort By Phone Num 3", ui_SetSortBy, (void *)RECF_PHONENUM3 }, { "Sort By Phone Num 3", ui_SetSortBy, (void *)RECF_PHONENUM3 }, { "Sort By Address Line 1", ui_SetSortBy, (void *)RECF_ADDRLINE1 }, { "Sort By Address Line 2", ui_SetSortBy, (void *)RECF_ADDRLINE2 }, { "Sort By Address Line 3", ui_SetSortBy, (void *)RECF_ADDRLINE3 }, { "Sort By Address Line 4", ui_SetSortBy, (void *)RECF_ADDRLINE4 }, { "Sort By Address Line 5", ui_SetSortBy, (void *)RECF_ADDRLINE5 }, { "Sort By Email Address", ui_SetSortBy, (void *)RECF_EMAILADDR }, { "Sort By Misc Field", ui_SetSortBy, (void *)RECF_MISC }, { NULL, NULL, NULL } }; static struct menu_item Page2Menu[] = { { "Search By Chosen Field", ui_DisplayMenu, SearchByFieldMenu }, { "Display All Entries", ui_DisplayAll, NULL }, { "Set Sort Order", ui_DisplayMenu, SortByFieldMenu }, { "Undelete An Entry", ui_UndeleteEntry, NULL }, { "Save Changes", ui_Save, NULL }, { "Purge Entries Marked For Deletion", ui_PurgeDeleted, NULL }, { "Application Options", ui_DisplayMenu, OptionsMenu }, { NULL, NULL, NULL } }; struct menu_item MainMenu[] = { { "Add New Entry", ui_AddNewEntry, NULL }, { "Delete Entry", ui_DeleteEntry, NULL }, { "Update Entry", ui_UpdateEntry, NULL }, { "Display Entry", ui_SearchAll, (void *)RECF_ID}, { "Search By Name", ui_SearchAll, (void *)RECF_NAME }, { "Save Changes", ui_Save, NULL }, { "More Options", ui_DisplayMenu, Page2Menu }, { "Help/About", ui_ShowInfo, NULL }, { NULL, NULL, NULL } }; /* =============================================================================== Function: ui_DisplayMenu Args: Pointer to a menu to be displayed Returns: Nothing Purpose: Displays the menu, gets the users option and processes it. =============================================================================== */ void ui_DisplayMenu(void *pmenu) { int i, choice; struct menu_item *menu = pmenu; struct menu_item *item; for (;;) { printf ("---> PhoneBook Menu <---\n"); for (i = 1, item = menu; item->Text != NULL; item++, i++) { printf("%2d %s\n", i, item->Text); } printf(" x Exit Menu\nEnter choice >"); if ((choice = io_GetInt(i-1)) == RC_BAD) break; item = menu + choice - 1; if (item->Text == NULL) break; (void) (*item->fptr) (item->args); } } /* =============================================================================== Function: ui_AddNewEntry Args: None (NULL pointer) Returns: Nothing Purpose: Caller function to process a new entry request. The menu is capable of calling the next function directly, but I left this in to assist future developments. =============================================================================== */ void ui_AddNewEntry(void *Dummy) { ui_AddOrUpdateEntry(Dummy); } /* =============================================================================== Function: ui_UpdateEntry Args: None (NULL Pointer) Returns: Nothing Purpose: Asks user for an ID, then calls another function to do record updates =============================================================================== */ void ui_UpdateEntry(void *Dummy) { struct Record *rec; int choice; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } for (;;) { printf("Enter Record ID Number (1-%d, x to exit) >", gl_HighestID); if ((choice = io_GetInt(gl_HighestID)) == RC_BAD) return; if ((rec = li_GetDataPtrByID(gl_AppData.MainList, choice)) == NULL) { printf("No such entry: %d\n", choice); } else break; } ui_AddOrUpdateEntry(rec); } /* =============================================================================== Function: ui_AddOrUpdateEntry Args: Pointer to a struct to be updated, OR NULL is request is to ADD. Returns: Nothing Purpose: Obtains user data to complete a Record structure, then adds or updates a record in the list. =============================================================================== */ void ui_AddOrUpdateEntry(struct Record *newrec) { struct Record rec; char buffer[MAXL_FIELD+1]; struct Node *tmpListPtr; memset (&rec, 0, sizeof(struct Record)); /* * If newrec is not NULL, the it must be pointing to a Record struct and * therefore we are updating an existing record. In this case, we show * the user the existing data before asking for new. If they press <enter> * on a blank line, we leave the old data in place, this saves them retyping * each field when they are only changing one. */ if (newrec != NULL) { rec = *newrec; printf("(Press <Enter> on blank line to keep existing text)\nCurrent Name: %s\n", newrec->Name); } printf ("Enter Name (max %d chars) >", MAXL_NAME); if (io_GetLine(buffer, MAXL_NAME+1, stdin) == 0) { if (newrec == NULL) return; /* allow user to break out by entering a new record with no name */ } else strncpy (rec.Name, buffer, MAXL_NAME+1); if (newrec != NULL) printf("Current 1st Phone: %s\n", newrec->PhoneNum1); printf("Enter 1st Phone (max %d chars) >", MAXL_PHONENUM); if (io_GetLine(buffer, MAXL_PHONENUM+1, stdin) > 0) strncpy (rec.PhoneNum1, buffer, MAXL_PHONENUM+1); if (newrec != NULL) printf("Current 2nd Phone: %s\n", newrec->PhoneNum2); printf("Enter 2nd Phone (max %d chars) >", MAXL_PHONENUM); if (io_GetLine(buffer, MAXL_PHONENUM+1, stdin) > 0) strncpy (rec.PhoneNum2, buffer, MAXL_PHONENUM+1); if (newrec != NULL) printf("Current 3rd Phone: %s\n", newrec->PhoneNum3); printf("Enter 3rd Phone (max %d chars) >", MAXL_PHONENUM); if (io_GetLine(buffer, MAXL_PHONENUM+1, stdin) > 0) strncpy (rec.PhoneNum3, buffer, MAXL_PHONENUM+1); if (newrec != NULL) printf("Current Address Line 1: %s\n", newrec->AddrLine1); printf("Enter Address Line 1 of 5 (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.AddrLine1, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Address Line 2: %s\n", newrec->AddrLine2); printf("Enter Address Line 2 of 5 (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.AddrLine2, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Address Line 3: %s\n", newrec->AddrLine3); printf("Enter Address Line 3 of 5 (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.AddrLine3, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Address Line 4: %s\n", newrec->AddrLine4); printf("Enter Address Line 4 of 5 (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.AddrLine4, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Address Line 5: %s\n", newrec->AddrLine5); printf("Enter Address Line 5 of 5 (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.AddrLine5, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Email Address: %s\n", newrec->EmailAddr); printf("Enter Email Address (max %d chars) >", MAXL_ADDR); if (io_GetLine(buffer, MAXL_ADDR+1, stdin) > 0) strncpy (rec.EmailAddr, buffer, MAXL_ADDR+1); if (newrec != NULL) printf("Current Misc data: %s\n", newrec->Misc); printf("Enter Misc Details (max %d chars) >", MAXL_MISC); if (io_GetLine(buffer, MAXL_MISC+1, stdin) > 0) strncpy (rec.Misc, buffer, MAXL_MISC+1); if (newrec == NULL) {rec.ID = gl_HighestID+1; rec.Status = 0;}; /* * Display new/changed details for user to review */ printf ("Record Details Now:\n"); rec_PrintLong(&rec); if (io_GetYesNo("Confirm Details (y/n) >") == TRUE) { /* User has confirmed new details, so update/add record and add to list */ if (newrec) /* updating an existing record */ { *newrec = rec; } else { /* Adding a new record */ if ((newrec = malloc(sizeof (struct Record))) == NULL) { perror ("Add/Update failed on malloc"); return; } *newrec = rec; if ((tmpListPtr = li_Insert (gl_AppData.MainList, newrec, rec_Compare)) == NULL) { printf("Error performing insert on list. Item not addded.\n"); free(newrec); /* throw the record away */ } else { gl_AppData.MainList = tmpListPtr; newrec->ID = gl_HighestID; } } gl_AppData.DataChanged = TRUE; if (gl_AppCfg.AutoSave) (void)io_WriteAllRecordsToFile(gl_AppData.MainList); } } /* =============================================================================== Function: ui_DeleteEntry Args: None (NULL pointer) Returns: Nothing Purpose: Gets an ID from the user, displays the record then marks it for deletion if the user agrees. If autosave is on, the list will be written to disk and the record will be erased completely (undelete not available in this case). =============================================================================== */ void ui_DeleteEntry(void *Dummy) { struct Record *rec; int choice; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } printf("Enter Record ID Number (1-%d, x to exit) >", gl_HighestID); if ((choice = io_GetInt(gl_HighestID)) == RC_BAD) return; if ((rec = li_GetDataPtrByID(gl_AppData.MainList, choice)) == NULL) { printf("No such entry: %d\n", choice); io_EnterToContinue(); return; } rec_PrintLong(rec); if (io_GetYesNo("Confirm Delete (y/n) >") == TRUE) { rec->Status = rec->Status | ST_DELETED; gl_AppData.DataChanged = TRUE; if (gl_AppCfg.AutoSave) (void)io_WriteAllRecordsToFile(gl_AppData.MainList); } } /* =============================================================================== Function: ui_UndeleteEntry Args: None (NULL Pointer) Returns: Nothing Purpose: Gets an ID from the user, and unsets the deleted flag. =============================================================================== */ void ui_UndeleteEntry(void *Dummy) { struct Record *rec; int choice; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } printf("Enter Record ID Number (1-%d, x to exit) >", gl_HighestID); if ((choice = io_GetInt(gl_HighestID)) == RC_BAD) return; if ((rec = li_GetDataPtrByID(gl_AppData.MainList, choice)) == NULL) { printf("No such entry: %d\n", choice); io_EnterToContinue(); return; } if (rec->Status & ST_DELETED) { rec->Status = rec->Status ^ ST_DELETED; printf ("Record undeleted\n"); gl_AppData.DataChanged = TRUE; if (gl_AppCfg.AutoSave) (void)io_WriteAllRecordsToFile(gl_AppData.MainList); } else printf ("Record was not marked for deletion\n"); io_EnterToContinue(); } /* =============================================================================== Function: ui_SearchByID Args: None Returns: Nothing Purpose: Gets an ID from the user, then display that Record in detail =============================================================================== */ void ui_SearchByID(void) { struct Record *rec; int choice; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } printf("Enter Record ID Number (1-%d, x to exit) >", gl_HighestID); if ((choice = io_GetInt(gl_HighestID)) == RC_BAD) return; if ((rec = li_GetDataPtrByID(gl_AppData.MainList, choice)) == NULL) printf("No such entry: %d\n", choice); else rec_PrintLong(rec); io_EnterToContinue(); } /* =============================================================================== Function: ui_SearchAll Args: Field type Returns: Nothing Purpose: Gets search criteria from user, the traverses the list, short printing each record that matches the criteria. =============================================================================== */ void ui_SearchAll(void *WhichField) { char buffer[MAXL_FIELD + 1]; int i, len; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } if ((enum RECORD_FIELDS)WhichField == RECF_ID) { ui_SearchByID(); return; } printf("Enter Criteria >"); if ((len = io_GetLine(buffer, MAXL_FIELD + 1, stdin)) != 0) { gl_AppData.SearchField = (enum RECORD_FIELDS)WhichField; for (i = 0; i < len; i++) /* convert to lower case for search */ if (isupper(buffer[i])) buffer[i] = tolower(buffer[i]); strncpy(gl_AppData.SearchText, buffer, MAXL_FIELD + 1); gl_AppData.LinesDisplayedSoFar = 0; (void)li_Traverse(gl_AppData.MainList, rec_SearchAndPrint); } io_EnterToContinue(); } /* =============================================================================== Function: ui_DisplayAll Args: None Returns: Nothing Purpose: Traverses the list and does a short print of each record =============================================================================== */ void ui_DisplayAll(void *Dummy) { if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } gl_AppData.LinesDisplayedSoFar = 0; gl_AppData.SearchField = RECF_DUMMY; (void)li_Traverse(gl_AppData.MainList, rec_SearchAndPrint); io_EnterToContinue(); } /* =============================================================================== Function: ui_Save Args: None (NULL Pointer) Returns: Nothing Purpose: Gets confirmation from the user, then saves the current list to disk =============================================================================== */ void ui_Save(void *Dummy) { if (io_GetYesNo("Confirm Save (including purge of deleted records) (y/n) >") == TRUE) { (void)io_WriteAllRecordsToFile(gl_AppData.MainList); } } /* =============================================================================== Function: ui_PurgeDeleted Args: None (NULL Pointer) Returns: Nothing Purpose: Gets confirmation from the user, then traverses the list, removing (free'ing) any records that are marked as deleted =============================================================================== */ void ui_PurgeDeleted(void *Dummy) { unsigned char status = ST_DELETED; if (gl_HighestID == 0) { printf ("No entries in the database!\n"); io_EnterToContinue(); return; } if (io_GetYesNo("Confirm Purge (y/n) >") == TRUE) gl_AppData.MainList = li_DeleteNodeAndData (gl_AppData.MainList, &status, rec_CompareStatus); } /* =============================================================================== Function: ui_ShowInfo Args: None (NULL Pointer) Returns: Nothing Purpose: Displays stats about the program and the PhoneBook =============================================================================== */ void ui_ShowInfo(void *Dummy) { printf ("--->\n---> **PhoneBook** - Version: %s\n", PRG_VERSION); printf ("---> Written By *Hammer* for the C Programming Contest\n"); printf ("---> held by http://www.cprogramming.com/cboard/ in May 2002\n"); printf ("---> You can contact the author via email: claw_hammer@hotmail.com\n"); printf ("--->\n---> The PhoneBook datafile is %s\n", STR_FILENAME); printf ("---> The PhoneBook configuration file is %s\n", STR_CFG_FILENAME); printf ("--->\n---> There are currently %d entries loaded.\n", li_Count(gl_AppData.MainList)); printf ("--->\n---> This program accepts command line information\n"); printf ("---> For example (assuming the program name is phone.exe):\n"); printf ("---> >phone.exe hammer tommy\n"); printf ("---> will result in the database being searched for the\n"); printf ("---> names hammer and tommy and the results being displayed.\n"); printf ("---> In this case, the menu is not loaded, and the\n"); printf ("---> program terminates. This is useful for quick lookups.\n"); printf ("--->\n"); io_EnterToContinue(); } /* =============================================================================== Function: ui_ToggleAutoSave Args: None (NULL Pointer) Returns: Nothing Purpose: Allows the user to turn auto-save off and on. =============================================================================== */ void ui_ToggleAutoSave(void *Dummy) { printf ("Auto-Save is currently %s\n", (gl_AppCfg.AutoSave)?"On":"Off"); if (io_GetYesNo("Toggle auto-save (y/n) >") == TRUE) { gl_AppCfg.AutoSave = ~gl_AppCfg.AutoSave; printf ("Auto-Save is now %s\n", (gl_AppCfg.AutoSave)?"On":"Off"); io_EnterToContinue(); } } /* =============================================================================== Function: ui_SetLinesPerDisplay Args: None (NULL Pointer) Returns: Nothing Purpose: Allows the user to set the number of lines displayed in lists before a io_EnterToContinue is called. =============================================================================== */ void ui_SetLinesPerDisplay(void *Dummy) { int Lines; printf ("This option determines how many lines are output to the screen\nbefore a \"hit enter to continue\" message is displayed\n"); printf ("The current setting is %d\n", gl_AppCfg.LinesPerDisplay); printf ("Enter a new number or x to exit >"); if ((Lines = io_GetInt(MAX_LINES_PER_PAGE)) == RC_BAD) return; gl_AppCfg.LinesPerDisplay = Lines; printf ("The new setting is %d\n", gl_AppCfg.LinesPerDisplay); io_EnterToContinue(); } /* =============================================================================== Function: ui_SetSortBy Args: Field type Returns: Nothing Purpose: Allows the user to set the sort order =============================================================================== */ void ui_SetSortBy(void *WhichField) { gl_AppCfg.SortField = (enum RECORD_FIELDS)WhichField; printf ("Sorting the data..."); li_Sort (gl_AppData.MainList, rec_Compare); printf ("Done!\n"); io_EnterToContinue(); } Code: /* =============================================================================== Author: Hammer, May 2002, For www.cprogramming.com/cboard/ File: main.h Contents: All the definitions needed for the app, along with the function prototypes. This is the only header file used by this program. =============================================================================== */ #ifndef __PHONE__ #define __PHONE__ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* * #defines * Field lengths - These do NOT include the 1 byte for the NULL terminator */ #define MAXL_NAME 100 #define MAXL_PHONENUM 20 #define MAXL_MISC 256 #define MAXL_FIELD 256 #define MAXL_ADDR 100 #define MAXL_FIELD_NAME 50 #define DEF_LINES_PER_PAGE 10 #define MAX_LINES_PER_PAGE 999 /* * String variables */ #define STR_FILENAME "phonebk.dat" #define STR_CFG_FILENAME "phonebk.cfg" #define PRG_VERSION "1.1" #define RC_BAD -1 /* * boolean style vars */ #define TRUE 1 #define FALSE 0 /* * Record status flags */ #define ST_DELETED 0x1 /* * Macros */ #define FLUSH_INPUT while(getchar() != '\n') /* * enums */ enum RECORD_FIELDS {RECF_DUMMY, RECF_ID, RECF_NAME, RECF_PHONENUM1, RECF_PHONENUM2, RECF_PHONENUM3, RECF_ADDRLINE1, RECF_ADDRLINE2, RECF_ADDRLINE3, RECF_ADDRLINE4, RECF_ADDRLINE5, RECF_EMAILADDR, RECF_MISC, RECF_END_MARKER}; /* * typedefs */ typedef int bool_t; /* * Structures */ struct Record { int ID; /* Assigned at load time, sequential based on input, not related to tree */ char Name[MAXL_NAME + 1]; /* All in name field, holds any type, so user can decide own format */ char PhoneNum1[MAXL_PHONENUM + 1]; /* 3 phone num fields, user decides what to put where */ char PhoneNum2[MAXL_PHONENUM + 1]; char PhoneNum3[MAXL_PHONENUM + 1]; char AddrLine1[MAXL_ADDR+1]; char AddrLine2[MAXL_ADDR+1]; char AddrLine3[MAXL_ADDR+1]; char AddrLine4[MAXL_ADDR+1]; char AddrLine5[MAXL_ADDR+1]; char EmailAddr[MAXL_ADDR+1]; char Misc[MAXL_MISC + 1]; /* Freeform text field, for user comments. */ unsigned char Status; /* See the ST_... variables */ }; struct Node { void *DataPtr; struct Node *Next; }; struct appdata { struct Node *MainList; enum RECORD_FIELDS SearchField; char SearchText[MAXL_FIELD + 1]; bool_t DataChanged; int LinesDisplayedSoFar; }; struct appconfig { bool_t AutoSave; int LinesPerDisplay; enum RECORD_FIELDS SortField; }; struct menu_item { char *Text; void (*fptr) (void *); void *args; }; /* * more typedefs */ typedef void (*FPTR_Action) (void *); typedef int (*FPTR_Compare) (const struct Record *, const struct Record *); typedef int (*FPTR_CompareDelete) (const struct Record *, void *); /* * Global vars / externs */ extern int gl_HighestID; extern struct appdata gl_AppData; extern struct appconfig gl_AppCfg; extern struct menu_item MainMenu[]; /* * Prototypes for ListUtilities */ struct Node *li_Create(void); struct Node *nd_Create(void *, struct Node *); void nd_Destroy(struct Node *); int li_Traverse(struct Node *, FPTR_Action); struct Node *li_Insert(struct Node *, void *, FPTR_Compare); struct Node *li_Destroy(struct Node *); struct Record *li_GetDataPtrByID(struct Node *, int ); struct Node *li_DeleteNodeAndData(struct Node *, void *, FPTR_CompareDelete); int li_Count(struct Node *); void li_Sort(struct Node *, FPTR_Compare); /* * Prototypes for RecordUtilities */ int rec_Compare(const struct Record *, const struct Record *); int rec_CompareID(const struct Record *, void *); int rec_CompareStatus(const struct Record *rec, void *); void rec_PrintShort(void *); void rec_PrintLong(void *); void rec_SearchAndPrint(void *); char *rec_GetFieldPointer(const struct Record *, enum RECORD_FIELDS); /* * Prototypes for ioUtilities */ void io_WriteRecordToFile(void *); struct Node *io_LoadPhoneBookFromFile(struct Node *); int io_WriteAllRecordsToFile(struct Node *); int io_GetInt(int); void io_EnterToContinue(void); int io_GetLine(char *, int , FILE *); bool_t io_GetYesNo(char *); void io_LoadAppConfig(void); void io_SaveAppConfig(void); /* * Prototypes for UserInterfaceUtilities */ void ui_AddNewEntry(void *); void ui_DeleteEntry(void *); void ui_UndeleteEntry(void *); void ui_UpdateEntry(void *); void ui_AddOrUpdateEntry(struct Record *); void ui_DisplayAll(void *); void ui_Save(void *); void ui_PurgeDeleted(void *); void ui_SearchAll(void *); void ui_SearchByID(void); void ui_DisplayMenu(void *); void ui_ShowInfo(void *); void ui_ToggleAutoSave(void *); void ui_SetLinesPerDisplay(void *); void ui_SetSortBy(void *); #endif |
| ygfperson is offline |
| | #7 |
| Just because Join Date: Jan 2002
Posts: 2,502
| and... Hammer wins! Hail to the Hammer! Cicero... there's always the next one. good job to the contestants, and thanks to the judges and their hard work. |
| ygfperson is offline |
| | #8 |
| Guest Join Date: Aug 2001
Posts: 4,923
| Congratulations to Hammer, and Cicero, too...they both deserve credit for their effort. Hammer's entry was very complex, and a little hard to follow sometimes. But all in all he deserves the most credit for his hard work. Cicero, on the other hand was better at stubbing out the implementation first, a wise move. But his implementation seemed a little weak. So I would have chosen Hammer for that reason. Cicero, Hammer, what have you two got to say about the results? |
| Sebastiani is offline |
| | #9 |
| Nerd Join Date: Apr 2002
Posts: 146
| Congrats to Hammer. |
| Xmevs is offline |
| | #10 |
| End Of Line Join Date: Apr 2002
Posts: 6,240
| Hey, what d'ya know... I won!! Naturally I'm pleased, and would like to pass my thanks to all those involved, and my condolences to Cicero. ![]() I don't have a speech prepared, you'll be glad to hear, nor do I have a mile long list of people to thank! I have attached a copy of my source, zipped, with a Windows exe. If anyone wants to actually make use of this program, they are more than welcome to (just leave my name in there!), I Also welcome any more comments on it. As for the comments by the judges, they're all fair and valid, and it's nice to see that all entries were given a fair chance, and were thoroughly examined. I like to know what other people think of my ideas, and this is definately a good way to do it. The only thing I would like to discuss further is my choice of list. I didn't use a tree because the search facility was designed to check each and every node (it used strstr() to find strings within strings in any given field). If the list was a tree, it would have to traverse all the way to the left doing nothing, then all the way back to the far right, doing compares on each node as it went. Using the link list method, you just start at the beginning and traverse to the end, therefore isn't this faster? I admit that adding a new node would be slower, but as most of the time the user will be searching, rather than adding, I thought link list was the way to go. What do you think? One bad point about the contest: only 2 entries. I'd have liked to seen more versions of the code to see how else it could have been done. Maybe next time...... Speaking of which, what is it and when?
__________________ When all else fails, read the instructions. If you're posting code, use code tags: [code] /* insert code here */ [/code] |
| Hammer is offline |
| | #11 | |
| Code Goddess Join Date: Sep 2001
Posts: 9,661
| Quote:
-Prelude
__________________ My best code is written with the delete key. | |
| Prelude is offline |
| | #12 |
| End Of Line Join Date: Apr 2002
Posts: 6,240
| Thanks for your reply Prelude..... >but consider how a skip list .... What, there's another type of list?!! Guess I'll have to go read up about that one now.
__________________ When all else fails, read the instructions. If you're posting code, use code tags: [code] /* insert code here */ [/code] |
| Hammer is offline |
| | #13 |
| Code Goddess Join Date: Sep 2001
Posts: 9,661
| >What, there's another type of list?!! Guess I'll have to go read up about that one now. You'll have fun with that one, imagine a linked list with extra links that skip over a certain number of nodes to speed up searching. So you have the lowest level which is a regular list, then another level with a link every 3rd or so node. It's a lot like a binary tree, and is often considered as an alternative. http://www.google.com/search?hl=en&i...s%3A+Skip+list -Prelude
__________________ My best code is written with the delete key. |
| Prelude is offline |
| | #14 |
| Banned Join Date: Oct 2001
Posts: 1,784
| Good job Son, I like your program. |
| Troll_King is offline |
| | #15 | |
| End Of Line Join Date: Apr 2002
Posts: 6,240
| Quote:
__________________ When all else fails, read the instructions. If you're posting code, use code tags: [code] /* insert code here */ [/code] | |
| Hammer is offline |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Obfuscated Code Contest: The Results | Stack Overflow | Contests Board | 29 | 02-18-2005 05:39 PM |
| Text Compression Contest -- Sept. 28, 2002 | ygfperson | A Brief History of Cprogramming.com | 4 | 10-03-2002 03:20 PM |
| Text Compression Contest -- Sept. 28, 2002 | ygfperson | C++ Programming | 5 | 10-03-2002 03:20 PM |
| Text Compression Contest -- Sept. 28, 2002 | ygfperson | C Programming | 3 | 10-01-2002 06:25 PM |
| Results for the Encryption Contest -- June 23, 2002 | ygfperson | A Brief History of Cprogramming.com | 18 | 07-07-2002 08:04 AM |