简体   繁体   中英

C: qsort has a problem sorting unsigned long long members of a structure

C's Qsort algorithm doesn't sort unsigned long long ints when they are part of a structure, which shouldn't have mattered. Here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

typedef struct TextData {
  char catalog,  // The catalog code.
       txt[137]; // The text for this object.
  short mv;      // mv * 100.
  unsigned long long indx; // Hash of 2D position.
} txtD;          // 152 bytes.

// The comparison function required by qsort for txtD items.
int cmpTdata(const void *a,
             const void *b) {
  txtD *dataA = (txtD*) a;
  txtD *dataB = (txtD*) b;
  if ((dataB->indx - dataA->indx) < 0) { return 1; }
  else if ((dataB->indx - dataA->indx) > 0) { return -1; }
  else { return 0; }
}

int main(int argc, char** argv) {
  FILE *UNSORTED = fopen("/top/middle/directory/filename", "r");
  if (UNSORTED == NULL) {
    printf("Filename not opened for reading!\n");
    exit(0);
  }

  int stat = fseek(UNSORTED, 0L, SEEK_END);
  if (stat != 0) {
     printf("Fseek on failed to find the end! because %s.\n", strerror(errno));
     exit(0);
  }

  unsigned long long size = ftell(UNSORTED);
  if ((size == 0) && (errno != 0)) {
     printf("Error %d) Ftell is 0! because %s.\n",
            errno, strerror(errno));
     exit(0);
  }

  fclose(UNSORTED);

  int nrItems = size / sizeof(txtD);

  txtD *data = (txtD*) malloc(nrItems * sizeof(txtD));
  if (data == NULL) {
    printf("txtD structure not allocated because:\n%s.\n",
           strerror(errno));
    exit(0);
  }

  // Sort it in order of increasing indx.
  qsort(data, nrItems, sizeof(txtD), cmpTdata);

  // Save the sorted items using fopen and fwrite. I'll spare you the details.
}

Here's the output of a program that simply reads the structures, and notes the errors:

Item 2) previous index 466715 greater than t.indx 449261!
Item 4) previous index 464265 greater than t.indx 404184!
Item 5) previous index 404184 greater than t.indx 353788!
Item 7) previous index 446334 greater than t.indx 361489!
Item 8) previous index 361489 greater than t.indx 328323!
Item 10) previous index 487465 greater than t.indx 343185!
Item 12) previous index 494247 greater than t.indx 428224!
Item 14) previous index 478868 greater than t.indx 130860!
Item 16) previous index 444180 greater than t.indx 339954!
Item 18) previous index 342195 greater than t.indx 281552!
Item 20) previous index 394250 greater than t.indx 370791!
Item 22) previous index 458202 greater than t.indx 311406!
Item 23) previous index 311406 greater than t.indx 280793!
Item 25) previous index 466171 greater than t.indx 424598!
Item 27) previous index 467144 greater than t.indx 431265!
Item 29) previous index 472449 greater than t.indx 198109!
Item 31) previous index 469376 greater than t.indx 451215!
Item 33) previous index 453004 greater than t.indx 427448!
Item 34) previous index 427448 greater than t.indx 374260!
Item 37) previous index 447735 greater than t.indx 336330!

Checked 41 items, there were 21 errors.

BTW, excoriating me for not using stderr or other stylistic infractions is not helpful. Why qsort isn't sorting is. Note also that the function cmpTdata works fine for other structures when I'm sorting doubles.

TIA!

function cmpTdata works fine for other structures when I'm sorting doubles.

double math differs from unsigned math. The following is never true as unsigned are never less than 0.

if ((dataB->indx - dataA->indx) < 0) { return 1; }

This implies code was not compiled with a good compiler that would have warned. So the biggest oops is not "doing the math wrong", but not using tools readily at hand. Best to enable all warnings.

foo.c:9:35: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

Recommend the C compare idiom - recognized by various compilers to emit efficient code.

int cmpTdata(const void *a, const void *b) {
  const txtD *dataA = (txtD*) a;
  const txtD *dataB = (txtD*) b;
  return (dataA->indx > dataB->indx) - (dataA->indx < dataB->indx);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM