C结构数组上的冒泡排序没有正确排序

时间:2013-10-23 19:18:52

标签: c pointers structure

我有以下书籍记录程序,我想对书籍name上的记录进行排序。代码没有显示任何错误,但它没有排序所有记录。

#include "stdio.h"
#include "string.h"
#define SIZE 5

struct books{                                      //define struct
        char name[100],author[100];
        int year,copies;
    };

struct books book1[SIZE],book2[SIZE],*pointer;          //define struct vars

void sort(struct books *,int);                      //define sort func

main()
{
    int i;
    char c;

for(i=0;i<SIZE;i++)             //scanning values
{
    gets(book1[i].name);
    gets(book1[i].author);
    scanf("%d%d",&book1[i].year,&book1[i].copies);
    while((c = getchar()) != '\n' && c != EOF);
}
pointer=book1;
sort(pointer,SIZE);                 //sort call

i=0;                        //printing values
while(i<SIZE)
{
    printf("##########################################################################\n");
    printf("Book: %s\nAuthor: %s\nYear of Publication: %d\nNo of Copies: %d\n",book1[i].name,book1[i].author,book1[i].year,book1[i].copies);
    printf("##########################################################################\n");
    i++;
}
}

void sort(struct books *pointer,int n)
{
    int i,j,sorted=0;
    struct books temp;
for(i=0;(i<n-1)&&(sorted==0);i++)       //bubble sort on the book name
{
    sorted=1;
    for(j=0;j<n-i-1;j++)
    {
        if(strcmp((*pointer).name,(*(pointer+1)).name)>0)
        {
            //copy to temp val
            strcpy(temp.name,(*pointer).name);
            strcpy(temp.author,(*pointer).author);
            temp.year=(*pointer).year;
            temp.copies=(*pointer).copies;

            //copy next val
            strcpy((*pointer).name,(*(pointer+1)).name);
            strcpy((*pointer).author,(*(pointer+1)).author);
            (*pointer).year=(*(pointer+1)).year;
            (*pointer).copies=(*(pointer+1)).copies;

            //copy back temp val
            strcpy((*(pointer+1)).name,temp.name);
            strcpy((*(pointer+1)).author,temp.author);
            (*(pointer+1)).year=temp.year;
            (*(pointer+1)).copies=temp.copies;

            sorted=0;
        }
                *pointer++;
    }
}
}

我的Imput

The C Programming Language
X Y Z
1934
56
Inferno
Dan Brown
1993
453
harry Potter and the soccers stone
J K Rowling
2012
150
Ruby On Rails
jim aurther nil
2004
130
Learn Python Easy Way
gmaps4rails
1967
100  

输出

##########################################################################
Book: Inferno
Author: Dan Brown
Year of Publication: 1993
No of Copies: 453
##########################################################################
##########################################################################
Book: The C Programming Language
Author: X Y Z
Year of Publication: 1934
No of Copies: 56
##########################################################################
##########################################################################
Book: Ruby On Rails
Author: jim aurther nil
Year of Publication: 2004
No of Copies: 130
##########################################################################
##########################################################################
Book: Learn Python Easy Way
Author: gmaps4rails
Year of Publication: 1967
No of Copies: 100
##########################################################################
##########################################################################
Book: 
Author: 
Year of Publication: 0
No of Copies: 0
##########################################################################

我们可以看到上面的排序是错误的吗?我做错了什么?

1 个答案:

答案 0 :(得分:2)

代码存在许多问题。最明显的语义错误是你弄乱了指针(你在内部循环中递增指针但你从不重新设置它),因此代码将在第二次迭代时通过读取和写入未分配的内存来调用未定义的行为

第二个问题是你的冒泡排序算法错误 - 如果你正在冒泡,那么你必须从n - 10向下运行外循环,否则,第一次迭代将无法移动第一个(也可能是最大的)元素。外循环的后续迭代继承了相同的行为。

其余问题与可读性,风格,设计和安全性有关。一个是你写的(*pointer).member应该为上帝的爱写成pointer->member。另一个类似的是(*(pointer + index)).member ......那可能就是pointer[index].member。缺少正确的格式,缩进和空格是第三个问题,使用#include ""代替#include <>标准库标题是第四个问题。

使用gets()也是一个坏主意,因为它不允许您指定导致潜在缓冲区溢出的缓冲区大小。应始终首选fgets()

代码重复和冗余很糟糕 - 你应该总是尝试通过将重复性任务(例如复制books结构)拉出来进行程序分解(这是几乎亵渎神明的“重构”事情......)他们自己的职能。命名变量是另一个重要的设计。不要打电话给pointer,这对读者没有帮助(在阅读你的代码时,我很想知道,很长一段时间,什么指针是一个指针...)

您应该尽可能避免使用全局变量。在您的情况下,绝对不需要任何全局变量,因此没有什么能够证明它们的使用是正确的。另一个好的做法是将私有帮助函数声明为static,这样可以降低名称冲突的风险。

最后一个要点是:不要滥用评论。

这样的行
sort(books, SIZE); // call sort function

没用。除了排序sort(books, SIZE)数组之外,books 可能还有什么意思(在设计良好的代码库中)?

总而言之,这就是我编写代码的方式:

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

#define SIZE 5

struct book {
    char title[100];
    char author[100];
    int year;
    int copies;
};

static void sort(struct book *books, int n);

int main()
{
    int i;
    int c; // EOF is out-of-range for `char`, this MUST be an int
    struct book books[SIZE];

    for (i = 0; i < SIZE; i++) {
        fgets(books[i].title, sizeof books[i].title, stdin);
        fgets(books[i].author, sizeof books[i].author, stdin);
        scanf("%d%d", &books[i].year, &books[i].copies);
        while ((c = getchar()) != '\n' && c != EOF);
    }

    sort(books, SIZE);

    for (i = 0; i < SIZE; i++) {
        printf("##########################################################################\n");
        printf("Book: %s\nAuthor: %s\nYear of Publication: %d\nNo of Copies: %d\n", books[i].title, books[i].author, books[i].year, books[i].copies);
        printf("##########################################################################\n");
    }
}

static void swap(struct book *a, struct book *b)
{
    struct book tmp = *a;
    *a = *b;
    *b = tmp;
}

static void sort(struct book *books, int n)
{
    int i, j;
    for (i = n - 1; i >= 0; i--) {
        for (j = 0; j < i; j++) {
            if (strcmp(books[j].title, books[j + 1].title) > 0) {
                swap(&books[j], &books[j + 1]);
            }
        }
    }
}