Personal computing discussed

Moderators: SecretSquirrel, just brew it!

IntelMole
Grand Gerbil Poohbah
Topic Author
Posts: 3505
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub
Contact:

### Stupid Gremlins :-D

Okay, this one's just a quickie I promise...

I was looking for some source code to learn a bit more about C, found a fractions calculator and decided I'd have a go at making one myself in the same style, without copying

Got it to the stage where it'll work out the fractions being entered... compiled it... went to sleep.

Woke up, recompiled it to the same point (because I'm paranoid, see earlier thread in Back Porch ) and went to run it... only to get it playing infinite loop on me...

Here's the source, the gremlins that be decided it was going to bugger up around second fraction/switch loop time There is more, but it doesn't ever get there.... lol

``#include <stdio.h>#define QUIT 'q'int nom1 = 0, nom2 = 0, denom1 = 0, denom2 = 0;int add(), subtract(), multiply(), divide();int nom1, nom2, denom1, denom2;main(void){ int choice = 0; char quit = 0; printf("Enter each fraction in the form numerator/denominator\n"); printf("Enter the first fraction\n"); scanf("%d\%d", &nom1, &denom1); printf("Enter the second fraction\n"); scanf("%d\%d", &nom2, &denom2);do  {   printf("\nKey:\n");   printf("1\t Add\n");   printf("2\t Subtract\n");   printf("3\t Multiply\n");   printf("4\t Divide\n");   printf("Enter an operation\n");   scanf("%d", &choice);   switch (choice)          {           case(1):           Add();           break;           case(2):           Subtract();           break;           case(3):           Multiply();           break;           case(4):           Divide();           break;           case(0):           printf("Enter a valid choice");           break;           default:           printf("Enter a valid choice");           break;           }  } while(choice < 1 || choice > 4);  while(quit != QUIT);  {   printf("\n\nEnter q to quit\n");   scanf("%c", &quit);  }}``

I know that it's just something REALLY stupid

But I can't see it, it's staring me right it the face I know it, I must have changed something I think... but I can't for the life of me see it...

Oh, and trying to stare the code out doesn't work either ,
IntelMole[/quote]
Living proof of John Gabriel's theorem

IntelMole
Grand Gerbil Poohbah
Topic Author
Posts: 3505
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub
Contact:
Found it

See the little scanf statements... the damn slashes are the wrong way around!!!!

I recently played with those actually... so I must have just put them in the wrong way...

Whoops, now I feel stupid ,
IntelMole
Living proof of John Gabriel's theorem

etilena
Gerbil Jedi
Posts: 1674
Joined: Wed Jun 12, 2002 7:43 am
Location: .ozziefied.
Yeah, hate it when I look through lines and lines of code and can't figure out what I did wrong and then notice a little typo. Then I grumble about the half an hour I wasted tryin go fix somethin silly.

Haha, though I'm getting more proficient and detecting bugs. Debuggers are sometimes really dumb, you have to comment out lines and lines before they point you to the actual mistake.
*yawn*

IntelMole
Grand Gerbil Poohbah
Topic Author
Posts: 3505
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub
Contact:
My pet hate ATM is writing "print" instead of "printf"... damn VBA screwed me up good But I'm getting used to that one...

Another thing that really annoys me about C is that you have to put a ";" at the end of EVERY line, and I might forget once every 15-20 or so lines... it's like "I know it's supposed to be there, you know it's supposed to be there, so why not just put one there for me!?!?!?!"

Damn quirks,
IntelMole
Living proof of John Gabriel's theorem

Craig P.
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN
IntelMole wrote:
My pet hate ATM is writing "print" instead of "printf"... damn VBA screwed me up good

I'd be worried about doing "?" or "?f".

Another thing that really annoys me about C is that you have to put a ";" at the end of EVERY line, and I might forget once every 15-20 or so lines... it's like "I know it's supposed to be there, you know it's supposed to be there, so why not just put one there for me!?!?!?!"

Which is great, except for the times when you want to extend to another line. Then again, I do think it's better to use \n as a sentence termination and use continuations when you need them, but it's not my language.

Gerbil Elite
Posts: 909
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK
Contact:
`` while(quit != QUIT);  {   printf("\n\nEnter q to quit\n");   scanf("%c", &quit);  } ``

This looks wrong - to be precise, the first line. I believe I'm right in saying that that is saying "while quit isn't QUIT, do nothing (i.e. do nothing forever), then when you've finished your infinite loop, print a line and read in 'quit'".

In other words, you don't want a semicolon after the while condition.

Personally I like the C "whitespace and newlines are irrelevant" philosophy. You get used to the semicolons - a line of code now looks wrong to me if it doesn't end with a ; unless I know it's a run-on. (e.g.
``if(something)    do_stuff();``

)

zgirl
Grand Gerbil Poohbah
Posts: 3987
Joined: Tue Jan 01, 2002 7:00 pm
Location: The dark side of the moon
Contact:
Wow!!!

My old C instructor would have dragged you out into the street and shot you for the code that you posted.

Why?

It is common practice and preferred that you DO NOT write any code in the Main function, unless absolutely necessary.

You always call your functions from Main. Maybe an if statement or two to decide with function to call, but never write code in there other wise.
"I used to think the brain was the most amazing organ in the entire body. Then I realized who was telling me this."
If ignorance were painful, half the posters here would be on morphine drips.

just brew it!
Gold subscriber
Posts: 50020
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer
z-man, it sounds to me like your instructor was incredibly anal.

While I agree it is generally a good idea to keep main() as simple as possible -- i.e. short and to the point -- a blanket "don't put any program logic in main()" rule is just plain silly.

liquidsquid
Minister of Gerbil Affairs
Posts: 2559
Joined: Wed May 29, 2002 10:49 am
Location: New York
Contact:
Agreed, too anal. Your main routine should follow your top level flow chart you have drawn up. In the case of an large embedded system, it may be like this (a bit simplified).

``int main(void) {  initPeripherals();  initObjectSystem();  getSettings();  while(!exitProg) handleTasks();  return errCode;}``

But that is because there is a large amount of code to pour through under each call, and wouldn't make sense all shoved in main(). However if you have a simple prog like what you have shown, and can all be displayed on one or two sheets of paper, there is no reason to keep everything out of main apart from stealing a few bytes of ram on your stack.

The "keep everything out of main()" mentality is more for documentation reasons than code reasons. On large projects you will tend to organize your code for better readability, and reducing main() is one of the many things you will do.

Also consider a tiny microcontroller with 64 bytes of ram. Do you want to start right off with 2 less, and all those two bytes are holding is the enterance address never to be used again? Silly... Every byte, nibble, and bit counts on these processors. Although programming small controllers in C is overkill, you would normally program in assembly since the code is usually so intimate with the hardware, portability of C is typically non-existant anyway.

-LS
Last edited by liquidsquid on Thu Jul 17, 2003 2:52 pm, edited 1 time in total.

fc34
Minister of Gerbil Affairs
Posts: 2816
Joined: Wed May 08, 2002 8:39 am
Location: Somewhere
Theres nothing wrong with:

while (quit != QUIT) theoretically.

you initialized quit as char.

char means either boolean or 1 ASCII character.

QUIT is neither a boolean nor a character.

The reason y u r stuck with the loop is that you are not setting quit to QUIT. In the first place this would be invalid if you tried to do so. But since you are not doing it, the computer jus loops till the condition is true, which will never happen in this case.

You should change it to something like

char temp= ""
//code//

while (temp == "")
{
printf("Press Anykey to quit")
scanf("&c", temp)
}
Windows XP - The 64-bit wannabe with a 32-bit graphics interface for 16-bit extensions to a 8-bit patch on a 4-bit operating system designed to run on a 2-bit processor by a company that can't stand 1-bit of competition

moog
Gerbil Elite
Posts: 868
Joined: Wed Jun 11, 2003 9:10 am
Unless the quit loop is just for excercise/learning, may I suggest removing the quit loop entirely. IMHO it doesn't serve any purpose except to wait for the user to hit a key (here 'q'). So you could just remove the loop and leave it like this:

printf("\n\nEnter q to quit\n");
scanf("%c", &quit);

You could hit q or anything, doesn't matter, the program exits.

Craig P.
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN
z-man wrote:
It is common practice and preferred that you DO NOT write any code in the Main function, unless absolutely necessary.

I think that's overstating it. You generally want to avoid huge functions that do too much at once, and this will generally mean that for a large program, there won't be anything in main(), but I certainly don't subscribe to a hard rule that there's nothing in main().

Gerbil Elite
Posts: 909
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK
Contact:
fc34 wrote:
The reason y u r stuck with the loop is that you are not setting quit to QUIT.

But surely he would be, if only that semicolon weren't there?

fc34 wrote:
char temp= ""

I may be wrong, but don't chars use 'single' quotes, and it's strings (insofar as they exist in C) which use "double" quotes?

liquidsquid
Minister of Gerbil Affairs
Posts: 2559
Joined: Wed May 29, 2002 10:49 am
Location: New York
Contact:
Craig P. wrote:
z-man wrote:
It is common practice and preferred that you DO NOT write any code in the Main function, unless absolutely necessary.

I think that's overstating it. You generally want to avoid huge functions that do too much at once, and this will generally mean that for a large program, there won't be anything in main(), but I certainly don't subscribe to a hard rule that there's nothing in main().

Quite true. My general rule of thumb is if it is more than one page in length, break it up if possible into calls. There are times when it wouldn't make any sense to break it up like a large calculation routine like a FFT or something, but if you are beyond a page in one routine, it is time to see if you can simplify. (One page being around 40 lines of CODE, not comments)

-LS

Glorious
Gold subscriber
Posts: 10393
Joined: Tue Aug 27, 2002 6:35 pm
While I agree it is generally a good idea to keep main() as simple as possible -- i.e. short and to the point -- a blanket "don't put any program logic in main()" rule is just plain silly.

It's definitely overboard, but there is a simple reason for it.

Students (your average student taking C++ programming, not us computer enthusiasts who love tinkering with everything) new to programming often like to stick to what they've already learned, so instead of using functions after being introduced to them, they just continue to do everything in int main() .

So teachers tend to get a little too zealous in telling students to stop doing that, after years of teaching and seeing students do the same thing over and over again, hell, I'd probably make a rule like that too.

IntelMole
Grand Gerbil Poohbah
Topic Author
Posts: 3505
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub
Contact:
moog wrote:
Unless the quit loop is just for excercise/learning, may I suggest removing the quit loop entirely. IMHO it doesn't serve any purpose except to wait for the user to hit a key (here 'q'). So you could just remove the loop and leave it like this:

printf("\n\nEnter q to quit\n");
scanf("%c", &quit);

You could hit q or anything, doesn't matter, the program exits.

Don't worry, there is a reason. I was planning to put a help key in as well...

FWIW, I also defined QUIT as 'q', but I think QUIT and HELP are more readable than q and h... Personal opinion though, if I was being anal about memory used, i suppose I could change it...

Oh, and the "keep main() clear" issue:
My own opinion is that main should be a program flow controller, so it should call any complex functions e.g. Add(), Subtract(), Cancel() etc. that require more than about 5 lines of code) or any function that needs to bugger with the values of the functions (since it will create temporary versions of these variables, say I needed to square root a number, add it to a variable being pointed to, and then return the value to the original variable, and do some comparison, I'd be more comfortable doing that with temporary variables...)

That's why I've tried to put initial input, and the switch(choice) function in main(), and handed math to other functions...

But hey, I've only been doing this a while, maybe I'll change my own opinion later, but it's my 0.02...

Anyone know of an algorithm to do the highest common factor, for a function Cancel()? My own thought is that it'll be recursive as long as the HCF is >1, possibly using an array similar to the sieve of eratosthenes method in the other post... I'll put my version in and then check back later probably...

Cheers for the input guys,
IntelMole
Living proof of John Gabriel's theorem

Craig P.
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN
IntelMole wrote:
Anyone know of an algorithm to do the highest common factor

C or C++?

If C++, check the standard library and check boost. It seems like the sort of thing that would be in one of the two.

IntelMole
Grand Gerbil Poohbah
Topic Author
Posts: 3505
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub
Contact:
It's being done in vanilla C...

I was kinda thinking of writing it myself though... will probably be along the lines of the following pseudocode:

``HCF(){   while there's a common factor > 1   {      find HCF      HCF   }}``

Possibly using some form of array up to the numerator or denominator, whichever is lower...

Thanks anyways,
IntelMole
Living proof of John Gabriel's theorem

moog
Gerbil Elite
Posts: 868
Joined: Wed Jun 11, 2003 9:10 am
... I'm not sure but I'm guessing you want a greatest common denominator function? (like the gcd of 25 and 10 is 5?)

I'll post a non-recursive (gcd1) & recursive version
``int gcd1(int min, int max) {   int rem, tmp;   if (max < min) {      tmp = max;      max = min;      min = tmp;   }   while ((rem = max % min) != 0) {      max = min;      min = rem;   }   return min;}int gcd2(int min, int max) {   int rem = max % min;   if (rem == 0)      return min;   return gcd2(rem, min);}``

gcd1 has a check to see if max is really the maximum number, gcd2 doesn't (the check is better done before calling gcd2 for efficiency).

These algos are well known, you can google for Euclid's gcd algo.

Edit: In gcd1, you can replace tmp with rem (get rid of tmp). (I know, useless quibbling is my specialty )

Gerbil Elite
Posts: 909
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK
Contact:
GCD (greatest common divisor) == GCD (greatest common denominator) == HCF (highest common factor).

``private void cancel() {   if (denom == 1) return;   long allGCD = coeffs[0], commonDivisor;   for (int i=1; i<coeffs.length; i++)       allGCD = euclid(allGCD, coeffs[i]);   commonDivisor = euclid(allGCD, denom);   if (commonDivisor < 0) commonDivisor = -commonDivisor;   if (commonDivisor == 1) return;   denom /= commonDivisor;   for (int i=0; i<coeffs.length; i++)       coeffs[i] /= commonDivisor;}``

The above is from one of our Java assignments, but most of the code except the for loops (I don't believe C has any direct method for finding the length of an array, since it doesn't actually have arrays, so you'll have to store it in a variable or constant beforehand or something) should be valid C as well. It's from a class definition representing univariate polynomials - a set of coefficients (a + bx + cx^2 + ...) stored in the array coeffs, plus a single common denominator denom. (The "euclid" function I use is just Euclid's GCD algorithm, you could use either of the implementations moog posted.)

It won't do exactly what you want, since you're entering a set of fractions each with their own denominator whereas this one shares the denominator, but the two methods are mathematically equivalent and it shouldn't be too hard to modify it to what you want
Last edited by BigMadDrongo on Mon Jul 21, 2003 6:27 pm, edited 1 time in total.

Gerbil Elite
Posts: 909
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK
Contact:
moog wrote:
Edit: In gcd1, you can replace tmp with rem (get rid of tmp). (I know, useless quibbling is my specialty )

For bonus points - anyone know how you can get rid of tmp without confusingly using rem for the same purpose? (In other words, swap two variables without using any additional variables?)

murray
Gerbil XP
Posts: 368
Joined: Wed Dec 26, 2001 7:00 pm
Location: Austin, TX
Contact:
x = x - y;
y = x + y;
x = -x + y;

At least, that's all i can come up with on the spot.

moog
Gerbil Elite
Posts: 868
Joined: Wed Jun 11, 2003 9:10 am
For bonus points - anyone know how you can get rid of tmp without confusingly using rem for the same purpose? (In other words, swap two variables without using any additional variables?)

x ^= y;
y ^= x;
x ^= y;

I tend not to use this. I get the feeling this would cause more of a pipeline stall due to dependencies? (I dunno, I'm not an assembler expert) Here let's say registers eax and ebx hold the vals to swap
xor eax, ebx
xor ebx, eax
xor eax, ebx

As opposed to swapping using a temporary reg/mem
mov [tmp], eax
mov eax, ebx
mov ebx, [tmp]

The compiler may use another register instead of mem for the temp var. Anybody know what's better? The xor trick or using a temp var.? (murray's trick also works too, but I think it takes 4 instructions as opposed to 3)

Gerbil Elite
Posts: 909
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK
Contact:
I've never been much of a low-level programmer, so I couldn't comment on the assembler considerations. (This is why I got fairly irritated when early on in the course our Java lecturer decided to spend fully fifteen minutes explaining an obscure trick about how to reverse a hexadecimal number in Java using the bitwise operators - before he'd so much as shown us a 'for' loop or 'if' statement. Fortunately I knew a decent amount of Java and C already...)

I hadn't seen that negation trick though - neat.

moog
Gerbil Elite
Posts: 868
Joined: Wed Jun 11, 2003 9:10 am
If you're curious, murray's negation trick will look something like this in assembler (eax = x, ebx = y),

sub eax, ebx
neg eax

murray
Gerbil XP
Posts: 368
Joined: Wed Dec 26, 2001 7:00 pm
Location: Austin, TX
Contact:
That XOR trick is pretty spiffy, I hadn't thought of that before.

Only situation I can think of that this sort of thing would really be useful is if you were absolutely positively out of registers and didn't want to force a memory access.

### Who is online

Users browsing this forum: MOSFET, Ryu Connor and 0 guests