Sort by Last Name

I am trying to sort a dynamically allocated array of structures alphabetically by last name. In order to do that I have to get the last name from the fullName character array so that I can compare them. Does anyone know an easier way I can accomplish this? I am not getting "errors" per se, but I am getting a lot of warnings and it's not letting me compile the program.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void SortRecords(CustomerAccountRecords* ptr, int SIZE)
{
	char lastName1[50], lastName2[50];
	for (int start = 0; start < SIZE; start++) {
		int minIndex = start;
		for (int i = start + 1; i < SIZE; i++) {
			lastName1[50] = GetLastName(ptr, i);
			lastName2[50] = GetLastName(ptr, minIndex);
			if (strcmp(lastName1, lastName2) < 0)
				minIndex = i;
		}
		swap(ptr[minIndex], ptr[start]);
	}
}

char GetLastName(CustomerAccountRecords* ptr, int recordNum)
{
	char lastName[50];

	for (int i = 0; i < strlen(ptr[recordNum].fullName); i++) {
		if (isspace(ptr[recordNum].fullName[i])) {
			for (int j = i + 1; j < strlen(ptr[recordNum].fullName); j++) {
				lastName[j - (i + 1)] = ptr[recordNum].fullName[j];
			}
		}

	}
}
I've changed it now to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void SortRecords(CustomerAccountRecords* ptr, int SIZE)
{
	char lastName1[50], lastName2[50];
	for (int start = 0; start < SIZE; start++) {
		int minIndex = start;
		for (int i = start + 1; i < SIZE; i++) {
			GetLastName(ptr, i, lastName1);
			GetLastName(ptr, minIndex, lastName2);
			if (strcmp(lastName1, lastName2) < 0)
				minIndex = i;
		}
		swap(ptr[minIndex], ptr[start]);
	}
}

char GetLastName(CustomerAccountRecords* ptr, int recordNum, char *lastName)
{
	for (int i = 0; i < strlen(ptr[recordNum].fullName); i++) {
		if (isspace(ptr[recordNum].fullName[i])) {
			for (int j = i + 1; j < strlen(ptr[recordNum].fullName); j++) {
				lastName[j - (i + 1)] = ptr[recordNum].fullName[j];
			}
		}

	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <string>
#include <cctype>
#include <cstring>
#include <algorithm>

struct customer
{
    // consider using std::string to hold the full name
    // string: https://cal-linux.com/tutorials/strings.html
    static const int NAME_SZ = 127 ;
    char full_name[NAME_SZ+1] {} ;
    // other stuff
};

// string: https://cal-linux.com/tutorials/strings.html
std::string first_name( const customer& cust )
{
    std::string fname ;

    const char* p = cust.full_name ;
    while( *p != 0 && std::isspace(*p) ) ++p ; // skip leading spaces

    for( ; *p != 0 && !std::isspace(*p) ; ++p ) fname += *p ; // add characters of first name

    return fname ;
}

std::string last_name( const customer& cust )
{
    std::string lname ;

    // get to the last character in the c string
    const char* p = cust.full_name + std::strlen( cust.full_name ) - 1 ;

    while( *p > cust.full_name && std::isspace(*p) ) --p ; // skip trailing spaces

    for( ; p >= cust.full_name && !std::isspace(*p) ; --p ) lname += *p ; // add characters of last name

    // the characters have been added from right to left, so reverse it
    std::reverse( lname.begin(), lname.end() ) ;

    return lname ;
}

// considr using std::vector if the items are to be dynamically allocated
// vector: https://cal-linux.com/tutorials/vectors.html
// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rsl-arrays

// get the index of the customer with the smallest last name
int min_index( const customer* cust, int sz ) // note: case sensitive
{
    int min_pos = 0 ;

    for( int i = 1 ; i < sz ; ++i )
        if( last_name( cust[i] ) < last_name( cust[min_pos] ) ) min_pos = i ;

    return min_pos ;
}

void sort_on_last_name( customer* cust, int sz ) // note: case sensitive
{
    if( sz > 1 ) // if there is more than one item left
    {
        // get the position of the item that should appear right in front
        const int min_pos = min_index( cust, sz ) ;

        // bring that item to the front
        using std::swap ;
        if( min_pos != 0 ) swap( cust[0], cust[min_pos] ) ;

        // sort the remaining sz-1 items
        sort_on_last_name( cust+1, sz-1 ) ;
    }
}

void std_sort_on_first_name( customer* cust, int sz ) // note: case sensitive
{
    // lambda expression: http://www.stroustrup.com/C++11FAQ.html#lambda
    // auto: http://www.stroustrup.com/C++11FAQ.html#auto
    const auto cmp_first_name = [] ( const customer& a, const customer& b )
    { return first_name(a) < first_name(b) ; };

    // https://en.cppreference.com/w/cpp/algorithm/sort
    std::sort( cust, cust+sz, cmp_first_name ) ;
}

int main() // minimal test driver
{
    customer cust[] =
    {
        { " Bjarne Stroustrup" },
        { "Andrew Richard Koenig " },
        { "  Alexander Stepanov  " },
        { "David Abrahams" },
        { "Dennis Ritchie" },
        { " Alan Mathison Turing " },
        { "Adele Goldberg" },
    };

    const int N = sizeof(cust) / sizeof(cust[0]) ;

    sort_on_last_name( cust, N ) ;

    // range based loop
    // http://www.stroustrup.com/C++11FAQ.html#for
    for( const customer& c : cust ) std::cout << last_name(c) << ", "  << first_name(c) << '\n' ;

    std::cout << "\n-----------\n\n" ;

    std_sort_on_first_name( cust, N ) ;
    for( const customer& c : cust ) std::cout << first_name(c) << ' ' << last_name(c) << '\n' ;
}

http://coliru.stacked-crooked.com/a/93ed5f2919e82e8d
Last edited on
Hello lkdodd,

I do not know if using a character array is required or if you could use a "std::string" in it place. Using "std::string" can solve a lot of your problems.

I put this together to test it out, nut you may find it useful:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <limits>
#include <string>

int main()
{
	size_t pos{}; // <--- Can be done with out this variable
	std::string fullName/*{ "De Laurentiis, Giada" }*/; // <--- Remove comments for testing.
	std::string firstName, lastName;

	std::cout << "\n Enter full name (Last, First): ";
	std::getline(std::cin, fullName); // <--- Comment out for testing.

	pos = fullName.find(',', 0);

	lastName = fullName.substr(0, pos);
	firstName = fullName.substr(pos + 2); // <--- Starting position is past the "," and space.

	 // <--- Can also be written as:
	//lastName = fullName.substr(0, fullName.find(',', 0)); // <--- Negate the need for "pos".
	//firstName = fullName.substr(fullName.find(',', 0) + 2);  // <--- Moves past the comma and space.

	std::cout << "\n\n  Last Name: " << lastName << std::endl;
	std::cout << " First Name: " << firstName << std::endl;


	// The next line may not be needed. If you have to press enter to see the prompt it is not needed.
	//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n Press Enter to continue :";
	std::cin.get();

	return 0;
}

I did all of this in "main", but you could just as easily put this in a function. There are two ways to use ".find". Either way works.

Should you need to use character arrays. Look to what JLBorges did.

Hope that helps,

Andy
Topic archived. No new replies allowed.