简体   繁体   English

从C中的typedef结构排序数组

[英]Sorting array from typedef struct in C

Problem : Trying to sort an array coming from a typedef struct I created (phonebook). 问题 :尝试对来自我创建的typedef结构(电话簿)的数组进行排序。

Goal : Trying to build a phonebook that allows users to add, delete, sort, and print the phonebook. 目标 :尝试构建一个允许用户添加,删除,排序和打印电话簿的电话簿。

Where I'm at : I've got everything working except the sort. 我在哪里 :除了排序外,我的一切都在运作。 I've cobbled together a sort function from reading various web forums/examples, but can't get it to work. 我通过阅读各种网络论坛/示例拼凑了一个排序函数,但无法让它工作。

Issue I'm having : After adding entries (which works fine), if you try to sort entries, the function zeroes out values of those entries and when you print the phonebook, it shows all entries as blank. 我遇到的问题 :添加条目(工作正常)后,如果您尝试对条目进行排序,该函数会将这些条目的值清零,当您打印电话簿时,它会将所有条目显示为空白。 It should sort them alphabetically by last name. 它应按姓氏的字母顺序排序。

Here's the sort algorithm I have in place: 这是我的排序算法:

void Sort (phone phonebook[])
{
    phone temp;
    int i;  int j;

    for (i=0; i<19; i++)
    {
        for (j=i+1; j<19; j++)
        {
            if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0)
            {
                temp=phonebook[i];
                phonebook[i]=phonebook[j];
                phonebook[j]=temp;

            }
        }
    }
}

Any ideas? 有任何想法吗?


Full code here: 完整代码:

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

//typedef struct to define what's in the phonebook
typedef struct PhoneBookContacts
{
    char Name[20];
    char Surname[20];
    char PhoneNumber[20];
} phone;

//Function prototypes
void AddEntry (phone[]);
void DeleteEntry (phone[]);
void PrintEntry (phone[]);
void Sort (phone[]);
int counter = 0; //Global counter variable used to keep track of number of contacts

//Begin main function
int main (void)
{
    phone phonebook[20]; //Phonebook instance
    char userChoice; //Variable to use to select menu choice

    while (userChoice != 'Q') {
        printf ("***************\n");
        printf ("Please enter a command:\n");
        printf("'A': Add an entry\n");
        printf("'D': Delete an entry\n");
        printf("'S': Sort entries\n");
        printf("'P': Print the phonebook\n");
        printf("'Q': Quit\n");
        printf ("***************\n");

        scanf("%s", &userChoice);  //Stores menu choice into variable userChoice

        // Add Contact
        if (userChoice == 'A')
            AddEntry(phonebook);

        //Remove Contact
        if (userChoice == 'D')
            DeleteEntry (phonebook);

        //Print Contacts
        if (userChoice == 'P')
            PrintEntry(phonebook);

        //Sort Contacts
        if (userChoice == 'S')
            Sort(phonebook);

        //Quit
        if (userChoice == 'Q') {
            printf("Phonebook will now quit.");
            return 0;
        }
    }
}

//Function Definition to Add Contacts to the Phonebook
void AddEntry (phone phonebook[]) {
    counter++; //global counter increase

    printf("\nFirst Name: ");
    scanf("%s", phonebook[counter-1].Name); //counter-1 b/c arrays start at 0

    printf("Last Name: ");
    scanf("%s", phonebook[counter-1].Surname);

    printf("Phone Number (XXX-XXX-XXXX): ");
    scanf("%s", phonebook[counter-1].PhoneNumber);

    printf("\n%s added to phonebook\n", phonebook[counter-1].Name); //tell user friend added
}

void DeleteEntry (phone phonebook[])
{
    int x = 0;
    char deleteName[20];  // Temp string to compare to existing phonebook
    char deleteSurname[20];  //temp string
    char nullStr[20] = {"\0"};  // empty string to remove phonenumber

    printf("\nEnter name: ");
    scanf("%s", deleteName); //place into temp string
    printf("Enter Surname: ");
    scanf("%s", deleteSurname); //place into temp string

    for (x = 0; x < counter; x++)
    {
        if (strcmp(deleteName, phonebook[x].Name) == 0) //compare deleteName to phonebook.Name
        {
            for (x = 0; x < counter; x++)
            {
                if (strcmp(deleteSurname, phonebook[x].Surname) == 0) //If deleteSurname matches phonebook.Surname
                {
                    strcpy(phonebook[x].Name, nullStr); //Put null into Name
                    strcpy(phonebook[x].Surname, nullStr); //Null into Surname
                    strcpy(phonebook[x].PhoneNumber, nullStr); //Null into PhoneNumber
                    printf("Contact removed from phonebook.\n");
                    counter--;
                    break;
                }
            }

        }
        else printf("Invalid entry--try again.\n");
    }
}

// Function def to print contacts
void PrintEntry (phone phonebook[]) {
    int x = 0;
    printf("\nPhonebook entries:\n");

    for ( x = 0; x < counter; x++) {
        printf("\n(%d)\n", x+1); //Show contact number
        printf("Name: %s %s\n", phonebook[x].Name, phonebook[x].Surname); //Name
        printf("Number: %s\n", phonebook[x].PhoneNumber); //Number
    }
}

void Sort (phone phonebook[]) {
    phone temp;
    int i;  int j;

    for (i=0; i<19; i++) {
        for (j=i+1; j<19; j++) {
            if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0) {
                temp=phonebook[i];
                phonebook[i]=phonebook[j];
                phonebook[j]=temp;
            }
        }
    }
}

You can use the already implemented sorting function qsort function available at stdlib.h : 您可以使用stdlib.h已经实现的排序函数qsort函数:

int SortFunc(void* a, void* b) {
    phone *p1 = (phone*)a;
    phone *p2 = (phone*)b;

    return strcmp(p1->Surname, p2->Surname);
}

void Sort (phone phonebook[]) {
    qsort(phonebook, counter, sizeof(phone), &SortFunc);
} 

The function is usually Quicksort , but that's up to the C library implementation to decide. 该函数通常是Quicksort ,但这取决于C库实现的决定。

Update: 更新:

The blank listing is because the sorting is reversed and always sorting all the 19 items of the phonebook, comparing the empty ones against the real ones. 空白列表是因为排序是相反的并且总是对电话簿的所有19个项目进行排序,将空白的项目与真实的项目进行比较。 If you have less than 19 entries on the phonebook, the actual data is going to be present at the end of the phonebook array. 如果电话簿上的条目少于19个,则实际数据将出现在电话簿阵列的末尾

Your original Sort function was always working almost OK. 您原来的排序功能总是工作几乎确定。 Just change the end condition on the two for. 只需更改两者的结束条件即可。

void Sort (phone phonebook[]) {
    phone temp;
    int i;  int j;

    for (i=0; i<counter; i++) {
        for (j=i+1; j<counter; j++) {
            if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0) {
                temp=phonebook[i];
                phonebook[i]=phonebook[j];
                phonebook[j]=temp;
            }
        }
    }
}

I've also updated my Sort above. 我还更新了我的Sort

First things first, you have a buffer overflow issue here: 首先,你有一个缓冲区溢出问题:

char userChoice;
:
scanf("%s", &userChoice);

That scanf will write two bytes when you enter one character (the character plus a null terminator). 当您输入一个字符(该字符加上一个空终止符)时,该scanf将写入两个字节。 This corrupted the first name of the first phonebook entry in my environment but, since it's undefined behaviour, it could do anything! 这破坏了我环境中第一个电话簿条目的名字,但由于它是未定义的行为,它可以做任何事情!

You can get around this by using: 您可以使用以下方法解决此问题:

char userChoice[] = "something that's not Q";
: 
scanf("%s", userChoice);
:
if (*userChoice == 'A')  // for all of these.

That won't stop a buffer overflow if you enter enough text but it will if you limit yourself to single character commands. 如果您输入足够的文本,这将不会停止缓冲区溢出,但如果您将自己限制为单个字符命令,它将会停止。 If you want a truly robust user input function, see here . 如果您想要一个真正强大的用户输入功能,请参见此处


Now to your specific problem. 现在针对您的具体问题。 It looks like you have a bit of a bubble sort going on there, but your logic is slightly off. 看起来你有一些泡泡排序,但你的逻辑略有偏差。 Assuming you don't want to use qsort (which would be the better way for real code), you just need to fix up a couple of things. 假设您不想使用qsort (这对于实际代码来说是更好的方法),您只需要修复一些事情。

Your outer loop is okay, as is your inner loop, but the inner loop body should be comparing elements j and j+1 , not j and i . 你的外循环是好的,你的内循环也是如此,但内循环体应该是比较元素jj+1 ,而不是ji That's because it works by swapping adjacent elements if they're out of order. 这是因为如果它们出现故障,它可以通过交换相邻元素来实现。

In addition, a forward focused bubble sort will place the highest element at the end of the list on the first pass, so you can't start j at i+1 on the second pass, simply because the first element may not be correct yet. 此外,前向聚焦的冒泡排序会在第一遍中将最高元素放在列表的末尾 ,因此您无法在第二遍中以i+1开始j ,只是因为第一个元素可能不正确。

The following psuedo-code is your classic bubble sort: 以下伪代码是您的经典冒泡排序:

didSwap = true
while didSwap:
    didSwap = false
    for i = 0 to lastidx - 1:
        if array[i] > array[i+1]:
            temp = array[i]
            array[i] = array[i+1]
            array[i+1] = temp
            didSwap = true

Read that, understand how it works, then implement it on your own. 阅读,了解它是如何工作的,然后自己实现。 If you have trouble with that, I've included a working version below: 如果您遇到问题,我在下面列出了一个工作版本:

void Sort (phone phonebook[]) {
    phone temp;
    int i;  int didSwap;

    didSwap = 1;
    while (didSwap) {
        didSwap = 0;
        for (i = 0; i < counter - 1; i++) {
            if (strcmp(phonebook[i].Surname, phonebook[i+1].Surname) > 0) {
                temp=phonebook[i];
                phonebook[i]=phonebook[i+1];
                phonebook[i+1]=temp;
                didSwap = 1;
            }
        }
    }
}
for (i=0; i<19; i++)
{ 
    for (j=i+1; j<19; j++)

    {
        if (strcmp(phonebook[i].Surname, phonebook[j].Surname) > 0)
        {
            temp=phonebook[i];
            phonebook[i]=phonebook[j];
            phonebook[j]=temp;

        }

    }
}

Three problems with your code. 你的代码有三个问题。 First is the logic of your algorithm. 首先是算法的逻辑。 Bubble sort works by fixing the order of two adjacent element. 冒泡排序通过固定两个相邻元素的顺序来工作。 In your code, after the first iteration of your inner for loop, it's not going to compare two adjacent elements. 在你的代码中,在你的内部for循环的第一次迭代之后,它不会比较两个相邻的元素。

The second problem, again in sorting algorithm, your counters i and j are both going to 19, even when there is less entries than that. 第二个问题,再次在排序算法中,你的计数器ij都是19,即使条目少于那个。 This might mess up the sorting as they will be reading invalid(uninitialized) entry. 这可能会导致排序混乱,因为它们将读取无效(未初始化)条目。 you should check the upper bound for the counter. 你应该检查柜台的上限。

The next one is in the deletion 下一个是删除

    if (strcmp(deleteName, phonebook[x].Name) == 0) //compare deleteName to phonebook.Name 
    {
        for (x = 0; x < counter; x++)
        {
            if (strcmp(deleteSurname, phonebook[x].Surname) == 0) //If deleteSurname matches phonebook.Surname
            {
                strcpy(phonebook[x].Name, nullStr); //Put null into Name
                strcpy(phonebook[x].Surname, nullStr); //Null into Surname
                strcpy(phonebook[x].PhoneNumber, nullStr); //Null into PhoneNumber
                printf("Contact removed from phonebook.\n");
                counter--;
                break;
            }

        }

    }

The code above will not check properly whether the first and last name since you're checking them separately. 上面的代码无法正确检查自您单独检查后的名字姓氏。 You only need one for loop with if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 ) 你只需要一个if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 ) for循环if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM