I am learning c . I got a struct array that has an attribute that is also a struct.
typedef struct Date
{
int day, month, year;
}Date;
typedef struct {
int order_num;
Date order_day; //Sort
string client;
string tech_type;
int serial_key;
char problem[50];
string technician_name;
char tech_fix[500];
int price;
int days_spent;
string status;
string order_type;
string urgency;
int problems_num;
faults problems[10];
}tech_info;
The question is that I need to sort it via date, that is the second attribute on tech_info.
Here is my attempt:
bool compare_date(const tech_info *a, const tech_info *b)
{
if (a->order_day.year < b->order_day.year)
return true;
if (a->order_day.year == b->order_day.year &&
a->order_day.month < b->order_day.month)
return true;
if (a->order_day.year == b->order_day.year &&
a->order_day.month == b->order_day.month &&
a->order_day.day < b->order_day.day)
return true;
// If none of the above cases satisfy, return false
return false;
}
static void sort_date(tech_info* all_orders[]) {
sort(all_orders, all_orders counter, compare_date);
cout << "Sorted by date. " << "\n";
}
In this case counter is the amount of entries the user has submitted.
I submit two entries. For the first one I read the information correctly, but for the second one I don't. I'll attach two screenshots to show. Where is my mistake?
Update: Given that I am accessing bad memory I'll post a bit more of my code, all the parts that have to do with this logic. Here is where I declare my array:
print_menu_initial();
int user_input;
cin >> user_input;
tech_info* orders[100]; //Empty by default
switch (user_input) {
case 1:
do_work_technician_mode(orders);
break;
case 2:
do_work_customer_mode(orders);
break;
}
Then the user does some operations to add orders from here:
static void do_work_customer_mode(tech_info* all_orders[]) {
while (true) {
cin >> user_input;
switch (user_input) {
case 0:
do_work_technician_mode(all_orders);
break;
case 1:
order[counter] = add_order();
all_orders[counter] = &order[counter];
counter ;
break;
case 2:
cout << "How many orders would you like to add? ";
cin >> many_orders;
for (int i = 0; i < many_orders; i ) {
cout << "Information for next order: " << "\n";
order[counter i] = add_order();
all_orders[counter 1] = &order[counter 1];
}
counter = counter many_orders;
break;
case 6:
sort_date(all_orders);
break;
}
The other cases are irrelevant, I believe. This is the sorting part. Counter is an int variable, declared 0 at start. Whenever the customer adds new entries I increase the value of counter with the number of entries he adds.
Funny enough - for my screenshot - variable a gets read correctly, just b is not being read correctly.
CodePudding user response:
It appears that you have come to C from a C background. That is not a bad thing, but I would recommend learning to use as much of the standard library as you can. C 20 in particular has added many features that make it easier to work with collections of objects. This requires a (somewhat) up to date compiler, but is definitely worth it. Here is how I would prefer to approach a problem like this in C .
There are two choices: keeping the collection of orders sorted at all times, or sorting only when needed. The former can be achieved using an ordered container such as std::set, the latter is what you are currently doing using std::sort. However, you could make your life a lot easier by storing the orders in a container like std::vector. Adding a new order is then as simple as
orders.emplace_back(add_order());
Tracking the number of orders in a counter variable is not necessary, since the vector has a size() function.
Further, if there is a natural choice of ordering among values of a type, as is the case with dates, then the recommendation in C is to overload comparison operators. This allows for uniform expression syntax like a != b and x < y when this makes sense for your class. By carefully ordering the members of your Date struct, this can be achieved with almost no code in modern C :
#include <compare>
struct Date {
int year, month, day;
friend auto operator<=>(Date const&, Date const&) = default;
};
static_assert(Date{2000, 1, 1} < Date{2000, 1, 2});
A more sophisticated approach would also prohibit the construction of invalid dates. Classes designed this way were introduced to the std::chrono namespace with C 20; you should now be able to use a class like year_month_day that provides what you need out of the box.
Either way, C 20's range-based std::ranges::sort algorithm then allows you to specify both a comparison and a projection function; the projected values are compared to determine the sorting order. Therefore, once you have a date class with comparison operators, you can also sort the orders like this:
#include <algorithm>
auto order_date = [](auto const& order) -> auto& { return order.order_date; };
std::ranges::sort(orders, std::ranges::less{}, order_date);
CodePudding user response:
The answer to your problem was a type in all_orders[counter i] = &order[counter i];
But since we're here let me clean your code up a bit. I can see you've most likely come from C as most of your syntax is C like. So here are some rules (some may be controvertial but wtvr
typedef struct Date //for structs -> struct NAME. typedef not needed
{
int day, month, year;
}Date; //you're declaring globabl object which isnt that good you want to have as little variables globally
typedef struct { //same here
int order_num; //struct has a lot of variables, i assume all of them are needed
Date order_day; //Sort
string client;
string tech_type;
int serial_key;
char problem[50]; //if this can have many sizes better use string
string technician_name;
char tech_fix[500]; //same here. string. you can always change string to char using function someStringName.c_str() other way round is also possible with minimal effort
int price;
int days_spent;
string status;
string order_type;
string urgency;
int problems_num;
faults problems[10];
}tech_info; //same here
What you'd prefer to see in a cpp program is the following:
struct Date
{
int day, month, year;
};
struct tech_info{
int order_num;
Date order_day; //Sort
string client;
string tech_type;
int serial_key;
string problem;
string technician_name;
string tech_fix;
int price;
int days_spent;
string status;
string order_type;
string urgency;
int problems_num;
faults problems[10];
};
And then your actual objects created in eg main function or some other function.
Next your sorting:
bool compare_date(const tech_info &a, const tech_info &b) //pointers to references
{
if (a.order_day.year < b.order_day.year) //id do it similar but a bit differently
return true;
if (a.order_day.year == b.order_day.year &&
a.order_day.month < b.order_day.month)
return true;
if (a.order_day.year == b.order_day.year &&
a.order_day.month == b.order_day.month &&
a.order_day.day < b.order_day.day)
return true;
// If none of the above cases satisfy, return false
return false;
}
static void sort_date(tech_info* all_orders[]) { //here you have double pointer *name[]. [] also acts as * so you have **all_orders
sort(all_orders, all_orders counter, compare_date); //sort, assuming its sort() from #include <algorithms> uses i think single pointer to beginning of array, end array then type of sorting
cout << "Sorted by date. " << "\n"; //endl instead of "\n"
}
I'd do it like this:
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
struct Date
{
int day, month, year;
Date(int d, int m, int y) : day(d), month(m), year(y) {}
Date() {}
};
struct tech_info{
int order_num;
Date order_day; //Sort
string client;
string tech_type;
int serial_key;
string problem;
string technician_name;
string tech_fix;
int price;
int days_spent;
string status;
string order_type;
string urgency;
int problems_num;
//faults problems[10]; you didnt define what this faults structure was
//making contructor for this class would be perfect
tech_info(int orderNum, int dateDay, int dateMonth, int dateYear, string cl, string techType, int serial, ...)
: order_num(orderNum), Date(dateDay, dateMonth, dateYear), client(cl), tech_type(techType), serial_key(serial), ... {}
tech_info() {}
};
bool compare_date(const tech_info &a, const tech_info &b) //pointers to references
{
if (a.order_day.year == b.order_day.year) //if year is the same
{
if (a.order_day.month == b.order_day.month) //if month is same
{
if (a.order_day.day < b.order_day.day) return true; //if day is different
else return false;
}
else //if month is different
{
if (a.order_day.month < b.order_day.month) return true;
else return false;
}
}
else //if year is different
{
if (a.order_day.year < b.order_day.year) return true;
else return false;
}
}
void sort_date(vector<tech_info> &all_orders) { //i suggest all your tech_info put into vector no static function
sort(all_orders.begin(), all_orders.end(), compare_date);
cout << "Sorted by date." << endl;
}
int main()
{
vector<tech_info> techInfo;
//to add:
techInfo.emplace_back(tech_info(1,2,3,4,"client","sometech", 1234));
//to remove:
techInfo.erase(techInfo.begin() 0); //where 0 is the index of the item you want to delete from vector
sort_date(techInfo);
}
Hope this helps!!!