Как мне отсортировать указатели по алфавиту на символы char ** в C?

#arrays #c #bubble-sort

#массивы #c #пузырьковая сортировка

Вопрос:

Я новичок в C. Я сделал свою собственную сортировку, чтобы отсортировать кучу строк в алфавитном порядке, и это то, что у меня есть, но strcmp, похоже, не работает? Программа просто вылетает.

 int main(void) {
   char **a = malloc(sizeof(char*));
   a[0] = "Cam";
   a[1] = "Bam";
   a[3] = "Dam";
   a[4] = "Aam";
   for (int i = 0; a[i] != ''; i  ) {
      for (int j = i 1; a[j] != ''; j  )
         if (strcmp(a[i], a[j]) > 0) {
            char* temp = a[i];
            a[i] = a[j];
            a[j] = temp;
         }
       printf("%s ", a[i]);
     }
   return 0;
}
// output should be Aam Baam Caam Daam
  

Комментарии:

1. C имеет qsort , который, даже если вы не можете его использовать, служит примером того, как вы должны организовать свой код: создайте функцию сортировки, а не просто делайте все main() .

2. Вы выделили место только для 1 указателя, но полагаетесь на то, что их 5 (один из которых, a[2] , не используется). Поэтому, конечно, он выходит из строя.

3. Подсказка: a[i] это a char* и не сопоставимо с нулевым байтом.

4. Вместо того, чтобы перебирать malloc , почему бы не просто char* a[] = { "X", "Y", ... } ? Это намного сложнее исправить, потому что вы не пропустите записи, как вы это сделали, или выделите неправильный размер, что является распространенной ошибкой. Одним из распространенных соглашений C является объявление его так { "X", ..., NULL } , чтобы вы знали, когда прекратить итерацию, и вам не нужно вычислять размер.

5. Правильный способ избежать перехода к концу массива — это иметь переменную length or size и тестировать i < size .

Ответ №1:

Три проблемы:

  1. Вы выделили место только для массива длиной 1, но использовали 5 слотов. Чтобы выделить массив размером 5, используйте char **a = malloc(5 * sizeof(char *));

  2. Вы никогда не инициализировались a[2] .

  3. a[i] != '' не имеет особого смысла, поскольку вы сравниваете указатель с символом.

Комментарии:

1. На самом деле код требует дополнительного NULL указателя в конце (как только тест исправлен для использования NULL вместо '' ). Таким образом, даже при malloc фиксированном вызове он все равно будет удаляться с конца массива (если только тест не будет изменен на использование длины массива).

Ответ №2:

В этом коде много путаницы в том, как работает C, и много простых ошибок, которых можно избежать, если уделять самое пристальное внимание мельчайшим деталям. В программировании один символ может иметь огромное значение, крошечная ошибка может кардинально изменить поведение вашего кода: от рабочего до сломанного или от безошибочного до полностью уничтоженного.

Вот более идиоматическая версия вашего кода на C:

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

int main(void) {
  // Create a local variable to represent the strings to be sorted
  char *a[] = {
    "E",
    "B",
    "C",
    "A",
    "D",
    NULL // Use NULL as a terminator
  };

  // Iterate over each entry and stop at the NULL terminator...
  for (int i = 0; a[i]; i  ) {
    for (int j = i 1; a[j]; j  ) {
      if (strcmp(a[i], a[j]) > 0) {
        char* temp = a[i];
        a[i] = a[j];
        a[j] = temp;
      }
    }
  }

  // Once the sort has wrapped, print the sorted array
  for (int i = 0; a[i]; i  ) {
    // This was erroneously inside the sorting routine before
    printf("%s ", a[i]);
  }

  printf("n");

  return 0;
}
  

Обратите внимание, что при компиляции может быть обнаружено много простых ошибок -Wall , или эквивалент, когда компилятор предупреждает ( -W ) обо всем ( all ), что он считает неправильным.

В clang вы получите предупреждения типа:

sort.c:10:28: предупреждение: сравнение указателя с нулевой символьной константой; вы имели в виду сравнение с NULL? [-Wpointer-compare]

Это помогает выявлять ошибки на ранней стадии. Помните, что в C «compiles» и «correct» часто отличаются друг от друга. Компилятор мало что проверяет в C, кроме синтаксиса. Остальное на вас, и как программист на C, вы несете большую ответственность.

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

Не торопитесь, найдите хорошие ссылки и учитесь на хороших примерах. Вы можете довольно быстро освоиться с C, как только поймете, что он будет и абсолютно не будет делать для вас.

Ответ №3:

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

Попробуйте это:

 char **a = malloc(sizeof(char*)*5);