2015-05-18 2 views
0

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

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h> 
#include <math.h> 
#include <stdlib.h> 
#include <string.h> 

#define MAX 50 

struct address 
{ 
    char name[50]; 
    char street[50]; 
    char citystate[50]; 
    char zip[20]; 
}; 

int main() 
{ 
    struct address *ptr[50]; 
    struct address tptr; 
    char buffer[80]; 
    int count = 0; 

    for (int i = 0; i <MAX; i++) 
    { 
     ptr[i] = malloc(sizeof(struct address)); 

     if (gets(buffer)== NULL) 
     { 
     break; 
     } 
     else 
     { 
     strcpy((*ptr[i]).name, buffer); 
     gets((*ptr[i]).street); 
     gets((*ptr[i]).citystate); 
     gets((*ptr[i]).zip); 
     free(ptr[i]); 
     count++; 
     } 
    } 

    for (int x = 0; x<count; x++) 
    { 
     for (int y = 0; y<count - 1; y++) 
     { 
     if ((*ptr[y]).zip>(*ptr[y + 1]).zip) 
     { 
      tptr = ptr[y + 1]; 
      ptr[y + 1] = ptr[y]; 
      ptr[y] = tptr; 
     } 
     } 
    } 

    for (int i = 0; i < count; i++) 
    { 
     puts((*ptr[i]).name); 
     puts((*ptr[i]).street); 
     puts((*ptr[i]).citystate); 
     puts((*ptr[i]).zip); 
    } 
} 
+3

http://www.cplusplus.com/reference/cstdlib/qsort/ – jangler

+2

Начните с отступывания своего кода, чтобы люди (включая себя) могли его прочитать! –

+0

Фактически, перед этим, опубликуйте что-то, что скомпилируется. В строке 'gets (buffer)' '' buffer' не был объявлен. (Конечно, 'get' тоже является ошибкой). –

ответ

2

Проблемы, которые я вижу в вашем коде:

  1. Вы используете gets. См. another SO post, который обращается к полему с использованием gets. Вместо этого используйте fgets.

    if (fgets(buffer, sizeof(buffer), stdin)== NULL) 
    
    fgets((*ptr[i]).street, sizeof((*ptr[i]).street), stdin); 
    fgets((*ptr[i]).citystate, sizeof((*ptr[i]).citystate), stdin); 
    fgets((*ptr[i]).zip, sizeof((*ptr[i]).zip), stdin); 
    
  2. Вы вызываете free на указатель в следующей строке

    free(ptr[i]); 
    

    и продолжают использовать его позже в коде. Удалите эту строку. Добавьте код, чтобы освободить выделенную память в конце функции.

    for (int i = 0; i < count; i++) 
    { 
        free(ptr[i]); 
    } 
    
  3. Вы присваиваете struct address* переменной типа struct address в следующей строке:

    tptr = ptr[y + 1]; 
    

    и вы присваиваете struct address переменной типа struct address* в следующей строке:

    ptr[y] = tptr; 
    

    оба они могут быть изменены путем изменения типа tptr на struct address*.

    struct address *tptr; 
    
  4. Следующий код не подходит для сравнения двух строк:

    if ((*ptr[y]).zip>(*ptr[y + 1]).zip) 
    

    это только сравнивает два значения указателя. Используйте

    if (strcmp((*ptr[y]).zip,(*ptr[y + 1]).zip) > 0) 
    
0
  1. Почему вы хотите free() выделенной памяти, как только вы запрашиваете данные от пользователя?
  2. Вы должны free() выделенной памяти в конце программы, после завершения печати.
  3. struct address tptr; должно быть типа struct address *tptr;, поскольку вы назначаете значение указателя.

Ниже приведены изменения: 1.

for (int i = 0; i <MAX; i++) 
{ 
    ptr[i] = malloc(sizeof(struct address)); 

    if (gets(buffer)== NULL) 
    { 
     free(ptr[i]); /* free the memory if data not read */ 
     break; 
    } 
    else 
    { 
     strcpy((*ptr[i]).name, buffer); 
     gets((*ptr[i]).street); 
     gets((*ptr[i]).citystate); 
     gets((*ptr[i]).zip); 
     /* Do not free the mem here as you are bound to lose the data */ 
     count++; 
    } 
} 

2.

for (int i = 0; i < count; i++) 
{ 
    puts((*ptr[i]).name); 
    puts((*ptr[i]).street); 
    puts((*ptr[i]).citystate); 
    puts((*ptr[i]).zip); 
    free(ptr[i]); /* free the memory here */ 
} 

PS: Использование gets() не является хорошей идеей.Проверьте это Do not use gets для получения дополнительной информации

0

Во-первых, при работе с указателем на структуры правильный доступ к элементу осуществляется с помощью оператора -> (например, ptr[i]->street). Как указывали другие, НЕ используйте gets. Он больше не является частью библиотеки C и был устаревшим, потому что он был небезопасным. Вместо этого используйте fgets или getline.

Далее, (и это вопрос формы), избегайте жестких номеров в коде. Используйте #define, чтобы установить свои значения. Это позволяет легко регулировать в одном месте, если значения меняются.

При этом вы не за горами с кодом. Создание только те изменения, удаления ненужных math.h и добавления strcmp для своего рода, вы можете сортировать структуры в порядке возрастания zip следующим образом:

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

#define MAX 50 
#define MAXL 80 
#define MAXZ 20 

struct address { 
    char name[MAX]; 
    char street[MAX]; 
    char citystate[MAX]; 
    char zip[MAXZ]; 
}; 

int main() 
{ 
    struct address *ptr[MAX]; 
    struct address *tptr; 
    char buffer[MAXL]; 
    int count = 0; 

    for (int i = 0; i < MAX; i++) { 
     ptr[i] = malloc (sizeof (struct address)); 

     if (fgets (buffer, MAXL, stdin) == NULL) { 
      break; 
     } else { 
      strncpy (ptr[i]->name, buffer, MAXL); 
      ptr[i]->name[MAXL - 1] = 0; 
      fgets (ptr[i]->street, MAX, stdin); 
      fgets (ptr[i]->citystate, MAX, stdin); 
      fgets (ptr[i]->zip, MAXZ, stdin); 
      count++; 
     } 
    } 

    for (int x = 0; x < count; x++) { 
     for (int y = 0; y < count - 1; y++) { 
      if (strcmp (ptr[y]->zip, ptr[y + 1]->zip) > 0) { 
       tptr = ptr[y + 1]; 
       ptr[y + 1] = ptr[y]; 
       ptr[y] = tptr; 
      } 
     } 
    } 

    for (int i = 0; i < count; i++) { 
     printf ("\n%s", ptr[i]->name); 
     printf ("%s", ptr[i]->street); 
     printf ("%s", ptr[i]->citystate); 
     printf ("%s", ptr[i]->zip); 
    } 
} 

Входной

$ cat dat/sortaddress.txt 
some name 
my street 
my city, my state 
55512 
another name 
another street 
another city, another state 
44412 

Использование/вывода

$ ./bin/struct_address_sort <dat/sortaddress.txt 

another name 
another street 
another city, another state 
44412 

some name 
my street 
my city, my state 
55512 

примечание: чтение с fgets или getline будет читать конечный newline и включить его в буфер. Это хорошая идея, чтобы вырезать новую строку из ваших строк, чтобы у вас не было разных строк в конце ваших данных. В StackOverflow есть много примеров.

+0

Большое спасибо за вашу помощь, изменения, которые вы предложили, сделали трюк. –

+0

Рад помочь. Как я уже сказал, вы не за горами, просто нужна небольшая помощь в обработке синтаксиса структуры и 'strcmp' для сравнения с сортировкой. Вы можете использовать 'qsort' (рекомендуется для любой значительной сортировки), но для простых примеров ручная сортировка прекрасна. –

Смежные вопросы