Pertanyaan Sorting array dari typedef struct dalam C


Masalah: Mencoba mengurutkan array yang berasal dari struct typedef yang saya buat (phonebook).

Tujuan: Mencoba membuat buku telepon yang memungkinkan pengguna untuk menambah, menghapus, menyortir, dan mencetak buku telepon.

Di mana saya berada: Saya punya segalanya bekerja kecuali semacam itu. Saya telah menyusun fungsi semacam dari membaca berbagai forum web / contoh, tetapi tidak dapat membuatnya berfungsi.

Masalah yang saya alami: Setelah menambahkan entri (yang berfungsi dengan baik), jika Anda mencoba menyortir entri, fungsi tersebut mengesampingkan nilai entri tersebut dan ketika Anda mencetak buku telepon, ini menunjukkan semua entri sebagai kosong. Ini harus mengurutkan mereka menurut abjad nama belakang.

Berikut adalah algoritma sortir yang saya miliki:

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;

            }
        }
    }
}

Ada ide?


Kode lengkap di sini:

#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;
            }
        }
    }
}

11
2017-10-27 05:09


asal


Jawaban:


Anda dapat menggunakan fungsi penyortiran yang telah diimplementasikan qsort fungsi tersedia di 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);
} 

Fungsi itu biasanya Quicksort, tapi itu tergantung pada implementasi perpustakaan C untuk memutuskan.

Memperbarui:

Daftar yang kosong adalah karena pemilahan dibalik dan selalu menyortir semua 19 item dari buku telepon, membandingkan yang kosong dengan yang asli. Jika Anda memiliki kurang dari 19 entri di buku telepon, data yang sebenarnya akan hadir di akhir dari susunan buku telepon.

Fungsi Urutkan asli Anda selalu berfungsi hampir BAIK. Ubah saja kondisi akhir pada keduanya untuk.

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;
            }
        }
    }
}

Saya juga memperbarui saya Sort atas.


6
2017-10-27 05:17



Pertama-tama, Anda memiliki masalah buffer overflow di sini:

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

Bahwa scanf akan menulis dua byte ketika Anda memasukkan satu karakter (karakter ditambah terminator null). Ini merusak nama pertama dari entri buku telepon pertama di lingkungan saya, tetapi karena perilaku tidak terdefinisi, itu bisa dilakukan apa pun!

Anda dapat menggunakan ini dengan menggunakan:

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

Itu tidak akan menghentikan buffer overflow jika Anda memasukkan teks yang cukup tetapi akan jika Anda membatasi diri Anda untuk perintah karakter tunggal. Jika Anda menginginkan fungsi input pengguna yang benar-benar kuat, lihat sini.


Sekarang untuk masalah spesifik Anda. Sepertinya Anda memiliki sedikit gelembung yang terjadi di sana, tetapi logika Anda sedikit tidak aktif. Dengan asumsi Anda tidak ingin menggunakannya qsort (yang akan menjadi cara yang lebih baik untuk kode sebenarnya), Anda hanya perlu memperbaiki beberapa hal.

Lingkaran luar Anda baik-baik saja, seperti juga lingkaran dalam Anda, tetapi badan pengulangan bagian dalam harus membandingkan elemen j dan j+1tidak j dan i. Itu karena ia bekerja dengan menukar berdekatan elemen jika rusak.

Selain itu, jenis gelembung yang difokuskan ke depan akan menempatkan paling tinggi elemen di akhir dari daftar pada laluan pertama, jadi Anda tidak dapat memulai j di i+1 pada lintasan kedua, hanya karena pertama elemen mungkin belum benar.

Kode psuedo berikut adalah jenis gelembung klasik Anda:

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

Baca itu, pahami cara kerjanya, lalu implementasikan sendiri. Jika Anda mengalami masalah dengan itu, saya telah menyertakan versi kerja di bawah ini:

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;
            }
        }
    }
}

1
2017-10-27 05:18



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;

        }

    }
}

Tiga masalah dengan kode Anda. Pertama adalah logika dari algoritma Anda. Bubble sort berfungsi dengan memperbaiki urutan dua elemen yang berdekatan. Dalam kode Anda, setelah iterasi pertama dari batin Anda for loop, itu tidak akan membandingkan dua elemen yang berdekatan.

Masalah kedua, lagi-lagi dalam menyortir algoritma, penghitung Anda i dan j keduanya akan 19, bahkan ketika ada entri kurang dari itu. Ini mungkin mengacaukan penyortiran karena mereka akan membaca entri tidak valid (tidak diinisialisasi). Anda harus memeriksa batas atas untuk penghitung.

Yang berikutnya dalam penghapusan

    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;
            }

        }

    }

Kode di atas tidak akan memeriksa dengan benar apakah yang pertama dan nama belakang karena Anda sedang memeriksanya secara terpisah. Anda hanya butuh satu for lingkaran dengan if( strcmp(deleteSurname, phonebook[x].Surname) == 0 && strcmp(deleteName, phonebook[x].Name) == 0 )


0
2017-10-27 05:32