Qsort удаляет первый элемент из массива (char *) - PullRequest
1 голос
/ 23 января 2020

Я очень новичок в C и пытаюсь использовать qsort () с массивом указателей на символы. Это не сортировка массива по алфавиту, как я ожидал, и он удаляет первый элемент. Я попытался настроить все аргументы, включая функцию сравнения, но мне не удалось выяснить, в чем дело.

Введите слово: foo
Введите слово: bar
Введите слово: baz
Введите слово: quux

Ожидается:
bar
baz
foo
quux

Результат:

бар
баз
quux

Мой код:

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

#define MAX_WORDS 10
#define MAX_LENGTH 20

int read_line(char str[], int n);
int compare(const void *a, const void *b);

int main(void) {
  char *words[MAX_WORDS], word[MAX_LENGTH + 1];
  int i;

  for(i = 0; i < MAX_WORDS; i++) {
    printf("Enter word: ");
    read_line(word, MAX_LENGTH);

    words[i] = malloc(strlen(word) + 1);
    if(!words[i]) {
      printf("Allocation of memory failed...\n");
      exit(EXIT_FAILURE);
    }

    strcpy(words[i], word);

    if(!strlen(words[i]))
      break;
  }

  qsort(words[0], i, sizeof(char *), compare);

  for(int j = 0; j <= i; j++) {
    printf("%s\n", words[j]);
  }

  return 0;
}

int read_line(char str[], int n) {
  int ch, i;

  while((ch = getchar()) != '\n') {
    if(i < n)
      str[i++] = ch;
  }
  str[i] = '\0';

  return i;
}

int compare(const void *a, const void *b) {
  return strcmp((char *) a, (char *) b);
}

Ответы [ 2 ]

3 голосов
/ 23 января 2020

Три ошибки.

  1. qsort требуется указатель на первый элемент сортируемого массива.

    Заменить

    qsort(words[0], i, sizeof(char *), compare);
    

    с

    qsort(&( words[0] ), i, sizeof(char *), compare);
    

    или просто

    qsort(words, i, sizeof(char *), compare);
    

    Эта последняя версия работает, потому что массив, используемый там, где ожидается указатель, распадается на указатель на его первый элемент.

  2. Функция сравнения передает указатели на элементы сортируемого массива. Поскольку вы сортируете массив указателей, это означает, что в вашем случае функция сравнения передает указатели на эти указатели (char**). Таким образом, compare должно быть

    static int compare(const void *a, const void *b) {
      return strcmp(*(char **)a, *(char **)b);
    }
    

    Еще лучше:

    static int compare(const void *a, const void *b) {
      return strcmp(*(char * const *)a, *(char * const *)b);
    }
    
  3. Ваш последний l oop имеет слишком много проходов.

    Если i<MAX_WORDS (потому что была введена пустая строка), это приведет к тому, что будет пустая строка (потому что words[i] содержит строку нулевой длины). Если i==MAX_WORDS, это вызывает Неопределенное поведение (поскольку words[i] находится за концом массива).

    Заменить

    for(int j = 0; j <= i; j++)
    

    на

    for(int j = 0; j < i; j++)
    
0 голосов
/ 23 января 2020

Проблема в том, что вы передаете (просто) первую строку в qsort, а не адрес массива. Вам нужно

 qsort(words, i, sizeof(char *), compare);

Как только вы исправите это, вы обнаружите, что ваша процедура сравнения неверна, так как она вызывается с адресами элементов массива слов, а не со значениями в нем. Так что вам нужно

int compare(const void *a, const void *b) {
    return strcmp(*(char **) a, *(char **) b);
}

, чтобы на самом деле извлечь char * из массива и сравнить строки.

...