6
\$\begingroup\$

Here is my objective:

Ask how many categories there are for the class (ex: Labs, Tests, Homework, Quizzes), and then ask what total percentage each make up for the class (ex: Lab are 15%, tests are 60%, so on), and then ask how many items there are under each category (ex: 7 labs, 3 tests, so on), and then ask for the max points of each items in each category, and finally ask what I got on each one.

I could make a pretty simple one for each class, but I wanted to be able to have one program that does it for any class that I can continue to use through my years at university. I'm not advanced by any means, which is why I want to take on this side project. I was hoping some of you could help me out in finishing it up.

Also, I don't know how to make arrays as big as the user wants, so I just put large enough numbers so that I won't ever need more. Probably not good practice, not sure.

int main()
{
    string categories[10];
    int percent[10];
    int totalPoints[50];
    int totalItems[50];
    int a = 0;

    cout << "How many grade categoies do you have: ";
    cin >> a;

    for(int i = 1; i <= a; i++)
    {
        cout << "Enter the category title: ";
        cin >> categories[i];
    }
    for(int i = 1; i <= a; i++)
    {
        cout << "Enter the total percentage for " << categories[i] << ": ";
        cin >> percent[i];
    }
    for(int i = 1; i <= a; i++)
    {
        cout << "How many items are there for " << categories[i] << ": ";
        cin >> totalItems[i];
    }

    return 0;
}
\$\endgroup\$
  • 2
    \$\begingroup\$ Also, I don't know how to make arrays as big as the user wants - for this, you should look into std::vector. It'll allow you to create an array of any size during runtime, which will also do the deallocation itself. \$\endgroup\$ – Jamal Oct 21 '14 at 22:42
  • 1
    \$\begingroup\$ I will skip around in the book and try to find information on std::vector. Thank you for help, Jamal! \$\endgroup\$ – Michael Oct 21 '14 at 22:47
  • 1
    \$\begingroup\$ If it's not in there (likely because schools don't teach this good stuff), then you'll have to check online. It's essentially a dynamically-allocated array wrapped within a class. \$\endgroup\$ – Jamal Oct 21 '14 at 22:50
  • \$\begingroup\$ I may review this later, though there doesn't seem to be much to review since this only takes user input. Consider searching for related questions here for some ideas on how to proceed. \$\endgroup\$ – Jamal Oct 21 '14 at 22:51
  • \$\begingroup\$ You're right, nothing in there about std::vector so far. That's disappointing that they wouldn't teach something that seems so useful. I checked also for other programs, but most are for one class, or GPA calculators. \$\endgroup\$ – Michael Oct 21 '14 at 22:55
7
\$\begingroup\$

What do you plan to do if a class doesn't grade like this? I've had classes where each assignment, test, and quiz had its own weight. Are you just going to make each its own category? Note that you'll have to calculate the percentages prior to entering the data here. Unfortunately, not every professor will return grades in the form of percentages.

If I had this as a task, I think that I'd just use a spreadsheet for it. A spreadsheet already has the relevant computing capacity and is very flexible in the face of arbitrary rules. It also supports saving, which this program doesn't. You'll have to enter the categories and such every time you use the program. With a spreadsheet, you'd save and would just need to update as grades arrive.

All that said, for learning purposes, I'm going to go over the code that you have.

string categories[10];
int percent[10];

This looks risky. The fact that you are using 10 in two places suggests that it has special significance. If so, you should declare a constant to hold the value:

const int MAX_CATEGORIES = 10;

Another problem is that you apparently want categories and percents to be linked, one percent per category. So the C++ way to handle this is to make a class, but in this case, let's make a struct instead:

struct Category {
    public std::string name;
    public float percentOfGrade;

We use a struct because I'm not up to explaining classes in an answer. Anyway, now you can just declare one array rather than two (yes, std::vector would be better, but it would bypass some of the things that I want to criticize).

Category categories[MAX_CATEGORIES];

Notice that categories is plural. I use this to tell me that categories refers to a collection of objects. If I were referring to just one category, I'd use a singular name.

Let's continue looking at your code:

int totalPoints[50];
int totalItems[50];

OK, first we have the same problem as before. It looks like 50 has some significance, so we want to make it a constant, say MAX_ITEMS_PER_CATEGORY. However, looking at your code, totalItems is an array showing how many items in a category. That suggests that it should not have MAX_ITEMS_PER_CATEGORY entries. In fact, we should add it to the category struct:

    public int numberOfItems;
};

Note that I renamed it. I don't like totalItems as a name because total is singular but you're defining an array. I would expect something named total to be the sum of the items or something like that.

I'm going to leave off describing what to do with totalPoints, as you haven't written code using it. Again though, I don't like the name.

cout << "How many grade categoies do you have: ";

Note that categories is misspelled there. Also, you probably should have written std::cout`` rather than plaincout`.

for(int i = 1; i <= a; i++)
{
    cout << "Enter the category title: ";
    cin >> categories[i];
}
for(int i = 1; i <= a; i++)
{
    cout << "Enter the total percentage for " << categories[i] << ": ";
    cin >> percent[i];
}
for(int i = 1; i <= a; i++)
{
    cout << "How many items are there for " << categories[i] << ": ";
    cin >> totalItems[i];
}

First, why do three for loops when one would do? Avoid things where two or more parts of your program have to synchronize. These lead to bugs as synchronicity is hard to maintain.

Second, C++ arrays are zero-indexed. You're starting with 1 but should be starting with 0. The end changes as well. Note the < where there was a <=.

for ( int i = 0; i < numberOfCategories; i++ )  {
    std::cout << "Enter the category title: ";
    std::cin >> categories[i].name;
    std::cout << "Enter the total percentage for " << categories[i].name << ": ";
    std::cin >> categories[i].percent;
    std::cout << "How many items are there for " << categories[i].name << ": ";
    std::cin >> categories[i].numberOfItems;
}

I also changed a to numberOfCategories for readability.

And of course, I started using the struct fields that we declared.

return 0;

You don't need to return from main at the end of execution. The compiler will handle this for you. Only return if you need to do so early.

If you do explicitly return, then do it as follows:

return EXIT_SUCCESS;

or

return EXIT_FAILURE;

This is cross-platform and doesn't rely on the OS understanding 0 the same as you do.

Note: I hinted at this previously, but I'll say it explicitly now. A class would be a better solution in general. I only skipped it because it's too complicated to explain. The struct solution is inferior but closer to how your existing code worked. Similarly, a std::vector would be a better data structure but is less like your current code. I prioritized critiquing your current code over restructuring it.

Another problem that I slid past is that you're doing no validation of your input. If someone enters input that doesn't fit, you should either handle it or abort the program. For example, if numberOfCategories is greater than MAX_CATEGORIES, you will get a runtime error when adding the first extra category.

\$\endgroup\$
5
\$\begingroup\$

When it comes to coding a user interface, big or small, you should try to get it as clean as possible. You've made an obvious typo in the first output, which probably should've stuck out.

In addition, these two output prompts stick out to me:

cout << "How many grade categoies do you have: ";

cout << "How many items are there for " << categories[i] << ": ";

As you are "asking a question" and choose to have a colon at the end, make them "commands", just like you already have with your other prompts. You'll also have to change the wording a bit to do that.

cout << "Enter the number of grade categories: ";

cout << "Enter the total number of items for " << categories[i] << ": ";

As a little extra to add, consider having the % symbol in the percent prompt:

cout << "Enter the total percentage for " << categories[i] << ": %";

This may also remind the user that they're to specifically enter a percentage itself and not the decimal value of that percentage (someone may be tempted to do that).

This is just something to consider, though if it'll only be used for yourself, it may not even matter.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.