Hey I found an example of using malloc with an array of structs that fits what I'm trying to do quite well, but when I go to combine it with qsort which I need to sort by the "number" value of struct I'm not having much luck. The code complies fine with no errors but doesn't actually run and just crashes. Since I'm a beginner I have no idea what's causing the problem. If someone could shed some light on this that be brilliant thanks!
// Example code from "a tutorial on 'dynamic' arrays in C"
// http://fydo.net
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct DATA{
char *name;
int number;
} DATA;
DATA *the_array = NULL;
int num_elements = 0; // To keep track of the number of elements used
int num_allocated = 0; // This is essentially how large the array is
int compare(struct DATA *, struct DATA *);
typedef int (*compfn)(const void*, const void*);
int compare(struct DATA *elem1, struct DATA *elem2)
{
if ( elem1->number < elem2->number)
return -1;
else if (elem1->number > elem2->number)
return 1;
else
return 0;
}
int AddToArray (DATA item)
{
if(num_elements == num_allocated) { // Are more refs required?
// Feel free to change the initial number of refs and the rate at which refs are allocated.
if (num_allocated == 0)
num_allocated = 3; // Start off with 3 refs
else
num_allocated *= 2; // Double the number of refs allocated
// Make the reallocation transactional by using a temporary variable first
void *_tmp = realloc(the_array, (num_allocated * sizeof(DATA)));
// If the reallocation didn't go so well, inform the user and bail out
if (!_tmp)
{
fprintf(stderr, "ERROR: Couldn't realloc memory!\n");
return(-1);
}
// Things are looking good so far, so let's set the
the_array = (DATA*)_tmp;
}
the_array[num_elements] = item;
num_elements++;
return num_elements;
}
int main()
{
// Some data that we can play with
char *names[6] = { "Steve", "Bill", "George", "fydo", "Dave", "Jim" };
int numbers[6] = { 42, 33, 15, 74, 5, 20 };
int i;
// Populate!
for (i = 0; i < 6; i++)
{
DATA temp;
temp.name = malloc((strlen(names[i]) + 1) * sizeof(char));
strncpy(temp.name, names[i], strlen(names[i]) + 1);
temp.number = numbers[i];
if (AddToArray(temp) == -1) // If there was a problem adding to the array,
return 1; // we'll want to bail out of the program. You
// can handle it however you wish.
}
//sort by number:
qsort((void *) &the_array, 6, sizeof(struct DATA), (compfn)compare );
// Regurgitate!
for (i = 0; i < 6; i++)
{
printf("%s's number is %d!\n", the_array[i].name, the_array[i].number);
}
// Deallocate!
for (i = 0; i < 6; i++)
{
free(the_array[i].name);
}
free(the_array);
// All done.
return 0;
}
You are passing the array in the wrong way.
it should be
qsort(the_array, 6, sizeof(struct DATA), (compfn)compare );
qsort expects as first argument a pointer to where the data to be sorted starts, and this is the_array
not its address &the_array
since you have declared it this way
DATA *the_array = NULL;
The output would be:
Dave's number is 5!
George's number is 15!
Jim's number is 20!
Bill's number is 33!
Steve's number is 42!
fydo's number is 74!
What happens is that qsort thinks the array is starting at the address of the_array
and start accessing other memory areas where it is not allowed to.
EDIT
I have tryed it with 4000 words and can't get it to crash, here is how i modified the code to read from a file, (strdup is ust handy equivalent to malloc
+ strcpy
)
char name[100];
while(1 == scanf("%s", name)) {
DATA temp;
temp.name = strdup(name);
temp.number = rand();
if (AddToArray(temp) == -1)
return 1;
}
executed like this:
out.exe < lorem.txt
The data is correctly sorted, printed and free-ed