【问题标题】:Qsort removes first element from array (char *)Qsort 从数组中删除第一个元素(char *)
【发布时间】:2020-05-09 07:07:03
【问题描述】:

我对 C 非常陌生,我正在尝试将 qsort() 与 char 指针数组一起使用。它没有像我预期的那样按字母顺序对数组进行排序,它删除了第一个元素。我已经尝试调整所有参数,包括比较函数,但我无法找出问题所在。

输入单词:foo
输入单词:bar
输入单词:baz
输入单词: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);
}

【问题讨论】:

  • 请不要编辑问题来解决问题,这是首先编写问题的原因。这使得整个问题和所有答案都毫无价值,因为如果不查看编辑历史,没有人可以看到问题。一个问题不应该是一个移动的目标。
  • @Gerhardh 知道了。

标签: c arrays sorting pointers quicksort


【解决方案1】:

三个错误。

  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. 你的最后一个循环有一个太多的传递。

    如果i&lt;MAX_WORDS(因为输入了一个空行),这将导致发出一个空行(因为words[i] 包含一个零长度的字符串)。如果i==MAX_WORDS,这将调用Undefined Behaviour(因为words[i] 超出了数组的末尾)。

    替换

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

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

【讨论】:

    【解决方案2】:

    问题是您将(仅)第一个字符串传递给 qsort,而不是数组的地址。你需要

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

    一旦你解决了这个问题,你会发现你的比较例程是不正确的,因为它是用单词数组元素的地址调用的,而不是其中的值。所以你需要

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

    从数组中实际获取 char * 并比较字符串。

    【讨论】:

    • 谢谢!它有效,但我有点困惑为什么我需要做 *(char **)。 (char **) a 指向哪里?
    • @Eric Leus,我的回答中解释了这一点和其他事情。它还确定了此答案遗漏的第三个问题。
    猜你喜欢
    • 2017-02-25
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    相关资源
    最近更新 更多