1

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);
}
10
  • Based on this question and the previous one asked, it appears that you have a misunderstanding of qsort. The library function qsort will not sort a file directly. It sorts an array that you pass it. You can probably just google for "qsort example" and get a better idea of how it works. Commented Nov 28, 2012 at 0:32
  • I read up on stackoverflow.com/questions/3707051/… and was under the impression i could, am i wrong? Commented Nov 28, 2012 at 0:34
  • 3
    No - it won't sort a file. In that example, the OP is (I believe) actually trying to sort the argv array (sort the actual parameters passed in to the program). I think you missed the important first step in @BenJackson's answer to your previous question. You need to read in the contents of the file (it means to write code ... fopen, fread, or whatever set of I/O functions you use). Commented Nov 28, 2012 at 0:42
  • thanks for the explanation, does this mean i dont need a copy of agrv and can just write const argv[1] to an array? Commented Nov 28, 2012 at 0:50
  • I'm not sure if I undestood what you want to achieve. But if you just want to be independent of the order of the arguments consider to use GNU Getopt Commented Nov 28, 2012 at 0:52

2 Answers 2

3
+50

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);
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a ton for this post, you'll surely get the rep for this. i just have a couple question regarding the code if we could chat
Happy to answer questions either in comments here or feel free to email me at [email protected].
I'll be sending an email, thank again! I have to wait 14 hours to award my bounty so you'll be getting the rep soon.
3

You can start with something like this, and you need to actually call sort somewhere. Also need to consider what happens when the file is large:

#include <stdio.h>

int
Sort(const void *a, const void *b)
{
    int *aa = a, *bb = b;
    return (aa[1] < bb[1]); //i need to sort by field, not a simple comparison. HOW?
}

int main(int argc, char **argv) {
  FILE *f = fopen(argv[1]);
  if (f) {
    char buffer[1024];
    int *v;
    int data[1024][5];
    int cnt = 0;
    while (fgets(buffer, sizeof(buffer), f)) {
        v = data[cnt++];
        sscanf(buffer, "%d %d %d %d %d", v, v+1, v+2, v+3, v+4);
    }
    fclose(f);
  }
  return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.