-
Notifications
You must be signed in to change notification settings - Fork 0
/
intermediate.c
1119 lines (909 loc) · 31.9 KB
/
intermediate.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// *********************************************************************
//
// Intermediate C coding examples
//
// intermediate.c is a C (intermediate level) cheat sheet
// copyright 2006 Hans de Rooij
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 51 Franklin St, Boston, MA
// 20110-1301, USA.
//
//
// Compile using the GNU C compiler
// gcc intermediate.c -o cintermediate
// with debug messages
// gcc -D_DEBUG intermediate.c -o cintermediate
//
// Compile using the GNU C++ compiler
// g++ intermediate.c -o intermediate
//
// *********************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
//Disable irrelevant Microsoft Visual C compiler warnings
#ifdef _MSC_VER
#pragma warning (disable : 4244)
#pragma warning (disable : 4305)
#pragma warning (disable : 4996)
#endif
#define STR_BUFF 80
// *********************************************************************
//
// Characters & C-style strings
//
// *********************************************************************
//Character functions
void f001()
{
char str[] = "The man yelled \"##**!!!\" for a 2nd time.";
char str1[STR_BUFF], str2[STR_BUFF], str3[STR_BUFF], str4[STR_BUFF];
char str5[STR_BUFF], str6[STR_BUFF], str7[STR_BUFF], str8[STR_BUFF];
size_t i, len;
int j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0, j6 = 0;
len = strlen(str);
for(i = 0; i < len; i++)
{
if(islower(str[i])) str1[j1++] = str[i];
if(isupper(str[i])) str2[j2++] = str[i];
if(isdigit(str[i])) str3[j3++] = str[i];
if(isalpha(str[i])) str4[j4++] = str[i];
if(isspace(str[i])) str5[j5++] = str[i];
if(ispunct(str[i])) str6[j6++] = str[i];
str7[i] = tolower(str[i]);
str8[i] = toupper(str[i]);
}
str1[j1] = '\0'; str2[j2] = '\0';
str3[j3] = '\0'; str4[j4] = '\0';
str5[j5] = '\0'; str6[j6] = '\0';
str7[i] = '\0'; str8[i] = '\0';
printf("Started with string: %s\n", str);
printf("islower -> %s\n", str1);
printf("isupper -> %s\n", str2);
printf("isdigit -> %s\n", str3);
printf("isalpha -> %s\n", str4);
printf("isspace -> %s\n", str5);
printf("ispunct -> %s\n", str6);
printf("tolower -> %s\n", str7);
printf("toupper -> %s\n", str8);
return;
}
#ifdef __GNUC__
//Flush the keyboard buffer
void FlushKeybBuff()
{
//For more information http://faq.cprogramming.com
char ch;
//Discard all characters in the buffer
while((ch = getchar()) != '\n' && ch != EOF);
return;
}
//Discard newline character at the end of a string
void DiscardNewLineChar(char* p2str)
{
char* pLastChar;
size_t str_length = strlen(p2str);
if(str_length > 0)
{
pLastChar = p2str + str_length - 1;
if(*pLastChar == '\n') *pLastChar = '\0';
}
return;
}
#else
//Flush the keyboard buffer
void FlushKeybBuff()
{
//For more information http://support.microsoft.com/kb/42075
fflush(stdin);
}
#endif
//Display character pointer information
void DisplayCharPtr(const char* p2str)
{
printf("The content of the string is : %s\n", p2str);
printf("The length of string is : %u\n", strlen(p2str));
return;
}
//Display character array information
void DisplayCharArr(const char* p2str, size_t str_buff_size)
{
DisplayCharPtr(p2str);
printf("The size of the string buffer is: %u\n", str_buff_size);
return;
}
//C-style strings basics
void f002()
{
//A C-style string is a null terminated array of characters,
//so this might be unconventional but is syntactically correct
char str1[] = {'1','s','t',' ','s','t','r','i','n','g','\0'};
//This is the conventional way to declare and initialize a string
char str2[] = "String two is declared and initialized";
//... and this is basically the same way as the conventional way
//but using pointer notation
const char* p2char_a = "Using pointer notation";
//It's also possible to explicitly specify the width of the buffer
char str3[STR_BUFF] = "1234";
//Miscellaneous variables
char* p2char_b = NULL;
int i; double dbl;
#ifdef __GNUC__
int bytes_read; size_t buff_size = STR_BUFF;
#endif
//Reading a C-style string from the standard input stream
printf("Enter a string: ");
#ifdef __GNUC__
//Use function getline to read the string from stdin
bytes_read = getline(&p2char_b, &buff_size, stdin);
//Read from stdin failed, handle error
if(bytes_read == -1) return;
//Discard the newline character that is read by function getline
DiscardNewLineChar(p2char_b);
#else
//Dynamic string allocation, reserve a buffer for a C-style string
//at run-time
#ifdef __cplusplus
p2char_b = (char*)calloc(STR_BUFF, sizeof(char));
#else
p2char_b = calloc(STR_BUFF, sizeof(char));
#endif
//Note that function gets is considered to be a security risk because
//there is no protection against buffer overflows!
gets(p2char_b);
#endif
//String conversion functions
i = atoi(str3);
dbl = i + atof("0.5");
//Display the string information to the user
putchar('\n');
DisplayCharArr(str1, sizeof(str1)); putchar('\n');
DisplayCharArr(str2, sizeof(str2)); putchar('\n');
DisplayCharPtr(p2char_a); putchar('\n');
DisplayCharArr(str3, sizeof(str3)); putchar('\n');
DisplayCharPtr(p2char_b); putchar('\n');
printf("String conversion results: %s + 0.5 = %.2f\n", str3, dbl);
if(p2char_b) free(p2char_b);
return;
}
//C-style string library functions as defined in header file string.h
void f003()
{
//Declaration and initialization section
char str1[STR_BUFF] = "BCDE";
char* p2chr_a; char* p2chr_b;
char* p2chr_c; char* p2chr_d;
size_t str_length; int cmp;
//Dynamic string allocation, reserve a buffer for a C-style string
//at run-time
#ifdef __cplusplus
p2chr_a = (char*)calloc(STR_BUFF, sizeof(char));
#else
p2chr_a = calloc(STR_BUFF, sizeof(char));
#endif
//Copy the contents of str1 to the buffer associated with p2chr_a
strcpy(p2chr_a, str1);
//String concatenation
strcat(p2chr_a, " "); //first add a string literal
strcat(p2chr_a, str1); //then add the contents of str1
//Change the contents of str1 using strcpy
strcpy(str1, "ABC");
//strcpy(str1, "BCDE BCDE");
//strcpy(str1, "CDE");
//Determine the length of a string
str_length = strlen(p2chr_a);
//Compare two strings
cmp = strcmp(str1, p2chr_a); //more detail on the result of strcmp below
//Search a string (left to right) for a specific character
p2chr_b = strchr(p2chr_a, 'C');
//Search a string (right to left) for a specific character
p2chr_c = strrchr(p2chr_a, 'C');
//Search a string for another string
p2chr_d = strstr(p2chr_a, "DE");
//Display the outcome of the string manipulations
printf("str1 = %s\n", str1);
printf("p2chr_a = %s (length is %u)\n\n", p2chr_a, str_length);
printf("String compare result -> cmp = strcmp(str1, p2chr_a)\n");
if(cmp == 0)
printf("The 1st parameter to strcmp equals the 2nd\n\n");
else if(cmp < 0)
printf("The 1st parameter to strcmp comes before the 2nd\n\n");
else //cmp > 0
printf("The 1st parameter to strcmp comes after the 2nd\n\n");
if(p2chr_b) printf("Located the character at %s\n", p2chr_b);
if(p2chr_c) printf("Located the character at %s\n", p2chr_c);
if(p2chr_d) printf("Located the search string at %s\n", p2chr_d);
if(p2chr_a) free(p2chr_a);
return;
}
// *********************************************************************
//
// Miscellaneous intermediate level coding examples involving;
// * The use of structures
// * Data structures like linked lists and binary trees
// * File reading and writing in text and binay formats
//
// *********************************************************************
//Declare a self-referential stucture used for storing vowels
struct vowel
{
char chr; //The vowel located
int iLine; //The line in which the vowel was located
int iPos; //The position in the char array of the vowel
struct vowel* p2vowel; //Pointer used to build a linked list
};
//Create an alias for data type struct vowel (optional)
typedef struct vowel Vowel;
//Insert a newly created node of type struct vowel in a linked list
void InsNodeInLL(Vowel** NodeStart, Vowel* NodeStore)
{
Vowel* NodeBefore = NULL;
Vowel* NodeAfter = *NodeStart;
//Loop until the insertion point in the list is reached
while(NodeAfter != NULL
&& tolower(NodeStore->chr) >= tolower(NodeAfter->chr))
{
NodeBefore = NodeAfter;
NodeAfter = NodeAfter->p2vowel;
}
//Insert the node to store at the beginning of the list
if(NodeBefore == NULL)
{
NodeStore->p2vowel = *NodeStart;
*NodeStart = NodeStore;
}
else //Insert the node in the middle or at the end of the list
{
NodeBefore->p2vowel = NodeStore;
NodeStore->p2vowel = NodeAfter;
}
return;
}
//Write the contents of a linked list of vowels to a file
void ContentsLL2File(FILE* File, Vowel* NodeLL)
{
//First write the file header
fprintf(File, "%5s%6s%6s\n", "Vowel", "Line", "Pos");
//Write the contents of the linked list
while(NodeLL)
{
fprintf(File, "%-5c%6d%6d\n", NodeLL->chr, NodeLL->iLine, NodeLL->iPos);
NodeLL = NodeLL->p2vowel;
}
return;
}
//Free up the resources associated with a linked list of vowels
void FreeResourcesLL(Vowel** NodeLL)
{
//Declare a node pointer to the node about to be removed
Vowel* NodeTemp;
while(*NodeLL)
{
//Store a pointer to what currently is the 1st node in the list
NodeTemp = *NodeLL;
//Make the next node in the list the new 1st node in the list
*NodeLL = (*NodeLL)->p2vowel;
//Free the resources associated with the now de-threaded node
free(NodeTemp);
}
return;
}
//Build a linked list of all the vowels read from an input file
int f004()
{
//Declaration and initialization section
int errValue = 0;
FILE* InFile = NULL;
FILE* OutFile = NULL;
char str1[STR_BUFF];
char str2[] = "aeiouAEIOU";
char* p2CharLocated;
Vowel* Node1st = NULL;
Vowel* NodeNew;
int i = 1;
//Open a file for sequential read
InFile = fopen("seinfeld.txt", "r");
//Check whether the file was opened successfully
if(InFile == NULL)
{
//Error occurred while opening the input file
errValue = -1; goto ERR_HANDLER; //Unconditional branching using goto!
}
//Read the file sequentially and build the linked list
while(fgets(str1, sizeof(str1), InFile) != NULL)
{
//Find the first vowel in the line read
p2CharLocated = strpbrk(str1, str2);
//If applicable, loop through all the vowels in the string
while(p2CharLocated != NULL)
{
//Call malloc to dynamically reserve memory for storing a structure
#ifdef __cplusplus
//C++ forces the cast of the void pointer returned by malloc
NodeNew = (Vowel*)malloc(sizeof(Vowel));
#else
//Function malloc returns a void pointer
NodeNew = malloc(sizeof(Vowel));
#endif
//Set the properties of the new node
NodeNew->chr = *p2CharLocated;
NodeNew->iLine = i;
NodeNew->iPos = p2CharLocated - str1; //Use of pointer arithmetic!
NodeNew->p2vowel = NULL;
//Insert the new node in the linked list
InsNodeInLL(&Node1st, NodeNew);
//Find the next vowel
p2CharLocated = strpbrk(p2CharLocated + 1, str2);
}
i++; //Next line
}
//The input file can now be closed
fclose(InFile);
//Open a file for sequential write
//Use "w" write and replace, "a" for append
OutFile = fopen("vowels.txt", "w");
//Check whether the file was opened successfully
if(OutFile == NULL)
{
//Error occurred while opening the output file
errValue = -2; goto ERR_HANDLER;
}
//Write the contents of the linked list to a file
ContentsLL2File(OutFile, Node1st);
//Let the user know that everything went according to plan
printf("Successfully completed processing and wrote file vowels.txt\n");
ERR_HANDLER:
//Show error message in case of error
switch(errValue)
{
case -1: printf("Error opening input file, terminating ...\n\n"); break;
case -2: printf("Error opening output file, terminating ...\n\n"); break;
}
//Free up resources associated with the linked list
FreeResourcesLL(&Node1st);
//Close the output file (if necessary)
if(OutFile) fclose(OutFile);
return errValue;
}
//Do you know the Seinfeld regulars?
struct seinfeldCharacter
{
int iCharacterID; //Seinfeld character identifier
char sName[32]; //Name of the character
};
//Create an alias for data type struct seinfeldCharacter (optional)
typedef struct seinfeldCharacter SeinfeldCharacter;
//Declare a structure used for building a binary tree
struct bTreeNode
{
int iCharacterID; //Seinfeld character identifier
long pos; //Offset in the binary file
struct bTreeNode* LeftChild;
struct bTreeNode* RightChild;
};
//Create an alias for data type struct bTreeNode (optional)
typedef struct bTreeNode BTreeNode;
//Determine the maximum number of records the file can hold
int iGetMaxNRs(FILE* File)
{
long lPos;
//Set the file position pointer to the end of the file
fseek(File, 0, SEEK_END);
lPos = ftell(File);
//Reset the file position pointer
fseek(File, 0, SEEK_SET);
return (lPos / sizeof(SeinfeldCharacter));
}
//Show node contents
void ShowBTreeNodeContents(FILE* File, BTreeNode* BTN)
{
SeinfeldCharacter SFC;
//Position the file position pointer and read character info
fseek(File, BTN->pos, SEEK_SET);
fread(&SFC, sizeof(SeinfeldCharacter), 1, File);
//List the content associated with the node
printf("%d. %s\n", BTN->iCharacterID, SFC.sName);
return;
}
//List the contents of file in ascending order
void ListBTreeContentsAsc(FILE* File, BTreeNode* BTN)
{
if(BTN != NULL)
{
//Recursive call in search of a smaller identifier
ListBTreeContentsAsc(File, BTN->LeftChild);
ShowBTreeNodeContents(File, BTN);
//Recursive call in search of a larger identifier
ListBTreeContentsAsc(File, BTN->RightChild);
}
return;
}
//List the contents of file in descending order
void ListBTreeContentsDesc(FILE* File, BTreeNode* BTN)
{
if(BTN != NULL)
{
//Recursive call in search of a larger identifier
ListBTreeContentsDesc(File, BTN->RightChild);
ShowBTreeNodeContents(File, BTN);
//Recursive call in search of a smaller identifier
ListBTreeContentsDesc(File, BTN->LeftChild);
}
return;
}
//Search for a node with a particular ID
BTreeNode* SearchBTree(BTreeNode* BTN, int iID)
{
//ID searched is smaller than the current key, go left
if(iID < BTN->iCharacterID)
{
if(BTN->LeftChild == NULL)
{
return NULL;
}
else
{
return SearchBTree(BTN->LeftChild, iID);
}
}
//ID searched is larger than the current key, go right
else if(iID > BTN->iCharacterID)
{
if(BTN->RightChild == NULL)
{
return NULL;
}
else
{
return SearchBTree(BTN->RightChild, iID);
}
}
//Located the ID!
else
{
return BTN;
}
}
//Free the resources associated with the binary tree index
void CleanUpBTreeIndex(BTreeNode* BTN)
{
if(BTN != NULL)
{
//Recursive call in search of a smaller identifier
CleanUpBTreeIndex(BTN->LeftChild);
//Recursive call in search of a larger identifier
CleanUpBTreeIndex(BTN->RightChild);
//List the content associated with the node
#ifdef _DEBUG
printf("Clean up node with ID %d\n", BTN->iCharacterID);
#endif
free(BTN);
}
return;
}
//Create a new database containing the quintessential Seinfeld characters
int CreateNewBinFile(FILE** File)
{
SeinfeldCharacter SFC[7]; //An array of Seinfeld characters
SeinfeldCharacter EmptySFC = {0, ""}; //Empty Seinfeld character
int i;
assert(*File == NULL);
//Open a file for binary write, create or truncate
*File = fopen("seinfeld.dat", "wb");
//Handle errors that might have occured while opening the file
if(*File == NULL) return -1;
//The regular cast
SFC[0].iCharacterID = 40; strcpy(SFC[0].sName, "Elaine");
SFC[1].iCharacterID = 20; strcpy(SFC[1].sName, "George");
SFC[2].iCharacterID = 10; strcpy(SFC[2].sName, "Jerry");
SFC[3].iCharacterID = 60; strcpy(SFC[3].sName, "Babu");
SFC[4].iCharacterID = 50; strcpy(SFC[4].sName, "Newman");
SFC[5].iCharacterID = 80; strcpy(SFC[5].sName, "Uncle Leo");
SFC[6].iCharacterID = 30; strcpy(SFC[6].sName, "Kramer");
//Write the entire array to the binary file
fwrite(SFC, sizeof(SeinfeldCharacter), 7, *File);
//Add a number of empty records to the file
for(i = 7; i < 24; i++)
{
fwrite(&EmptySFC, sizeof(SeinfeldCharacter), 1, *File);
}
//All the writing is now done, close the file
fclose(*File);
//Open the newly created binary file for read & write
*File = fopen("seinfeld.dat", "rb+");
//Handle errors that might have occured while opening the file
if(*File == NULL) return -2;
return 0;
}
//Insert a new node in the binary tree
int InsNodeInBTree(BTreeNode** BTRoot, BTreeNode* BTCurrNode,
BTreeNode* BTNewNode)
{
int iRet = 0;
if(*BTRoot == NULL) //The tree is completely empty
{
*BTRoot = BTNewNode;
#ifdef _DEBUG
printf("New root, with ID %d\n\n", (*BTRoot)->iCharacterID);
#endif
}
else //Find the correct spot in the tree
{
//Start of searching at the root of the tree
if(BTCurrNode == NULL) BTCurrNode = *BTRoot;
//In case the new key is smaller than the current key, go left
if(BTNewNode->iCharacterID < BTCurrNode->iCharacterID)
{
if(BTCurrNode->LeftChild == NULL) //Insertion point located
{
BTCurrNode->LeftChild = BTNewNode;
#ifdef _DEBUG
printf("Placed in tree, left of node with ID %d\n\n",
BTCurrNode->iCharacterID);
#endif
}
else
{
#ifdef _DEBUG
printf("Continue search left of node with ID %d\n",
BTCurrNode->iCharacterID);
#endif
//Use a recursive call to continue the search
iRet = InsNodeInBTree(BTRoot, BTCurrNode->LeftChild, BTNewNode);
}
}
//In case the new key is larger than the current key, go right
else if(BTNewNode->iCharacterID > BTCurrNode->iCharacterID)
{
if(BTCurrNode->RightChild == NULL) //Insertion point located
{
BTCurrNode->RightChild = BTNewNode;
#ifdef _DEBUG
printf("Placed in tree, right of node with ID %d\n\n",
BTCurrNode->iCharacterID);
#endif
}
else
{
#ifdef _DEBUG
printf("Continue search right of node with ID %d\n",
BTCurrNode->iCharacterID);
#endif
//Use a recursive call to continue the search
iRet = InsNodeInBTree(BTRoot, BTCurrNode->RightChild, BTNewNode);
}
}
//No duplicate keys allowed
else
{
#ifdef _DEBUG
printf("No duplicate keys allowed, ID %d\n\n",
BTNewNode->iCharacterID);
#endif
iRet = -1;
}
}
return iRet;
}
//Create a new Seinfeld character, write to file and add to binary tree
void CreateNewSFC(FILE* File, BTreeNode** BTRoot, int* NRs, int iID)
{
SeinfeldCharacter SFC;
char* p2char = NULL;
long lpos;
BTreeNode* BTN;
#ifdef __GNUC__
int bytes_read; size_t buff_size = 32;
#endif
//Before calling this function please make sure that;
//1. The user has indicated that he or she wants to create a new character
//2. a non-existing ID was specified for the character to be created (iID)
//3. there is sufficient room available on the database for record creation
SFC.iCharacterID = iID;
//Prompt the user for the name of the character to be added
printf("Enter character name: ");
#ifdef __GNUC__
//Use function getline to read the string from stdin
bytes_read = getline(&p2char, &buff_size, stdin);
//Handling of error condition (bytes_read == -1) not implemented
//Discard the newline character that is read by function getline
DiscardNewLineChar(p2char);
#else
//Dynamic string allocation, reserve a buffer for a C-style string
//at run-time
#ifdef __cplusplus
p2char = (char*)calloc(STR_BUFF, sizeof(char));
#else
p2char = calloc(STR_BUFF, sizeof(char));
#endif
//Note that function gets is considered to be a security risk because
//there is no protection against buffer overflows!
gets(p2char);
#endif
//Copy the name specified by the user to the struct
strncpy(SFC.sName, p2char, 32); SFC.sName[31] = '\0';
free(p2char); //Temporary buffer is no longer needed
putchar('\n');
//Position the file position pointer and store the pointer value
fseek(File, *NRs * sizeof(SeinfeldCharacter), SEEK_SET);
lpos = ftell(File);
//Execute the write of the newly created character
fwrite(&SFC, sizeof(SeinfeldCharacter), 1, File);
//Call malloc to reserve memory for storing a node
#ifdef __cplusplus
BTN = (BTreeNode*)malloc(sizeof(BTreeNode));
#else
BTN = malloc(sizeof(BTreeNode));
#endif
//Set the properties of the binary tree node
BTN->iCharacterID = SFC.iCharacterID;
BTN->pos = lpos;
BTN->LeftChild = NULL;
BTN->RightChild = NULL;
//Insert the node read from file in the binary tree
InsNodeInBTree(BTRoot, NULL, BTN);
//Reflect the record creation in the record count
(*NRs)++;
return;
}
//Create a binary tree index on the file
int CreateBTreeIndex(FILE* File, BTreeNode** BTRoot)
{
int NRs, numStructs; long lpos;
SeinfeldCharacter SFC;
BTreeNode* BTN;
//Position the file position pointer at the beginning of the file
rewind(File);
//Reset the variable for storing the number of records on the file
NRs = 0;
//Index all the Seinfeld characters available on the file. Read one
//structure at a time, escape from the loop using break when;
//1. Read beyond the EOF occurs or
//2. First empty stucture is read
while(1)
{
//Store the value currently held by the file position pointer
lpos = ftell(File);
//Read the next struct from the binary file
numStructs = fread(&SFC, sizeof(SeinfeldCharacter), 1, File);
//Specifying !feof(File) as a condition for the while loop won't work!
//The EOF flag is only set when an attempt is made to read beyond the
//last byte of data. Reading up to and including the last byte of data
//does not set the EOF flag.
if(numStructs != 1)
{
if(ferror(File))
{
#ifdef _DEBUG
printf("Error occured while reading the file\n\n");
#endif
return -1; //Exit from the function and return a negative value
}
else
{
assert(feof(File));
break; //Break out of the loop and return the number of records
}
}
#ifdef _DEBUG
printf("Read \"%s\" with ID %d\n", SFC.sName, SFC.iCharacterID);
#endif
//Exit from loop when reading the first empty stucture
if(SFC.iCharacterID == 0) break;
//Call malloc to reserve memory for storing a node
#ifdef __cplusplus
BTN = (BTreeNode*)malloc(sizeof(BTreeNode));
#else
BTN = malloc(sizeof(BTreeNode));
#endif
//Set the properties of the binary tree node
BTN->iCharacterID = SFC.iCharacterID;
BTN->pos = lpos;
BTN->LeftChild = NULL;
BTN->RightChild = NULL;
//Insert the node read from file in the binary tree
if(InsNodeInBTree(BTRoot, NULL, BTN) != 0)
{
//Release the resources associated with the newly created node
free(BTN);
return -2;
}
NRs++;
}
#ifdef _DEBUG
if(NRs == 0)
printf("No Seinfeld characters available on the file\n\n");
else
printf("Successfully read & indexed %d records\n\n", NRs);
#endif
return NRs;
}
//Let the user specify either yes or no
char GetUserYesOrNo(const char* sPrompt)
{
char chrYesNo;
printf("%s (y\\n): ", sPrompt);
scanf("%c", &chrYesNo); FlushKeybBuff();
putchar('\n');
//Count a 'Y' as a 'y'
return tolower(chrYesNo);
}
//Let the user specify his or her preferred option
char GetUserOption()
{
char chr;
printf("Enter your choice\n"
" a. Find Seinfeld character\n"
" b. List file contents in ascending order\n"
" c. List file contents in descending order\n"
" q. Exit\n\n"
"? ");
//Get the user input
scanf("%c", &chr); FlushKeybBuff();
putchar('\n');
//Allow for upper- and lowercase option entry
return tolower(chr);
}
//Build and manipulate a binary tree of Seinfeld characters
int f005()
{
//Declaration and initialization section
int errValue = 0, iMaxNumRecs, iNumRecs, iID;
FILE* BinFile = NULL;
BTreeNode* BTreeRoot = NULL;
BTreeNode* BTNode = NULL;
char chrOption;
//Open the binary file, if NULL is returned special handling is required
if((BinFile = fopen("seinfeld.dat", "rb+")) == NULL)
{
if(errno != ENOENT) //File exists but access attempt results in error
{
//Database locked, no rights, ...
errValue = -1; goto ERR_HANDLER;
}
//From this point on errno == ENOENT (no such file or directory)
if(GetUserYesOrNo("No data file! Create new file?") != 'y')
{
//No database and user doesn't want to create one
errValue = -2; goto ERR_HANDLER;
}
//Create a new binary database file
if(CreateNewBinFile(&BinFile) == 0)
{
printf("Successfully created a new binary data file\n\n");
}
else
{
//No rights, disk full, ...
errValue = -3; goto ERR_HANDLER;
}
}
assert(BinFile != NULL);
//Determine the maximum number of records that the file can store
if((iMaxNumRecs = iGetMaxNRs(BinFile)) == 0)
{
//File too small to hold any records
errValue = -4; goto ERR_HANDLER;
}
//Build the file index
if((iNumRecs = CreateBTreeIndex(BinFile, &BTreeRoot)) < 0)
{
//Error occured building index, posibly a duplicate ID
errValue = -5; goto ERR_HANDLER;
}
printf("Read %d records, maximum number of records is %d\n\n",
iNumRecs, iMaxNumRecs);
//The application functionality is exposed to the user in this loop
while((chrOption = GetUserOption()) != 'q')
{
switch(chrOption)
{
case 'a': //Find Seinfeld character