一个C程序,按名称或年份对飓风进行排序

时间:2017-04-13 06:32:13

标签: c file sorting

我需要编写一个程序,用飓风数据加载文件中的数据(如年份,名称,受影响的状态)
数据文件如下所示:

1960 Dnna Fl,NC
1972年Agnes FL
1969年Camile MS

用户将能够选择飓风是按年份还是按名称排序。 sort函数应使年份列表和受影响的状态列表与飓风名称保持平行。允许最多30个飓风,但使用常数宏来获得此数字,以便日后轻松扩展数据库。

如果按年份排序,他们希望输出看起来像这样 年名称国家
1960 Donna FL,NC
1969年卡米尔MS
1972年Anges FL

我想我不会正确地解决这个问题。我只是无法弄清楚如何对数组进行排序并打印出来。每次我只是尝试打印数组以确保它加载了正确的数据,我只是得到一堆垃圾,或者它只是崩溃。

这是最好的代码(如果你可以称之为)  到目前为止。

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

#define Numof_Hurricane 23

char Hurrican_data[Numof_Hurricane][3];
char temp[Numof_Hurricane][3];

int i,j;
char HowSort;

int cmp ( const void *pa, const void *pb ) {
    const char (*a)[4] = pa;
    const char (*b)[4] = pb;
    return strcmp(*a, *b);
}
// start of program
int main()
{

    FILE *Hurrican;
    Hurrican = fopen("hurricane_data.txt","r");   // the data file for Hurricanes 
    if (Hurrican==NULL)
    {
        printf("ERROR: File failed to open\n");
        fclose(Hurrican);

    }
    for(i=0; i<30; i++)
    {
        for(j=0; j<3; j++)
        {
            fscanf(Hurrican," %s", &Hurrican_data[i][j]);    //loads data into array
        }
    }
    fclose(Hurrican);
    printf("How would you like to sort the data?\n"
            "(by Year or Name, use Y for year and N for name)");   // ask how user wants to sort it
    scanf(" %c", &HowSort);
    if (HowSort == 'Y'|| HowSort == 'y')                                     //sort by year
    {
        printf("\nYou chose to sort by year");
//I plan on adding a function here to sort by year

// my atempt to sort by year
     qsort(Hurrican_data, 1, sizeof Hurrican_data[0], cmp );

// To print sorted data
      for ( i = 0 ; i < Numof_Hurricane ; i++ ) 
      {
        for ( j = 0 ; j < 4 ; j++ )
        {
            printf( "%s ", Hurrican_data[i][j] );
        }
        printf("\n");
      }
    }
        else
        {
            printf("\nYou chose to sort by name");
// I plan to put a function here to sort by Name
        }
    return 0;
}

1 个答案:

答案 0 :(得分:0)

此代码中的错误:

fclose调用错误

if (Hurrican==NULL)
{
    printf("ERROR: File failed to open\n");
    fclose(Hurrican); /// HERE
}

fclose毫无意义,是崩溃的秘诀。您刚刚确定fopen的结果为NULL。因此,文件没有打开。因此,文件指针不是你可以关闭的东西。如果文件无法打开,则没有理由继续该程序:

if (Hurrican==NULL)
{
    perror("hurricane_data.txt: ");
    return EXIT_FAILURE;
}

数组大小错误。

鉴于您的数据如下所示:

1960 Dnna Fl,NC
1972 Agnes FL
1969 Camile MS

并且您的加载器循环尝试将此内容读入此内容:

#define Numof_Hurricane 23

char Hurrican_data[Numof_Hurricane][3];

使用此循环:

for(i=0; i<30; i++) // HERE: 30??? What about that 23 ??
{
    for(j=0; j<3; j++)
    {
        // HERE: Each of these can be no longer than TWO chars wide.
        fscanf(Hurrican," %s", &Hurrican_data[i][j]);
    }
}

这假设文件中总共有30个项目,分配明确指出可能,但不是精确&#34;允许最多30次飓风......&#34; 意味着可能有30个,但也可能有一个,五个甚至 。真的在伤口上倒盐,你在一个只有 23 元素宽的阵列核心阵列上循环到三十个(一路上溢出的缓冲区,更多在下面)。如果有三十个元素,则会在第二十四行突破您的主阵列。

此外,您的加载器外观是(a)未选中,以及(b)每次读取时缓冲区溢出的配方。考虑第一行1960上的第一个字符串值。该字符串长度为四个个字符;五个包括终结符,但你试图将它推入一个只有三个字符宽的缓冲区。

打破排序算法

您的排序循环正在对名称的第一个字符进行排序。这是错的。

不同的方法

算法很简单:

  • 定义结构Hurricane,其中包含三个字段
    • year - 一个简单的整数
    • name - 长度合理的字符缓冲区
    • states - 一个char缓冲区,能够用逗号分隔符保存足够数量的状态缩写。
  • 您的整体数据阵列最多包含30个这样的结构序列。
  • 一次从文件中读取一个完整行的数据。 256个字符的行长度应足以容纳数据。
  • 每行分析年份,名称和字符串列表。
  • 将它们作为一个完整的实体存储在结构数组中。
  • 使用此结构数组进行排序操作。

结果代码如下所示:

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

#define MAX_DATA        30
#define MAX_NAME_LEN    64
#define MAX_STATES_LEN  151

struct Hurricane
{
    int year;
    char name[MAX_NAME_LEN];
    char states[MAX_STATES_LEN];
};

struct Hurricane data[MAX_DATA];


void print_data(const struct Hurricane ar[], int size)
{
    for (int i=0; i<size; ++i)
        printf("%d %s %s\n", ar[i].year, ar[i].name, ar[i].states);
}


void sort_year(struct Hurricane ar[], int size)
{
    int swapped = 1;
    while (swapped && size--)
    {
        swapped = 0;
        for (int i=0; i<size; ++i)
        {
            if (ar[i].year > ar[i+1].year)
            {
                swapped = 1;
                struct Hurricane tmp = ar[i];
                ar[i] = ar[i+1];
                ar[i+1] = tmp;
            }
        }
    }
}


void sort_name(struct Hurricane ar[], int size)
{
    int swapped = 1;
    while (swapped && size--)
    {
        swapped = 0;
        for (int i=0; i<size; ++i)
        {
            if (strcmp(ar[i].name, ar[i+1].name) > 0)
            {
                swapped = 1;
                struct Hurricane tmp = ar[i];
                ar[i] = ar[i+1];
                ar[i+1] = tmp;
            }
        }
    }
}


// start of program
int main()
{
    int count=0, i;
    char line[256];
    char HowSort;

    FILE *fp = fopen("hurricane_data.txt","r");   // the data file for Hurricanes
    if (fp==NULL)
    {
        printf("ERROR: File failed to open\n");
        fclose(fp);
    }

    // read until we are full or no more data
    for (i=0; (i < MAX_DATA && fgets(line, sizeof(line), fp)); )
    {
        if (sscanf(line, "%d %63s %150s", &data[i].year, data[i].name, data[i].states) == 3)
            ++i; // only increment if we got good data
    }

    // save the number of successful reads.
    count = i;

    // close the file
    fclose(fp);


    printf("How would you like to sort the data?\n"
           "(by Year or Name, use Y for year and N for name)");   // ask how user wants to sort it
    scanf(" %c", &HowSort);
    if (HowSort == 'Y'|| HowSort == 'y')
    {
        printf("\nYou chose to sort by year");
        sort_year(data, count);
    }
    else if (HowSort == 'N' || HowSort == 'n')
    {
        printf("\nYou chose to sort by year");
        sort_name(data, count);
    }
    print_data(data, count);

    return EXIT_SUCCESS;
}

我没有机会测试这个,但它可能非常接近你想要的。两种情况下的排序算法都是简单的冒泡排序。对于真实世界的等价,我们将创建适当的qsort比较函数并使用标准库,特别是如果元素的数量明显大于几十个。但是,就我们的目的而言,这已足够。请参阅qsort() here的文档和示例。

最重要的是,请注意,通过使用一个结构来保存记录而不是将其展现在一系列字符缓冲区中,您不仅可以获得正确类型的好处(例如,年份为int),你可以获得更好的数据管理,最重要的是,很多更容易在排序例程中交换元素(结构值交换ftw)。

无论如何,这就是我认为你正在尝试做的事情。