简体   繁体   中英

C struct quick sort for strings

I have problem with quick sort. It should sort books with author's names. Here is the code

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

struct book {
    char title[80];
    char autor[80];
    int pages;
};

int comparator (const void * a, const void *b)
{
    struct book * ia=(struct book*)a;
    struct book * ib=(struct book*)b;
    return (strcmp(ia->autor,ib->autor));
}

int main(int argc, char ** argv)
{
    int c = 2;
    int i;

    //Pointer to array of struct pointers, malloc for 2 structs
    struct book **ptr = (struct book*)malloc(c*sizeof(struct book));
    for(i=0;i<c;i++) {
            //malloc for every struct
            //also, if I'm doing it right?
            ptr[i] = (struct book*)malloc(sizeof(struct book));
            printf("Title: ");
            scanf("%s",ptr[i]->title);
            printf("Autor: ");
            scanf("%s",ptr[i]->autor);
    }
    for(i=0;i<c;i++) {
            printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
      }
    qsort(ptr,2, sizeof(struct book), comparator);
          printf("QSORT DONe...\n\n");
      for(i=0;i<c;i++) {
            printf("TEST");
            printf("After quick sort: Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
      }

    return 0;
}

So program compiles but it reaches only to printf("TEST"); (TEST prints on screen) and then it crashes. Did I destroy my array with that quick sort? Or what could happen?

Also could you check my code if it's ok? Especially what mallocs (really) do in my code, because I'm not sure if I used them properly.

Thanks!

It is shown for the point to be changed(for Pointer to array of struct pointers (but double pointer is not necessary)) following as

  1. #include <string.h>

  2. struct book * ia=*(struct book**)a; struct book * ib=*(struct book**)b;

  3. struct book **ptr = malloc(c*sizeof(struct book*));

  4. qsort(ptr,2, sizeof(struct book*), comparator);


Perhaps version what you want

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

struct book {
    char title[80];
    char autor[80];
    int pages;
};
int comparator (const void * a, const void *b)
{
    struct book * ia=(struct book*)a;
    struct book * ib=(struct book*)b;
    return (strcmp(ia->autor,ib->autor));
}

int main(int argc, char ** argv)
{
    int c = 2;
    int i;

    struct book *ptr = malloc(c*sizeof(struct book));
    for(i=0;i<c;i++) {
            printf("Title: ");
            scanf("%s",ptr[i].title);
            printf("Autor: ");
            scanf("%s",ptr[i].autor);
    }
    for(i=0;i<c;i++) {
            printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
    }
    qsort(ptr,2, sizeof(struct book), comparator);
          printf("QSORT DONe...\n\n");
    for(i=0;i<c;i++) {
            printf("TEST");
            printf("After quick sort: Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
    }

    return 0;
}

There were some small issues and confusions:

1) You were missing #include <string.h> for strcmp

2) You were allocating an array of pointers, which is probably not what you meant to do. An array in C is a pointer to the first element of the array, therefore if you allocate using (struct book*) malloc(n * sizeof(struct book)) you're already allocating a full array of n books. You could also allocate an array of pointers to books, in which case you'd need to assign each pointer to a newly allocated book.

So you could do either of the following (and your code is mixing both):

struct book** ptr = (struct book**) malloc(c * sizeof(struct book*));

struct book* ptr = (struct book*) malloc(c * sizeof(struct book));

In the first case, you need to allocate new books (and therefore the malloc inside the loop would make sense)

In the second case, you just use the array directly, which is what I changed the following code to do:

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

struct book {
  char title[80];
  char autor[80];
  int pages;
};

int comparator(const void * a, const void *b)
{
  struct book * ia = (struct book*)a;
  struct book * ib = (struct book*)b;
  return (strcmp(ia->autor, ib->autor));
}

int main(int argc, char ** argv)
{
  int c = 3;
  int i;

  //Pointer to array of struct pointers, malloc for 2 structs
  struct book* ptr = (struct book*) malloc(c*sizeof(struct book));

  if (ptr == NULL) {
    printf("Could not allocate data\n");
    return 1;
  }

  for (i = 0;i<c;i++) {
    printf("Title: ");
    scanf("%s", ptr[i].title);
    printf("Autor: ");
    scanf("%s", ptr[i].autor);
  }
  for (i = 0;i < c;i++) {
    printf("Before Quick sort Autor: %s, Title : %s \n", ptr[i].autor, ptr[i].title);
  }
  qsort(ptr, c, sizeof(struct book), comparator);
  printf("QSORT Done...\n\n");
  for (i = 0;i<c;i++) {
    printf("TEST");
    printf("After quick sort: Autor: %s, Title: %s \n", ptr[i].autor, ptr[i].title);
  }

  free(ptr);

  return 0;
}

3) Finally, it is a good practice to test the result of your malloc and to call free when you don't need it anymore.

I'm going to give you an answer which will keep the definition of ptr, which is a pointer to a pointer to struct book , and also change a minimal amount of your code. This means we will allocate an array of pointers to struct book , and then for each pointer in that array we will allocate an actual object struct book .

The first malloc will allocate an array of c pointers to struct book :

struct book **ptr = (struct book**)malloc(c*sizeof(struct book*));

The for loop which allocates an object struct book using malloc is then correct.

The second correction is at the qsort() call. We are sorting pointers to struct book , not actual objects struct book .

qsort(ptr,4, sizeof(struct book*), comparator);

Then the comparison function needs a fix. Since we are sorting pointers, the comparison function will return a pointer to a pointer to struct book . So we need to dereference that pointer to our pointer to struct book :

int comparator (const void * a, const void *b)
{
    struct book* ia=*(struct book**)a;
    struct book* ib=*(struct book**)b;
    return (strcmp(ia->autor,ib->autor));
}

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