Stuck with sorting struct array

Hi i'm new here and a total newbie to C++, i was tasked with creating a program that gives the user to view a list of TV series either by a) listing them all b) by country c) by genre or d) selecting country / genre then giving the user the highest rating series, which is were i got stuck.

Here's how my code for the last part looks.
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
#include <iostream>
#include <strings.h>

struct Series
{
 char name[50];
 char genre[50];
 char country[50];
 float rating;
} s[5] = {
  {"Series 1", "Action", "US", 8.7},
  {"Series 2", "Fantasy", "US", 8.4},
  {"Series 3", "Drama", "US", 8.1},
  {"Series 4", "Fantasy", "US", 8.2},
  {"Series 5", "Fantasy", "US", 8.9}};

int main(void)
{
 char c[50];
 char g[50];

 do
 {
  std::cout << "Country: ";
  std::cin.getline(c, 50);
  std::cout << "Genre: ";
  std::cin.getline(g,50);

  bool found = false;
  
  for (int i = 0; i < 5; i++)
  {
   if (strcasecmp(s[i].country, c) == 0)
   {
    if (strcasecmp(s[i].genre, g) == 0)
    {
     /* 
      Up until here it's fine, it shows the series corresponding to the
      selected countries but i can't exactly figure out how to only show
      the one with highest rating.
     */

     found = true;
     std::cout << "Name: " << s[i].name <<  std::endl;
     std::cout << "Rating: " << s[i].rating << "/10\n" <<  std::endl;
    }
   }
  }

  if(!found)
  {
   std::cout << "No series was found." << std::endl;
  }
 } while (true);

 return 0;
}
Last edited on
Hello Eclypz,

I have to ask if I should be looking at this as a C program or a C++ program?


Also you need better indenting.

Andy
It's a C++ program and sorry for the indenting it's hard to do it here :P
Hello Eclypz,

I thought so.

Then you should "<string>" and not "<strings.h>" which I believe is not a C header file.

And I have never heard of the function "strcasecmp" unless you have written this function your-self.

Including the header file "<algorithm>" you could use "std::sort" to sort the array, but since you are dealing with an array of structs you would have to use the 3rd parameter of the function.

It looks to me like what you need to do first is create a menu of your choices.

After that you could use if statements to choose what to do based on the menu choice. Or you could use a switch.

Either way I would start with displaying everything in the array. You could either do this in "main" or call functions as needed letting "main" control the flow of the program.

I also noticed that your do/while loop is an endless loop with no way out at the moment. This needs to be fixed.

Andy
Hello again.

i found "strcasecmp" while googling around a way to compare two strings without being case sensitive and without having to make it too complex for me writing more, found it's part of <strings.h>.

I do have an options menu for each of the previous options which i've got working fine, it's just this last part of the last option that's giving me trouble trying to print only the series with the highest rating and i will check <algorithm>.

Also thank you i have fixed the endless loop.
Last edited on
strcasecmp() is part of the c strings.h library found with some compilers but is not part of C++.

Some compilers (such as MS VS) support _stricmp() - but again this is none C++ standard.

There's no single standard C++ function to do this.
Last edited on

if you use qsort with the corresponding callback function, you can use tolower(chars) for case independence.
Your structure with some letters uppercased to test.
(had to make a callback for each field!)
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

#include <iostream>
#include <string>
using namespace std;

struct Series
{
 char name[50];
 char genre[50];
 char country[50];
 float rating;
} s[5] = {
  {"SeriEs 1", "Action", "US", 8.7}, // change some cases
  {"Series 2", "Fantasy", "US", 8.4},
  {"SERIES 3", "drama", "US", 8.1},
  {"SeRies 4", "fantasy", "US", 8.2},
  {"Series 5", "Fantasy", "US", 8.9}};
  
 enum direction{up,down}; 
 int direction;
  
  int callbackname(const void * n1, const void * n2) 
{
	if (direction == down)
	{
 if (tolower(*((struct Series*)n1)->name) > tolower(*((struct Series*)n2)->name)) return -1;
  if (tolower(*((struct Series*)n1)->name) < tolower(*((struct Series*)n2)->name)) return 1;
}
 else
 {
 if (tolower(*((struct Series*)n1)->name) > tolower(*((struct Series*)n2)->name)) return 1;
  if (tolower(*((struct Series*)n1)->name) < tolower(*((struct Series*)n2)->name)) return -1;	
}
}

  int callbackgenre(const void * n1, const void * n2) 
{
	if (direction == down)
	{
 if (tolower(*((struct Series*)n1)->genre) > tolower(*((struct Series*)n2)->genre)) return -1;
  if (tolower(*((struct Series*)n1)->genre) < tolower(*((struct Series*)n2)->genre)) return 1;
}
 else
 {
 if (tolower(*((struct Series*)n1)->genre) > tolower(*((struct Series*)n2)->genre)) return 1;
  if (tolower(*((struct Series*)n1)->genre) < tolower(*((struct Series*)n2)->genre)) return -1;	
}
}

  int callbackcountry(const void * n1, const void * n2) 
{
	if (direction == down)
	{
 if (tolower(*((struct Series*)n1)->country) > tolower(*((struct Series*)n2)->country)) return -1;
  if (tolower(*((struct Series*)n1)->country) < tolower(*((struct Series*)n2)->country)) return 1;
}
 else
 {
 if (tolower(*((struct Series*)n1)->country) > tolower(*((struct Series*)n2)->country)) return 1;
  if (tolower(*((struct Series*)n1)->country) < tolower(*((struct Series*)n2)->country)) return -1;	
}
}


  int callbackrating(const void * n1, const void * n2) 
{
	if (direction == down)
	{
 if (((struct Series*)n1)->rating > ((struct Series*)n2)->rating) return -1;
  if (((struct Series*)n1)->rating < ((struct Series*)n2)->rating) return 1;
}
 else
 {
 if (((struct Series*)n1)->rating > ((struct Series*)n2)->rating) return 1;
  if (((struct Series*)n1)->rating < ((struct Series*)n2)->rating) return -1;	
}
}

void print(Series s[],int num,string field)
{
	cout<<field<<endl;
	int i;

	for(i=0;i<num;i++) cout<<s[i].name<<"  "<<s[i].genre<<"  "<<s[i].country<<"  "<<s[i].rating<<endl;
cout<<endl;	
}
  

int main(void)
{
	direction=up;
	
	 qsort (s, sizeof(s)/sizeof(*s), sizeof(*s), callbackname);
	 print(s,5,"Sort by Name");
	 
	 qsort (s, sizeof(s)/sizeof(*s), sizeof(*s), callbackgenre);
	 print(s,5,"Sort by Genre");
	 
	 //qsort (s, sizeof(s)/sizeof(*s), sizeof(*s), callbackcountry); // no need they are all "US"
	// print(s,5,"country");
	 
	 qsort (s, sizeof(s)/sizeof(*s), sizeof(*s), callbackrating);
	 print(s,5,"Sort by Rating");
	 
	 cout <<"  "<<endl;
cout <<"Press return to end . . ."<<endl; 
cin.get();	 
	
}
  



Last edited on
<algorithm> sort has more capabilities than qsort.
https://www.cplusplus.com/reference/algorithm/sort/

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
#include <iostream>             // std::cout
#include <algorithm>            // std::sort
#include <string>
#include <cctype>
using namespace std;

struct Series {
  char name[50];
  char genre[50];
  char country[50];
  float rating;
} s[5] = {
  {"SeriEs 1", "Action", "US", 8.7}, // change some cases
  {"Series 2", "Fantasy", "US", 8.4},
  {"SERIES 3", "drama", "US", 8.1},
  {"SeRies 4", "fantasy", "US", 8.2},
  {"Series 5", "Fantasy", "US", 8.9}
};

enum direction { up, down };
enum field { name, genre, country, rating };

int icmp(const char a[], const char b[])
{
  int result;
  size_t i;
  for (i = 0; a[i] && b[i]; ++i) {
    result = tolower(a[i]) - tolower(b[i]);
    if (result != 0)
      break;
  }
  if (result == 0) {
    if (!a[i])
      result = -1;
    else if (!b[i])
      result = +1;
  }
  return result;
}

struct sorter {
  direction m_direction;
  field m_field;

  sorter(direction a, field b):m_direction(a), m_field(b) {
  };

  bool operator() (const Series & a, const Series & b) {
    int result;
    switch (m_field) {
    case name:
      result = icmp(a.name, b.name);
      break;
    case genre:
      result = icmp(a.genre, b.genre);
      break;
    case country:
      result = icmp(a.country, b.country);
      break;
    case rating:
      result = a.rating < b.rating ? -1 : a.rating > b.rating ? +1 : 0;
      break;
    }
    bool answer = false;
    if (m_direction == up && result < 0)
      answer = true;
    if (m_direction == down && result > 0)
      answer = true;
    return answer;
  }
};

void print(Series s[], int num, string field)
{
  cout << field << endl;
  for (int i = 0; i < num; i++)
    cout << s[i].name << " "
         << s[i].genre << " "
         << s[i].country << " "
         << s[i].rating << endl;
}

int main(void)
{
  std::sort(s, s+5, sorter(up,name));
  print(s, 5, "Sort by Name");

  std::sort(s, s+5, sorter(down,genre));
  print(s, 5, "Sort by genre");
}


It's not a huge step to using std::vector and std::string to replace the arrays.

Topic archived. No new replies allowed.