Corning Community College
CSCS2330 Discrete Structures
Have you converted that argv[] value to an integer?
Remember in their natural state the argv[] they are arrays of char (strings).
Even if it is a single “digit”, like 2, as a string it will actually be a 2 element char array, the ASCII character '2', followed by a NULL terminator.
And the ASCII character '2' has a numeric value of 50.
There is a handy C library function (even mentioned in the project page) that can do a quick conversion for you (or you could implement the code yourself).
Simple, follow these easy steps to success:
Remember that we have TWO potential terminating values in these programs:
One or both of them may be set. Your program needs to be able to deal with all combinations of this (including the error states, by displaying the appropriate message).
Some further examples of program invocation with resulting output may further help clarify:
If you ran the program as follows: ./primereg 10 1
It would (lacking a lower bound argument) start at 2, and (also lacking un upper bound argument) display 10 consecutive prime values (2 3 5 7 11 13 17 19 23 29).
Giving (just) a lower bound still involves quantity: ./primereg 5 1 7
Here we would start at 7, and display the first 5 primes computed (7 11 13 17 19)
With an upper bound involved, AND a quantity, it ends up being whoever is satisfied first.
For example: ./primereg 5 1 7 13
Would only display “7 11 13”, because while we told it to produce 5 values, we also told it that its upper bound was 13.
But we could also have done: ./primereg 5 1 7 100
Here the upper bound would be 100, but the program would only display “7 11 13 17 19” because the quantity condition would have been satisfied first.
There could also be no explicit quantity threshold provided. For those who did the prime number projects for me back in the spring, this is actually the mode of operation you implemented, but you see here it is but one of many operating conditions.
An example of this functionality would be invoked by: ./primereg 0 1 2 19
Which would calculate all the primes between 2 and 19 (inclusive of both), so: “2 3 5 7 11 13 17 19”
Again, there are technically TWO terminating conditions… quantity (if > 0) and/or upper bound (if given).
If both are given, then it is whichever is satisfied first.
I found that adding these specific requirements adds a nice bit of spice to the construction of the program. It actually doesn’t make it that much more complex, but it really causes one to think about how to best address monitoring and dealing with those conditions effectively.
Think about all the potential conditions you need to satisfy: The presence of quantity (or not), the presence of an upper bound (or not), the presence of both (and whoever gets there first wins). Also to identify the possible error conditions (what if neither is provided?)
I ended up making use of some compound conditions in places (ie using && and ||).
Also consider the way you are doing things. You are doing things that way because…? Might there be a better way? What if you flipped things? Or reversed the way you were doing things?
Sometimes the more elegant solution comes from doing things a little differently than you have up to this point. And remember: if before this point was C/C++ Programming, that was an introductory and pedagogical experience. Here in Discrete we're interested more in efficiency and effective uses of constructs.
Because we know we’re not. Evolution perfects survival skills. There are perfect hunters. There is perfect defense. Why is there no such thing as perfect hiding? How would you know?
Logically, if evolution were to perfect a creature whose primary skill were to hide from view, how could you know it existed? It could be with us every second and we would never know. How would you detect it? Even sense it? Except in those moments when for no clear reason, you choose to speak aloud. What would such a creature want? What would it do?
If your program ends up producing correct outputs, implements the correct algorithm, and follows project specifications, I wouldn’t say that way is ‘incorrect’; I would call it a “working solution”.
And that is a distinction I want everyone to become increasingly aware of; there are many “adequate” solutions, functioning properly and producing correct results. But there is also the set of solutions that do the same and appear elegant, clean, and/or neat.
Sometimes code messiness cannot be avoided. But we should strive to avoid it if possible. If we suspect something isn't as optimal as it could be, by all means explore other approaches (so long as they remain within project specifications and constraints).
I consider programming an art form, which means the actual appearance of the code itself can incorporate an aesthetic of beauty. And procedural syntaxes (like that of C, C++, Java, PHP) are actually meant to embody that aesthetic appearance to their solutions.
The gross, ugly hacks you might be able to pull off, while potentially also yielding an acceptable or adequate solution, may be short changing you: implementing aesthetically pleasing solutions may introduce you to other means of solving the problem and thinking about it, which further enriches you overall.
For those keen on the “gross hacks” (and I admit, sometimes they are necessary), use them in your first draft to get a working prototype, then massage them out in later iterations of the code, so that your submitted result (the code) looks like poetry.
I feel so sorry for you…
… If you think computing is about memorizing product model numbers, installing LED light strips in your case, checking the version of the driver of your gaming mouse, and chatting on facebook, you clearly do not understand what “programming and computers” is all about.
Ehhh… maybe viable as a prototyping step, but I’d really like to see the end (submitted) result address both in the same looping body (it can most certainly be done).
You may also find that segregating them could possibly create issues potentially leading to more special cases, and before you know it, your code size balloons and contains a lot of slightly modified redundant copies of the central logic (a debugging nightmare should a problem crop up).
The same way you satisfy any problem that needs solving: with an effective solution.
Clearly you can come up with a terminating condition for JUST quantity, and I assume JUST range.
You can probably also come up with a solution to satisfy BOTH quantity AND range.
But then there might be the trickier TOGETHER but whichever is satisfied independent of the other. And for that I will gift you with a capitalized hint: quantity OR range.
Think about it, think about how you could express all these conditions within the same block of code. It is entirely possible.
It doesn't even all have to be in the exact same line. But definitely within the same block of code.
It is things like this which will open up new possibilities of crafting solutions, which is in part what Discrete is all about. If left to our own devices, we will want to flock to the familiar (even if limiting) approach, but the true power of effective programming comes from being able to craft more ideal solutions, even when dealing with scenarios you haven't encountered before.
Sure, there may be “best practices” or “conventional approaches” which you can reference to see if they fit the bill, but if they don't, could they be modified to better suit our needs? Or is an entirely fresh solution warranted?