Thursday, April 28, 2011

QSort part 3

Ok so I'll take this line by line.


char *sources[] = {"this", "is", "a", "program", "for", "testing"};


The first line about defining and initializing the variables "sources". "sources" is a pointer to an array of characters. I think that's the best way to say it. It's not a pointer to a character array, it's a pointer to an array of pointers that hold the location of character arrays. The syntax of initializing the variable with the {} is something K&R pointed out. I'm not sure if there is another way of doing it - there likely isn't a way to do it on the fly without some malloc action.

Anyways, this establishes the data we're working with.

It's important to note here that the value of "sources" itself is the address of where the character arrays start in memory, and saying something like "sources[3]" is the address of where the characters that make of "program" start. I think.



The function "printarray()" takes in two arguments: the address of the array of strings and how many elements are in the string. Since the address of the array is an address of something that holds an address I have to declare it to be a pointer to a pointer "char **stringarray". That's one of the toughest parts of C. You have to know exactly what you're giving a function and tell it exactly what to expect. I'm still working in my head about why I don't have to dereference the array variable in the printf() function. It works but I don't know why and that's breaking the rules a bit.



This is probably my favorite function ever because I get to cast and dereference all at once. The qsort() function prototype has an argument that's a pointer to a function that takes void pointers, so here is my function that takes void pointers where I cast them to what they really are - pointers to pointers - and then dereference them to pass them to strcmp(). This is why I'm kind of thrown by why I have to dereference the local variable that holds the address here but not in my function that prints out the strings.

So, the rest is in the secret sauce that qsort() uses. The prototype for qsort() is:

void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));

*base is the address of my array of data so I just pass it "sources". size_t nel is the number of elements in the array (which is hard coded to six - I could make this more flexible). size_t width the size of the elements and I'm just passing it "sizeof(char *)" since remember the array is REALLY an array of pointers to characters, and the characters actually AT the location of where the array elements point to is what we're really sorting. I'm not sure if that was a complete sentence. The last argument takes a pointer to a function that takes two void pointers as arguments. I call qsort() as follows:

qsort(sources, 6, sizeof(char *), compare);

And it works fine. The only mystery (which I might be able to hash out if I draw it out) is why my function for printing out the words works. I suspect it has to do with what I call "array synonyms". Like how "sources" is the same as saying "&sources[0]". I'm passing the function an address to an variable that holds the address of the start of an array of addresses.... why does printf() behave? Needs testing.

No comments:

Post a Comment