Sign in to follow this  
bluefox25

my first real program!!

Recommended Posts

This is my first real program I have written on my own that was not part of a project or assignment. It calculates my final grade for my class. I compileed it and it works!! Can you guys make any suggestions for improvements? Shortcuts? etc....
#include <iostream>
/**
* Sets test scores
*@param exams[] contains the number of exams
*@pre Initialized by the calling program 
*@post Prompts user for score per test
*@returns a filled array with test scores
*/
double totaltest(double exams[]);
/**
* Sets quiz scores
*@param quizzes[] contains the number of quizzes
*@pre  Initialized by the calling program 
*@post Prompts user for score per quiz
*@returns a filled array with quiz scores
*/
double totalquiz(double quizzes[]);
/**
* Sets homework assignments  scores
*@param homework[] contains the number of homework assignments
*@pre Initialized by the calling program 
*@post Prompts user for score per homework
*@returns a filled array with homework assignment scores
*/
double totalhwork(double homework[]);
/**
* Sets Programming Projects  scores
*@param projs[] contains the number of programming projects
*@pre Initialized by the calling program 
*@post Prompts user for score per programming project
*@returns a filled array with programming project  scores
*/
double totalprojects(double projs[]);
/**
* Calculates the Final Grade
*@param int a contains the combined test scores
*@param int b contains the combined quiz scores
*@param int c contains the combined homework assignment scores
*@param int d contains the combined projects scores
*@pre Initialized by the calling program 
*@post Adds up all totals
*@returns The final grade for the course
*/
double calculate(double& a, double& b, double& c, double& d);//calculates grade
int main(){
    double test[4];
    double quiz[9];
    double assignments[12];
    double programmmingProjects[3];
    double tscore= totaltest(test);
    double qscore= totalquiz(quiz);
    double hscore= totalhwork(assignments);
    double pscore= totalprojects(programmmingProjects);
    double myGrade = calculate(tscore,qscore,hscore,pscore);
    
    std::cout << "My final grade for the course is: " << myGrade 
              << std::endl; 
   
    
    system("pause");
    return 0;
}
double totaltest(double exams[]){
    
    for(int i=1;i< 4;i++){
        std::cout << "Enter your score for Test " << i << ": "; 
        std::cin >> exams[i];
    }
    return exams[1] + exams[2] + exams[3];
}


double totalquiz(double quizzes[]){
        for(int i=1;i<9;i++){
        std::cout << "Enter your score for Quiz " << i << ": "; 
        std::cin >> quizzes[i];
    }
    return quizzes[1] + quizzes[2]+quizzes[3]+quizzes[4]+quizzes[5]+quizzes[6]
           +quizzes[7]+quizzes[8];
}

double totalhwork(double homework[]){
    for(int i=1;i<12;i++){
        std::cout << "Enter your score for Assignment " << i << ": "; 
        std::cin >> homework[i];
    }
    return homework[1] + homework[2]+ homework[3]+homework[4]+homework[5]
           +homework[6]+homework[7]+homework[8]+homework[9]+homework[10]
           +homework[11];
}

double totalprojects(double projs[]){
    for(int i=1;i<3;i++){
        std::cout << "Enter your score for Programming Project " << i << ": "; 
        std::cin >> projs[i];
    }
    return projs[1] + projs[2];
}
double calculate(double& a, double& b, double& c, double& d){
       using namespace std;
       cout.setf(ios::fixed);
       cout.setf(ios::showpoint);
       cout.precision(2); 
       
       return ((a/300)*.60) + ((b/80) *.10) + ((c/110) *.10) + ((d/200) *.20);
}



Share this post


Link to post
Share on other sites
You have a nasty bug in your code. Array indices start from 0, not 1.
your exams array is accessed at indices 1, 2 and 3, but since it's an array of size 3, it only has indices 0, 1 and 2. Only reason the program works for you is... luck. Apparently there isn't anything vitally important following exams[2], so while you write outside your array, the program doesn't crash.

You might want to use the standard library's vector instead of arrays. Among other things, they give you proper bounds checking, so you can easily spot these things.

Anyway, grats on your first program [grin]

Share this post


Link to post
Share on other sites
Is it a bug? I thought you could start at any index in array as long as you don't go over the size of the array. I used test[4] as the argument passed into the functions. If I started at inex 0 then it would read
"Enter score for Test 0:" or whatever the text is, and I wanted it to say Test 1,test 2, etc with the for loop. My book(Problem Solving with C++) sets the i to 1 on many occasions.

How can I make it crash? What should I input, Id like to see the error occure for learning purposes

Share this post


Link to post
Share on other sites
The error *is* occurring. Just you can't easily see since it's writing to essentially a random piece of memory. If you were lucky, it would try to write to some place that you don't have permission to write (eg: OS stuff) and would give you an Access Violation error (or similar depending on platform, etc.)

You have to start at index of 0. There's no ifs-ands-or-buts to that. Well, of course, unless you don't want to read the first thing in the array.

Share this post


Link to post
Share on other sites
Quote:
Original post by bluefox25
"Enter score for Test 0:" or whatever the text is, and I wanted it to say Test 1,test 2, etc with the for loop. My book(Problem Solving with C++) sets the i to 1 on many occasions.

what about

for(int i=1;i< 4;i++){
std::cout << "Enter your score for Test " << i+1 << ": ";
std::cin >> exams[i];

:)?

Share this post


Link to post
Share on other sites
Quote:
The error *is* occurring. Just you can't easily see since it's writing to essentially a random piece of memory. If you were lucky, it would try to write to some place that you don't have permission to write (eg: OS stuff) and would give you an Access Violation error (or similar depending on platform, etc.)


Well he should be be using 0 as a matter of practice but no "error" is occuring as he is only writing to or reading from item 11 at the most. It would however make sense to use item 0 as that is about 8 bytes of memory wasted in each array (though thats hardly the end of the world).

Next time try to create the array of size 11 and then use


for(int i=0;i<11;i++){
std::cout << "Enter your score for Test " << "note the plus 1 so it displays correctly"i+1 << ": ";
std::cin >> exams[i];
}



But yeah other than that you have no memory overwrite so dont panic. Just consider situations where you may waste memory.

Good Luck and have fun

Share this post


Link to post
Share on other sites
Quote:
Original post by Ezbez
The error *is* occurring. Just you can't easily see since it's writing to essentially a random piece of memory. If you were lucky, it would try to write to some place that you don't have permission to write (eg: OS stuff) and would give you an Access Violation error (or similar depending on platform, etc.)

You have to start at index of 0. There's no ifs-ands-or-buts to that. Well, of course, unless you don't want to read the first thing in the array.


You don't have to start at 0. E.g.: If you call malloc(), it does *not* necessarily return the address of the just allocated memory, instead it allocates the requested memory + size of the mem-descriptor, so free() can use a negative index on your new memory to access the memory descriptor.

I *don't* recommend arbitrary indices, that all messes up (at work we use delphi, and it is a mess, really), nevertheless you can use them (pseudo code):

void* myMalloc( size, startIndex )
{
void *ret = malloc( size );
return ret-startIndex;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid

void* myMalloc( size, startIndex )
{
void *ret = malloc( size );
return ret-startIndex;
}


Undefined behaviour. The mere action of creating a pointer outside the bounds of a memory segment will allow your program to act in an undefined fashion. The code above is perfectly allowed to format your hard drive or brutally reboot your computer. The bounds of the segment created by char* p = malloc(s) are between p and p + s inclusive (the C standard explicitly allows the programmer to manipulate past-the-end pointers).

Aside from that, you're doing pointer arithmetic with a void*, which is also a quite funny (if impossible) thing to do.

In general if someone needs special indices, he should either use an index-generation function, or write a subscript operator for a custom wrapper class.

Share this post


Link to post
Share on other sites
hi!
i think what can make your program good is to add question on how many test or work you have done so as to be able to calculate your true grade (of course school test are not just four you know).
also some error checking would e nice, like what if you entered a negative grade for example..

hope you find my advice useful ;)

Share this post


Link to post
Share on other sites

Here is one way you can make the function a bit more flexible:

double totaltest(double exams[], int nExams)
{
double total = 0.0;
for(int i=0; i<nExams; i++)
{
std::cout << "Enter your score for Test " << i+1 << ": ";
std::cin >> exams[i];
total += exams[i];
}
return total;
}


This way your function can deal with any number of exam results =)
You can do similar to the other functions as well, just make sure that the exams array you send to the function is big enough. (eg. at least nExams elements)

Grats with your first program by the way =)


Share this post


Link to post
Share on other sites
Thanks guys
I hadn't thought about using i+1, duh!!
I thought about how to make the program reusable for other courses. All I would need to do is change the weight of each task right? 2 exams might be 80% for example

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by greenhybrid

void* myMalloc( size, startIndex )
{
void *ret = malloc( size );
return ret-startIndex;
}


Undefined behaviour. The mere action of creating a pointer outside the bounds of a memory segment will allow your program to act in an undefined fashion. The code above is perfectly allowed to format your hard drive or brutally reboot your computer. The bounds of the segment created by char* p = malloc(s) are between p and p + s inclusive (the C standard explicitly allows the programmer to manipulate past-the-end pointers).

Aside from that, you're doing pointer arithmetic with a void*, which is also a quite funny (if impossible) thing to do.

In general if someone needs special indices, he should either use an index-generation function, or write a subscript operator for a custom wrapper class.


Hence I wrote "pseudo code", to show how it basically works. The following fragment, btw, does not partition my hd, neither does it double the virtual memory or so :D


# vi arbitstartindex.cc
# g++ arbitstartindex.cc -o test_start0
# vi arbitstartindex.cc
# g++ arbitstartindex.cc -o test_start1
# vi arbitstartindex.cc
# g++ arbitstartindex.cc -o test_start_n666
# ./test_start0 && ./test_start1 && ./test_start_n666
0123456789
0123456789
0123456789
# smach@debian-smach:~/Desktop$ cat arbitstartindex.cc
// GNU version 2
// (C)2007 Sebastian Mach

#include <stdlib.h>
#include <stdio.h>


#define STARTINDEX -666


template<class T> T *myMalloc( unsigned int size )
{
return (T*)malloc( size ) - STARTINDEX;
}

/*void myFree( void *p, unsigned int sizeSingle )
{
free( (char*)p + sizeSingle*STARTINDEX );
}*/

void dumpint( int *p, int length )
{
unsigned int u;
for( u=STARTINDEX; u<STARTINDEX+length; u++ ){
printf( "%u", p[u] );
}
printf( "\n" );
}

int main( int argc, char *args[] )
{
int size = 10;
int *array = myMalloc<int>( size*sizeof(int) );

int u;

// excusez moi for triple implementation, for educational purposes ;)
#if STARTINDEX==0
// conventional
for( u=0; u<size; u++ ){
array[u] = u;
}
#elif STARTINDEX==1
// here for the ones who prefer 1 as start index
for( u=1; u<=size; u++ ){
array[u] = u-1;
}
#else
// the arbitrary one
for( u=STARTINDEX; u<STARTINDEX+size; u++ ){
array[u] = (u-STARTINDEX);
}
#endif

dumpint( array, size );

return 0;
}
#


For sure you have to keep track which start index you actually use, but this is also the case with other languages that allow arbitrary indices (that's why I mentioned kinda delphi-mess).

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid
The following fragment, btw, does not partition my hd, neither does it double the virtual memory or so :D


The worst thing about undefined behaviour is that it works. It usually stops working at the wrong time, though, so it is a thing best not relied upon. I'm not saying that you shouldn't use it in your own code (which is, after all, yours). But since you posted it on a public forum without mentioning that it was an unreliable coincidence frowned upon by the C standard, I decided to mention it myself.

Share this post


Link to post
Share on other sites
My code has as much "undefined behaviour" as any other code which uses arrays/pointers. As long as you stay in the bounds (where my [yes,quick-and-dirty] code explicitly allows arbitrary bounds).

Btw, it's funny like you laugh at others when using void-ptr-arithmetrics inside pseudo-code and don't recognize that not even all variables have been given a type.

btw: gnu malloc source code

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid
My code has as much "undefined behaviour" as any other code which uses arrays/pointers. As long as you stay in the bounds (where my [yes,quick-and-dirty] code explicitly allows arbitrary bounds).

Btw, it's funny like you laugh at others when using void-ptr-arithmetrics inside pseudo-code and don't recognize that not even all variables have been given a type.

btw: gnu malloc source code

The implementation of the library is not a concern of the standard, only that it performs such that the observed behavior is as expected. Your code on the other hand is required to behave as the standard dictates, if you want it to be at all stable and usable.

The majority of code is very well defined around pointers, because NOT being well defined there tends to result in bugs, I know, foreign concept to you probably. Bugs are these things that go wrong with a program, stuff that isn't supposed to happen. Maybe you've seen an application crash a few times, that's caused by this thing called a "bug." Something which the above code of yours promotes by using undefined behavior.

Share this post


Link to post
Share on other sites
Quote:
Original post by Washu
Quote:
Original post by greenhybrid
My code has as much "undefined behaviour" as any other code which uses arrays/pointers. As long as you stay in the bounds (where my [yes,quick-and-dirty] code explicitly allows arbitrary bounds).

Btw, it's funny like you laugh at others when using void-ptr-arithmetrics inside pseudo-code and don't recognize that not even all variables have been given a type.

btw: gnu malloc source code

The implementation of the library is not a concern of the standard, only that it performs such that the observed behavior is as expected. Your code on the other hand is required to behave as the standard dictates, if you want it to be at all stable and usable.

The majority of code is very well defined around pointers, because NOT being well defined there tends to result in bugs, I know, foreign concept to you probably. Bugs are these things that go wrong with a program, stuff that isn't supposed to happen. Maybe you've seen an application crash a few times, that's caused by this thing called a "bug." Something which the above code of yours promotes by using undefined behavior.


Who are you to claim I don't know what a bug/undefined behaviour is? Sorry, but this an affront to me.

Undefined behaviour is behaviour not defined outside the [defined/allowed] [input/behaviour], as such, my code is very well defined to work with it as it is intended to.

The gnu-implementation-example was intended to simply show that from time to time you don't get the physical address of just allocated memory, but more a kind of virtual address. But I agree it's not a good example for arbitrary indices.

edit: typo

[Edited by - greenhybrid on May 26, 2007 2:30:41 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid
Undefined behaviour is behaviour not defined outside the [defined/allowed] [input/behaviour].


In the C language, (T*)malloc( size ) - STARTINDEX; is undefined behaviour as soon as STARTINDEX > 0, because that would create an address that is before the standard-guaranteed segment allocated by malloc, and merely creating an address outside a segment is undefined behaviour (you don't even need to dereference it: as soon as you create it, you can kiss the Standard goodbye).

This is why your code causes undefined behaviour while normal, standard-abiding pointer manipulation code doesn't (because standard-abiding pointer manipulation code stays inside memory segments, as the standard requires), and this is what we've been telling you since the start.

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid
Who are you to claim I don't know what a bug/undefined behaviour is? Sorry, but this an affront to me.

Well, I see the code you've posted, and that immediately tells me that you don't know what undefined behavior is (in the C or C++ languages), nor what a bug is apparently, because your code promotes bugs.
Quote:
Undefined behaviour is behaviour not defined outside the [defined/allowed] [input/behaviour], as such, my code is very well defined to work with it as it is intended to.

Undefined behavior is any behavior defined by the standard to be undefined (either explicitly or implicitly, and some cases it's undefined simply by omission). Such as pointing a pointer outside of the bounds allocated for it by the allocating function (malloc/new).

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
In the C language, (T*)malloc( size ) - STARTINDEX; is undefined behaviour as soon as STARTINDEX > 0, because that would create an address that is before the standard-guaranteed segment allocated by malloc, and merely creating an address outside a segment is undefined behaviour (you don't even need to dereference it: as soon as you create it, you can kiss the Standard goodbye).


In the C-language, templates are not defined.
In your point of view of undefined behaviour, as soon as STARTINDEX != (rather than >, like you mentioned), is undefined behaviour. If you define your code to do this and to do that, and you can guarantee it does that as long as you do what you intend to do, the behaviour is very well defined. True, one constraint of my code is dereferencation. There are many constraints in the worl of coding, not?

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
In the C language, (T*)malloc( size ) - STARTINDEX; is undefined behaviour as soon as STARTINDEX > 0, because that would create an address that is before the standard-guaranteed segment allocated by malloc, and merely creating an address outside a segment is undefined behaviour (you don't even need to dereference it: as soon as you create it, you can kiss the Standard goodbye).


In the C-language, templates are not defined.
In your point of view of undefined behaviour, as soon as STARTINDEX != (rather than >, like you mentioned), is undefined behaviour. If you define your code to do this and to do that, and you can guarantee it does that as long as you do what you intend to do, the behaviour is very well defined. True, one constraint of my code is dereferencation. There are many constraints in the worl of coding, not?

Share this post


Link to post
Share on other sites
Quote:
In the C-language, templates are not defined.


My code doesn't use templates. Besides:
  • This undefined behaviour is also described in the C++ standard, so everything I said applies in C++ as well, and templates do exist in C++.
  • Aside from the template part, your code is pure C. In fact, it's not even Standard C++ (it uses non-standard header stdio.h, for instance).


Quote:
In your point of view of undefined behaviour,


This is not so much my point of view as the very description of undefined behaviour. The one put forward by the standards of C and C++.

Quote:
as soon as STARTINDEX != (rather than >, like you mentioned), is undefined behaviour.


No, it's perfectly posible to have 0 <= STARTINDEX, as long as STARTINDEX <= size, without triggering this particular brand of undefined behaviour in the aforementioned expression.

Quote:
If you define your code to do this and to do that, and you can guarantee it does that as long as you do what you intend to do, the behaviour is very well defined.


Sorry, but the programmer has no legitimity defining what the code does. The language standard is the only entity with the power to define what the code does, and this is what it was written for in the first place. If the standard says the behaviour of your code is undefined, then the behaviour of your code is undefined. This is because compiler writers respect what the language standard says, even if you don't.

Besides, how can you guarantee that your code does what you think it does? The only guarantee that compiler writers ever provide is that their compiler respects the language standard. If you don't respect the language standard, how can you guarantee anything?

Share this post


Link to post
Share on other sites
I'm sorry, but saying you apparently don't know what a bug is seems perfectly justified, given this post. And if you don't even know what "undefined behavior" is, you have no business working with C or C++, because those languages are literally swimming in the stuff. Don't touch either language unless you're prepared to keep track *yourself* of your code's validity.

Quote:
Original post by greenhybrid
In your point of view of undefined behaviour, as soon as STARTINDEX != (rather than >, like you mentioned), is undefined behaviour. If you define your code to do this and to do that, and you can guarantee it does that as long as you do what you intend to do, the behaviour is very well defined.

You CAN NOT guarantee this, or any the kind of behavior, because you are in what the standard states is undefined behavior. It might work for you now. It might work for you tomorrow. It might stop working the day after. It might format your harddrive if you run the code on a friday with a full moon. It is undefined, and merely saying "it worked when I tested it" does not make it any more well-defined, and does certainly not guarantee that it'll keep working when you run it on someone else's computer.

malloc(x) allocates x bytes of memory, starting from the address it returns. Accessing anything that lies before this is undefined, and yes, will quite often cause problems because the memory allocator typically stores information about the allocation in the bytes preceding it.

Quote:
Hence I wrote "pseudo code", to show how it basically works. The following fragment, btw, does not partition my hd, neither does it double the virtual memory or so :D

You mean it didn't do so the last time you compiled and ran it. It might do so now. Or it might not. It might give you the result you expect. Or it might not. That's the point of undefined behavior. You don't know what's going to happen. And you don't know if the same thing is going to happen every time you run the code.

Share this post


Link to post
Share on other sites
Hmm, really, sorry, but, I don't get why the behaviour of my example code of how you can use start indices != 0 should be undefined.

It's much like when writing a stupid parser function like this (warning: pseudo again ;) ):



bool followsPPToken( char **p )
{
if( ((*p)[0]!='\0' && (*p)[0] == '+') && ((*p)[1]!='\0' && (*p)[1] == '+') )
return true;
return false;
}



(code checks if a '++' will be scanned from the current position, no much sense in total :) )

You can give this function some pointer to a sunny place somewhere in an arbitrary string. You don't access from the strings actual start position with a fully quilified offset, but with kinda relative index to the currently scanned position.

My (I say again) quick-and-dirty example code above does also something like this. For sure it's not standard, and as I said above, too, I *don't* recommend this.

Now if my code above is undefined behaviourish, than a parser's function like that must also be, not?


Don't misunderstand me, I just wanna discuss here, without flaming and so ;)


edit: not to forget, I also said above that you have to keep track *everywhere* about the actual starting index (a mess, yes. this is very delphiish [we use Delphi at work, I really hate it])


edit10: ToohrVyk: For sure it's no good idea to return an address before the actual start of the array, but it's only an address, you don't dereferece it by itself, but calculate something like address+offset, and *after* that you dereference it.

Share this post


Link to post
Share on other sites
Quote:
Original post by greenhybrid
Hmm, really, sorry, but, I don't get why the behaviour of my example code of how you can use start indices != 0 should be undefined.

I don't know the standard by heart, and I don't know whether merely subtracting from a pointer returned by malloc yields undefined behavior (assuming you don't actually *dereference* the pointer, which would definitely be undefined). But quite often, C and C++ decides that such apparently harmless tricks are undefined behavior. Why? Because the standard says so. (And the reason it says so is to give more freedom to the compiler writers in implementation issues)

But when working in C/C++, better get used to this. If the standard says something is undefined, then it is undefined. Even if there's no apparent reason for it. Even if it seems to you that there's only one way to implement it anyway, and it should always work.
One reason I could imagine for such a restriction is that there's no absolute rule saying all memory must belong to one continuous address space. So on some architectures, your computed address might not just be a number slightly lower than the address you malloc'ed. It might underflow (and maybe throw an exception), or it might in theory be a really weird datatype that does weird things, rather than just being an integer number)

After all, pointer arithmetic does have some restrictions compared to regular arithmetic (if memory serves, addition of two pointers is undefined, for example, and the NULL pointer is not just 0 either according to the standard), so why not this restriction as well?

In the end, when people yell "undefined behavior" at you, it's generally safe to assume they're right... [grin]

Quote:

It's much like when writing a stupid parser function like this (warning: pseudo again ;) ):

Not entirely like it. The previous example was with subtracting from a pointer pointing to the start of an allocated segment of memory.

It might sound like a trivial difference to you, but the C and C++ standards really like to make such trivial differences determine whether or not something is undefined behavior. :)
edit10: ToohrVyk: For sure it's no good idea to return an address before the actual start of the array, but it's only an address, you don't dereferece it by itself, but calculate something like address+offset, and *after* that you dereference it.[/quote]

Share this post


Link to post
Share on other sites
Quote:
Original post by Spoonbender
Quote:
Original post by greenhybrid
Hmm, really, sorry, but, I don't get why the behaviour of my example code of how you can use start indices != 0 should be undefined.

I don't know the standard by heart, and I don't know whether merely subtracting from a pointer returned by malloc yields undefined behavior (assuming you don't actually *dereference* the pointer, which would definitely be undefined). But quite often, C and C++ decides that such apparently harmless tricks are undefined behavior. Why? Because the standard says so. (And the reason it says so is to give more freedom to the compiler writers in implementation issues)

Yes, pointing a pointer outside of the bounds defined (that is the start to one past the end) is undefined. No dereferencing required. Imagine a segmented system.
Quote:

After all, pointer arithmetic does have some restrictions compared to regular arithmetic (if memory serves, addition of two pointers is undefined, for example, and the NULL pointer is not just 0 either according to the standard), so why not this restriction as well?

And pointers are NOT integers.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this