问题:尝试对来自我创建的typedef结构(电话簿)的数组进行排序。
目标:尝试构建一个允许用户添加,删除,排序和打印电话簿的电话簿。
我在哪里:除了排序外,我已经完成了所有工作。我通过阅读各种网络论坛/示例拼凑了一个排序函数,但无法让它工作。
问题我有:添加条目(工作正常)后,如果您尝试对条目进行排序,该函数会将这些条目的值清零,当您打印电话簿时,它会显示所有条目条目为空白。它应按姓氏的字母顺序排序。
这是我的排序算法:
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;
}
}
}
}
有什么想法吗?
完整代码:
#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;
}
}
}
}
答案 0 :(得分:6)
您可以使用qsort
处提供的已实现的排序功能stdlib.h
功能:
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);
}
该函数通常是Quicksort,但这取决于C库实现的决定。
<强>更新强>
空白列表是因为排序是相反的,并且总是对电话簿的所有19个项目进行排序,将空白的项目与真实的项目进行比较。如果电话簿上的条目少于19个,则实际数据将出现在电话簿阵列的 end 中。
您的原始排序功能始终正常几乎确定。只需更改两者的结束条件即可。
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;
}
}
}
}
我还更新了上面的Sort
。
答案 1 :(得分:1)
首先,你有一个缓冲区溢出问题:
char userChoice;
:
scanf("%s", &userChoice);
当您输入一个字符(字符加上空终止符)时,scanf
将写入两个字节。这破坏了我环境中第一个电话簿条目的名字,但由于它是未定义的行为,它可以做任何事情!
您可以使用以下方法解决此问题:
char userChoice[] = "something that's not Q";
:
scanf("%s", userChoice);
:
if (*userChoice == 'A') // for all of these.
如果您输入足够的文本,那将不会停止缓冲区溢出,但如果您将自己限制为单个字符命令,它将会停止。如果您想要一个真正强大的用户输入功能,请参阅here。
现在针对您的具体问题。看起来你有一些泡泡排序,但你的逻辑略有偏差。假设你不想使用qsort
(这对于真正的代码来说是更好的方法),你只需要解决一些问题。
您的外循环是正常的,内循环也是如此,但内循环体应该比较元素j
和j+1
,而不是j
和i
。那是因为它可以通过交换相邻的元素来工作,如果它们出现故障。
此外,向前聚焦的冒泡排序会在第一遍中将最高元素放置在列表的 end 中,因此您无法启动{{1在j
的第二遍,只是因为第一个元素可能还不正确。
以下伪代码是您的经典冒泡排序:
i+1
阅读,了解它是如何工作的,然后自己实现。如果您遇到问题,我在下面列出了一个工作版本:
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
答案 2 :(得分:0)
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;
}
}
}
您的代码存在三个问题。首先是算法的逻辑。冒泡排序通过固定两个相邻元素的顺序来工作。在您的代码中,在内部for
循环的第一次迭代之后,它不会比较两个相邻的元素。
第二个问题,再次在排序算法中,您的计数器i
和j
都将达到19,即使条目数少于此值。这可能会导致排序混乱,因为它们将读取无效(未初始化)条目。你应该检查柜台的上限。
下一个是删除
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;
}
}
}
上面的代码无法正确检查第一个和姓氏,因为您要单独检查它们。您只需要一个for
循环if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 )