cquicksortkernighan-and-ritchie

What's wrong with this quick sort?


I tried to adapt this example from K&R (5.11, ANSI edition) to sort an array of ints but it crashes randomly and I can't figure why.

The original version sorted "lines" : char *lineptr[1000], I'm trying to sort int *p or int p[4]. I would like to keep the most generic parameters possible and I guess it's where my problem comes from.

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

#define MAXNUMS 4

int numcmp(int* a, int* b);
void mqsort(void* v[], int left, int right, int (*comp)(void*, void*));
void swap(void* v[], int i, int j);

int numcmp(int* a, int* b) {
  return *a - *b;
}

void swap(void* v[], int i, int j) {
  printf("swap befor %d: %d, %d: %d\n", i, v[i], j, v[j]);
  void* temp;
  temp = v[i];
  v[i] = v[j];
  v[j] = temp;
  printf("swap after %d: %d, %d: %d\n", i, v[i], j, v[j]);
}

void mqsort(void* v[], int left, int right, int (*comp)(void*, void*)) {
  int i, last;

  if (left >= right) {
    return;
  }

  printf("left %d, right %d\n", left, right);
  for (int j = 0; j < 4; j++) {
    printf("%d, ", v[j]);
  }
  printf("\n");
  swap(v, left, (left + right) / 2);

  last = left;
  for (i = left + 1; i <= right; i++) {
    if ((*comp)(v[i], v[left]) < 0) {
      ++last;
      swap(v, last, i);
    }
  }
  swap(v, left, last);
  for (int j = 0; j < 4; j++) {
    printf("%d, ", v[j]);
  }
  printf("\n");
  mqsort(v, left, last - 1, comp);
  mqsort(v, last + 1, right, comp);
}
int main(void) {
  int i;
  /* doesn't work :( */
  /* int* p; */
  /* int* p_start; */
  /* p_start = p = malloc(sizeof(int) * MAXNUMS); */
  /* if (p == NULL) { */
  /*   printf("cannot allocate"); */
  /*   exit(1); */
  /* } */
  /* *(p + 0) = 1; */
  /* *(p + 1) = 3; */
  /* *(p + 2) = 5; */
  /* *(p + 3) = 7; */

  int p[MAXNUMS] = {1, 3, 5, 7};

  for (i = 0; i < MAXNUMS; i++) {
    printf("%d, ", p[i]);
  }
  printf("\n");

  mqsort((void**)p, 0, MAXNUMS - 1, (int (*)(void*, void*))numcmp);

  for (i = 0; i < MAXNUMS; i++) {
    printf("%d, ", p[i]);
  }
  printf("\n");

  /* free(p); */
  /* free(p_start); */

  return 0;
}

Here's a link to a working version and to the example itself, page 100.

I tried to bypass the comp function completely, I also tried to change the pivot, I tried many versions of numcmp like int numcmp(int a, int b), int numcmp(int *a, int *b) but nothing works.

I always get random numbers after execution.

I really can't figure what's wrong and where do those numbers come from.

Obviously, when I just use mqsort(int* p, int start, int right) and a comparison, it works fine :)


Solution

  • Your code has a minor error, which is that the array needs to consist of int * rather than int. So, in main, change

    int p[MAXNUMS] = {1, 3, 5, 7};
    

    to

    int ip[] = {1, 3, 5, 7};
    int *p[MAXNUMS] = {&ip[0], &ip[1], &ip[2], &ip[3]};
    

    That and fixing the printfs to use correct parameters and formats fixes your code:

    1, 3, 5, 7, 
    left 0, right 3
    0x7ffe434e26e0, 0x7ffe434e26e4, 0x7ffe434e26e8, 0x7ffe434e26ec, 
    swap befor 0: 0x7ffe434e26e0, 1: 0x7ffe434e26e4
    swap after 0: 0x7ffe434e26e4, 1: 0x7ffe434e26e0
    swap befor 1: 0x7ffe434e26e0, 1: 0x7ffe434e26e0
    swap after 1: 0x7ffe434e26e0, 1: 0x7ffe434e26e0
    swap befor 0: 0x7ffe434e26e4, 1: 0x7ffe434e26e0
    swap after 0: 0x7ffe434e26e0, 1: 0x7ffe434e26e4
    0x7ffe434e26e0, 0x7ffe434e26e4, 0x7ffe434e26e8, 0x7ffe434e26ec, 
    left 2, right 3
    0x7ffe434e26e0, 0x7ffe434e26e4, 0x7ffe434e26e8, 0x7ffe434e26ec, 
    swap befor 2: 0x7ffe434e26e8, 2: 0x7ffe434e26e8
    swap after 2: 0x7ffe434e26e8, 2: 0x7ffe434e26e8
    swap befor 2: 0x7ffe434e26e8, 2: 0x7ffe434e26e8
    swap after 2: 0x7ffe434e26e8, 2: 0x7ffe434e26e8
    0x7ffe434e26e0, 0x7ffe434e26e4, 0x7ffe434e26e8, 0x7ffe434e26ec, 
    1, 3, 5, 7,