Järgnevas näites on kirjeldatud kuidas teha struktuurile ümbrist, mis aitab jälgida mitu elementi struktuuri massiivis on juba kasutusel ning palju kokku on. Wrapper ehk ümbrisstruktuur hoiab endas siis mahtu ja kasutust ning viita struktuuride massiivile (alamstruktuur) kus andmeid hoitakse.
Programmi töö testimiseks on pakutud näidisandmete fail. Näidisandmete puhul luuakse struktuur, mis mahutab 2 liiget. Esimesel korral lisatakse 2 andmerida ning teisel kroral veel 3 andmerida. Näidisandmete faili saab kasutada koos voo suunamisega ( ./programm < testandmed.txt )
1 2 3 4 5 6 7 8 |
2 2 0114 Rasmus Aare 38101012210 9.20 0115 Tarmo Waldorf 38909091120 14.20 3 0116 Jane Kask 48511113320 12.20 0117 Aare Kallas 38412124330 7.45 0118 Alexandra Sepp 49105040334 15.00 |
Programm on antud kujul päisefail + c koodifail. C koodifailis on olemas makro EXPANDABLE, mille väärtuse alusel otsustatakse kas kirjete lisamisel on võimalik struktuure laiendada (EXPANDABLE 1, kasutab realloc) või on struktuurid fikseeritud suurusega (EXPANDABLE 0).
Laiendamisel kasutatakse põhimõtet, et iga kord suurendatakse mälumahtu 2x olemasolevast.
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 |
#ifndef WRAPPER_H #define WRAPPER_H #define EID_LEN 12 #define MAX_NAME 2511 typedef struct { int code; char fName[MAX_NAME]; char lName[MAX_NAME]; char eID[EID_LEN]; float wagePerHour; } employee; typedef struct { employee *db; unsigned limit; unsigned used; } employee_list; void AllocateList(employee_list *wf); void InsertMembers(employee_list *wf); void InsertMembersWithExpandability(employee_list *wf); void printMembers(employee_list wf); employee CreateMember(); #endif // WRAPPER_H |
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 |
/** * File: wrapper_struct.c * Author: Risto Heinsar * Created: 28.02.2018 * Edited: 13.02.2024 * * Description: The following code will demonstrate a couple of hints on allocating * memory in C. * First of all, it will demonstrate the use of a wrapper structure * which will give better control over size management. In this case, * it will track how many memory slots are in use and how many are * there in total. This allows to keep the data neatly together * and avoid array overflows. * Secondly, this code also demonstrates a possibility to safely * expand the storage using reallocation. The reallocate step is 2x * of what it was previously, so it would be more optimal in speed. */ #include <stdio.h> #include <stdlib.h> #include "wrapper.h" // Use 0 for non-expandable list, 1 for expandable using realloc. #define EXPANDABLE 1 int main(void) { employee_list workForce = {NULL, 0, 0}; AllocateList(&workForce); if (EXPANDABLE) { InsertMembersWithExpandability(&workForce); InsertMembersWithExpandability(&workForce); } else { InsertMembers(&workForce); InsertMembers(&workForce); } printMembers(workForce); free(workForce.db); return 0; } /** * Allocate an initial list, mostly for demonstrative purposes and compatibility * with both methods of inserting members (fixed and expandable) */ void AllocateList(employee_list *wf) { unsigned n; printf("For many employees is storage required?\n"); scanf("%u", &n); wf->db = (employee *)calloc(n, sizeof(employee)); if (wf->db == NULL) { perror("Error allocating memory"); exit(EXIT_FAILURE); } wf->limit = n; } /** * Insert members to the structure array. This is only capable of adding members * until the array is full. It will also keep track of how many members have been * added. The array cannot be expanded using this function */ void InsertMembers(employee_list *wf) { unsigned n; printf("How many employees to add?\n"); scanf("%u", &n); if (n <= wf->limit - wf->used) { for (int i = 0; i < n; i++) { printf("Adding member %d out of %d\n", i + 1, n); *(wf->db + wf->used) = CreateMember(); wf->used++; } } else { printf("Error! %d out of %d slots are in use. Storage left for %d " "Employees\n", wf->used, wf->limit, wf->limit - wf->used); } } /** * Function to create a new struct member with data. The struct will be returned * so it can be added to the appropriate array later using the preferred method. */ employee CreateMember() { employee newEmployee; printf("Enter employee code:\n"); scanf("%d", &newEmployee.code); printf("Enter first name:\n"); scanf("%s", newEmployee.fName); printf("Enter last name:\n"); scanf("%s", newEmployee.lName); printf("Enter Estonian identification number:\n"); scanf("%s", newEmployee.eID); printf("Enter wage per hour:\n"); scanf("%f", &newEmployee.wagePerHour); return newEmployee; } /** * Prints the list of members in the struct array */ void printMembers(employee_list wf) { printf("%d out of %d slots are in use\n", wf.used, wf.limit); printf("%7s %12s %15s %15s %6s\n", "code", "eID", "fName", "lName", "wage"); for (int i = 0; i < wf.used; i++) { printf("%7d %12s %15s %15s %6.2f\n", (wf.db + i)->code, (wf.db + i)->eID, (wf.db + i)->fName, (wf.db + i)->lName, (wf.db + i)->wagePerHour); } } /** * Insert members to the structure array. This function will try to expand * the dynamically allocated array if it is possible. The reallocate will be done * safely. If for some reason the expansion fails, the program can be allowed to * continue */ void InsertMembersWithExpandability(employee_list *wf) { unsigned n; printf("How many employees to add?\n"); scanf("%u", &n); int i = 0; while (i < n) { // first lets create some code that detects if array is full if (wf->limit == wf->used) { // let's make the new limit 2x from what we had int newLimit = 2 * wf->limit; printf("We ran out of memory. Trying to expand array from %d to %d\n", wf->limit, newLimit); // reallocate the new memory employee *pTemp = realloc(wf->db, sizeof(employee) * newLimit); // check if we were successful if (pTemp != NULL) { // "sync" the pointers and update the limit wf->db = pTemp; wf->limit = newLimit; printf("Allocation success! New limit is %d\n", wf->limit); } else { printf("Allocation failed. Old limit of %d is being used\n", wf->limit); } } // Check if we are have capacity to write new data if (wf->used < wf->limit) { printf("Adding member %d out of %d\n", i + 1, n); *(wf->db + wf->used) = CreateMember(); wf->used++; i++; } else { printf("Unfortunately the program ran out of memory.\n" "Expansion of the employee list has been aborted\n" "You can continue with what you have so far\n"); break; } } } |