Reputation:
I am working on a program that stores an arbitrarily long list of contacts (names and phone numbers). The entries are stored in an array that is resized each time a new element is added with the realloc
function. The first contact can be added and displayed normally. However, when I try to add the second contact, the program crashes with the following message:
Program received signal SIGTRAP, Trace/breakpoint trap.
In ntdll!RtlZeroHeap () (C:\WINDOWS\SYSTEM32\ntdll.dll)
No breakpoints have been set in my editor. The debugger says the problem is on the line containing the realloc
statement. How can I fix this issue? I have included the relevant sections of code below.
#define STRING_LENGTH 32
typedef struct entry_t {
char name[STRING_LENGTH];
char number[STRING_LENGTH];
} Entry;
void *add_entry(Entry*, int);
int main()
{
int entry_count = 0;
Entry *entries = calloc(1, sizeof(Entry));
int choice = 0;
while (1) {
printf("Options:\n1) Add Entry\n2) Modify Entry\n3) Print Entries\n4) Exit\n\nSelect an option: ");
scanf(" %d", &choice);
switch (choice) {
case 1:
entries = add_entry(entries, entry_count++);
break;
// ...
}
}
}
void *add_entry(Entry *entries, int current_count)
{
Entry entry;
printf("Enter name: ");
scanf(" %[^\n]s", entry.name);
printf("Enter number: ");
scanf(" %[^\n]s", entry.number);
printf("\n");
entries[current_count] = entry;
return realloc(entries, sizeof(Entry) * (current_count + 1));
}
Upvotes: 0
Views: 4598
Reputation: 13590
There is a logic problem here. You initially allocate space for one object with
calloc
then call add_entry
with the count equals to 0.
Then you add the new entry at index current_count
which is 0 at this point.
Then you resize the memory with current_count + 1
, which is also 1. So you are
not resizing the memory at all.
In the next iteration, entry_count
is 1 and you add a new element at
entries[1]
. And that's the problem, you are accessing the memory out of
bounds, because you still have space for only one object at this time.
Instead of reallocating by current_count + 1
, you should reallocate by
current_count + 2
, so that the next iteration has space to put the new
elements at the end of the memory.
void *add_entry(Entry *entries, int current_count)
{
Entry entry;
printf("Enter name: ");
scanf(" %[^\n]s", entry.name);
printf("Enter number: ");
scanf(" %[^\n]s", entry.number);
printf("\n");
entries[current_count] = entry;
return realloc(entries, sizeof(Entry) * (current_count + 2)); // <-- +2
}
Note that your current_count
variable is always one step behind the real size of the allocation, that's why you need the +2
edit
Note also that the more natural way would be to resize first, and then insert
the new object. So I would initialize the memory with NULL
and do it like
this:
int main()
{
size_t entry_count = 0;
Entry *entries = NULL, *tmp;
int choice = 0;
while (1) {
printf("Options:\n1) Add Entry\n2) Modify Entry\n3) Print Entries\n4) Exit\n\nSelect an option: ");
scanf(" %d", &choice);
switch (choice) {
case 1:
tmp = add_entry(entries, &entry_count);
if(tmp == NULL)
{
// error handling
// entries still point to the old memory
// could be useful in error handling
free(entries);
return 1;
}
entries = tmp;
break;
// ...
}
}
}
void *add_entry(Entry *entries, size_t *current_count)
{
if(current_count == NULL)
return NULL;
Entry entry;
printf("Enter name: ");
scanf(" %[^\n]s", entry.name);
printf("Enter number: ");
scanf(" %[^\n]s", entry.number);
printf("\n");
if(entries == NULL)
*current_count = 0;
Entry *tmp = realloc(entries, (*current_count + 1) * sizeof *entries);
if(tmp == NULL)
return NULL;
entries = tmp;
entries[(*current_count)++] = entry;
return entries;
}
Note here that the realloc
and the increment of the counting variable
happens in the same function. Only when everything goes OK, you should increase
the counter. Also note that entries
is initialized with NULL
, because
realloc(NULL, size)
is equivalent to malloc(size)
.
Upvotes: 1