Home > Software design >  c Problem sorting struct array, probably issue with pointers
c Problem sorting struct array, probably issue with pointers

Time:12-11

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?enter image description here

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!!!

  • Related