The following example shows how to create a wrapper for a dynamically allocated array. This simplifies array access and size management – i.e. how many elements are stored, for how many is there room for, where is the data?
For testing, an example file with workflow is provided, that can be used for the program’s input stdin :
- An array that can hold two members is created
- Data for two members is entered
- An attempt is made to extend the array by adding three more members.
The result of the third step depends on whether EXPANDABLE macro is set to 1 or 0.
To test with the provided data using stream redirection: ./program_name < test_data.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 |
The following code is given as source and header file. The previously mentioned EXPANDABLE macro is in the source file. When setting the value to 1, realloc() is used to expand the dynamic array . If it is set to 0, the structure size is fixed by the first prompt.
Expanding the array is done using (n * 2) method for reallocation.
|
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 |
/** * File: wrapper_struct.h * Author: Risto Heinsar * Created: 28.02.2018 * Edited: 01.06.2026 * * Description: Header containing the Employee struct definition and the wrapper * used to manage memory for Employee array */ #ifndef WRAPPER_STRUCT_H #define WRAPPER_STRUCT_H #include <stdio.h> // Required for size_t #define EID_LEN 12 #define MAX_NAME 256 typedef struct { int code; char fName[MAX_NAME]; char lName[MAX_NAME]; char eID[EID_LEN]; float wagePerHour; } Employee; typedef struct { Employee *db; size_t limit; size_t used; } EmployeeList; void AllocateList(EmployeeList *wf); void InsertMembers(EmployeeList *wf); void InsertMembersWithExpandability(EmployeeList *wf); void PrintMembers(EmployeeList wf); Employee CreateMember(); #endif // WRAPPER_STRUCT_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 193 |
/** * File: wrapper_struct.c * Author: Risto Heinsar * Created: 28.02.2018 * Edited: 01.06.2026 * * Description: The following example demonstrates two techniques regarding * dynamic memory allocation. * * First, a wrapper struct for dynamic array is demonstrated. * This helps to keep track of the array size cleanly. * * Second, expanding dynamic memory using (n * 2) strategy is * shown, that will greatly improve allocation speed. */ #include <stdio.h> #include <stdlib.h> #include "wrapper_struct.h" // Use 0 for non-expandable list, // 1 for expandable using realloc. #define EXPANDABLE 1 int main(void) { EmployeeList workForce = {.db = NULL, .limit = 0, .used = 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(EmployeeList *wf) { unsigned n; printf("For many employees is storage required?\n"); scanf("%u", &n); wf->db = 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(EmployeeList *wf) { size_t n; printf("How many employees to add?\n"); scanf("%zu", &n); // Detect if employees array can't fit the requested number of employees if (n > wf->limit - wf->used) { fprintf(stderr, "Error! %zu out of %zu slots are in use.\n", wf->used, wf->limit); fprintf(stderr, "Storage left for %zu slots\n", wf->limit - wf->used); return; } for (size_t i = 0; i < n; i++) { printf("Adding member %zu out of %zu\n", i + 1, n); *(wf->db + wf->used) = CreateMember(); wf->used++; } } /** * Insert members to the structure array. This function will try to expand * the dynamically allocated array if possible. If expanding memory fails, * the program can be allowed to continue. */ void InsertMembersWithExpandability(EmployeeList *wf) { size_t n; printf("How many employees to add?\n"); scanf("%zu", &n); size_t i = 0; while (i < n) { // Detect if array is full and needs expanding if (wf->limit <= wf->used) { // let's make the new limit 2x from what we had size_t newLimit = 2 * wf->limit; printf("Attempting to expand array from %zu to %zu\n", wf->limit, newLimit); // Expand the array memory block Employee *pTemp = realloc(wf->db, sizeof(Employee) * newLimit); // Handle allocation failure if (pTemp == NULL) { fprintf(stderr, "Error: Memory allocation failed!\n"); fprintf(stderr, "Previously allocated data is safe. "); fprintf(stderr, "Allocation exists for %zu items\n", wf->limit); break; } // "sync" the pointers and update the limit wf->db = pTemp; wf->limit = newLimit; printf("Allocation success! New limit is %zu\n", wf->limit); } printf("Adding member %zu out of %zu\n", i + 1, n); *(wf->db + wf->used) = CreateMember(); wf->used++; i++; } } /** * Creates a new struct member with data from user. The struct will be returned * so it can be added to the appropriate array later using the preferred method. */ Employee CreateMember() { Employee newEmployee; /* static variables are scope limited, but have global lifetime */ static int employeeCode = 0; newEmployee.code = employeeCode++; 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(EmployeeList wf) { printf("%zu out of %zu slots are in use\n", wf.used, wf.limit); if (wf.used <= 0) { return; } printf("%7s %12s %15s %15s %6s\n", "code", "eID", "fName", "lName", "wage"); for (size_t 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); } } |