Given a two dimensional array decalred below:
char * Arr[4] =
{
{"124 -346 DATA...."},
{"39479 -32 MOREDATA...."},
{"12 -1 DATA2...."},
{"100 -45 DATA4...."}
};
i'm trying to use qsort() to sort this function according to the SECOND field, meaning the strings would be ordered according to the lowest second value(-1,-32,-45,-346). I know how to make this function if each value were only one digit, but the digits in the program could be arbitrarily long. here is what i have but the program crashes, if there is a more efficient way to sort this data i would love to here it(i know my method can't be very efficient).
Sort function(which qsort() calls):
inline void GetStr(char *ix, char* Result) //call to get second number in function
{
char *spacing; //iterator to traverse
spacing = ix; //iterator = pos of ix
int LEN = 0; //length and offset
int Offset = 0;
while(*spacing != ' ') //while not at end of first num
{
Offset++; //offset is more
spacing++;
}
spacing++; //go one ahead of the space
Offset++;
while(*spacing != ' ') //while not end of second number
{
spacing++;
Offset++;
LEN++; //length of number
}
strncpy(Result, ix + (Offset - LEN),LEN);
}
int sort(const void* a, const void* b)
{
char *ia = *(char**)a;
char *ib = *(char**)b;
char * Str;
char * Str2;
GetStr(ia, Str); //getting some strange errors....... program just crashes
GetStr(ib, Str2);
printf("Str: %s Str2: %s", Str, Str2);
int n1 = atoi(Str);
int n2 = atoi(Str2);
return (n1 > n2);
}
I believe you have at least one problem here:
strncpy(Result, ix + (Offset - LEN),LEN);
If you look at the documentation for strncpy
, you will see that it does not automatically null-terminate the copied string if you hit the character limit. Therefore your Result
strings are not null-terminated.
Try changing to this:
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
Of course, you still need to provide memory for the Result string. Currently you are passing an uninitialized pointer into GetStr()
:
char * Str;
char * Str2;
Since these are fairly small integers you can use statically allocated storage like this:
#define MAX_RESULT_LEN 64
/* ... */
char Str[MAX_RESULT_LEN]
char Str2[MAX_RESULT_LEN]
/* ... */
if (LEN > MAX_RESULT_LEN - 1) {
LEN = MAX_RESULT_LEN - 1;
}
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
Finally, there are some issues with your sort()
function. If you look at the qsort() documentaton, you can see that the return value should be "an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second". The easiest way to achieve this is with the logic n1 - n2
instead of the n1 < n2
.
I also thought you're sort arguments of type char **
were odd as well, but upon further reflection I realize they are correct. From the qsort docs: "two arguments that point to the objects being compared". So indeed they will be pointers to C strings or char **
.
So here is the final version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_RESULT_LEN 64
void GetStr(char *ix, char* Result) //call to get second number in function
{
char *spacing; //iterator to traverse
spacing = ix; //iterator = pos of ix
int LEN = 0; //length and offset
int Offset = 0;
while(*spacing != ' ') //while not at end of first num
{
Offset++; //offset is more
spacing++;
}
spacing++; //go one ahead of the space
Offset++;
while(*spacing != ' ') //while not end of second number
{
spacing++;
Offset++;
LEN++; //length of number
}
if (LEN > MAX_RESULT_LEN - 1) {
LEN = MAX_RESULT_LEN - 1;
}
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
}
int sort(const void* a, const void* b)
{
char *ia = *(char **)a;
char *ib = *(char **)b;
char Str[MAX_RESULT_LEN];
char Str2[MAX_RESULT_LEN];
GetStr(ia, Str);
GetStr(ib, Str2);
printf("Str: %s Str2: %s", Str, Str2);
int n1 = atoi(Str);
int n2 = atoi(Str2);
return (n1 - n2);
}
int main(void) {
char * Arr[4] =
{
{"124 -346 DATA...."},
{"39479 -32 MOREDATA...."},
{"12 -1 DATA2...."},
{"100 -45 DATA4...."}
};
qsort(Arr, 4, sizeof(char *), sort);
}