Stupid Gremlins :-D

From Visual Basic to GNU C, this is the place to talk programming.

Moderators: SecretSquirrel, just brew it!

Stupid Gremlins :-D

Postposted on Sun Jul 13, 2003 7:30 pm

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 :-D

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 :-D) 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 :-D There is more, but it doesn't ever get there.... lol

Code: Select all
#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 :-D

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 :lol:,
IntelMole[/quote]
Living proof of John Gabriel's theorem
IntelMole
Grand Gerbil Poohbah
 
Posts: 3529
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub

Postposted on Sun Jul 13, 2003 8:38 pm

Found it :-D

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 :-D,
IntelMole
Living proof of John Gabriel's theorem
IntelMole
Grand Gerbil Poohbah
 
Posts: 3529
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub

Postposted on Sun Jul 13, 2003 8:51 pm

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. :wink:

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*
etilena
Gerbil Jedi
 
Posts: 1669
Joined: Wed Jun 12, 2002 7:43 am
Location: .ozziefied.

Postposted on Tue Jul 15, 2003 8:41 pm

My pet hate ATM is writing "print" instead of "printf"... damn VBA screwed me up good :-D 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!?!?!?!" :-D

Damn quirks,
IntelMole
Living proof of John Gabriel's theorem
IntelMole
Grand Gerbil Poohbah
 
Posts: 3529
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub

Postposted on Wed Jul 16, 2003 12:41 am

IntelMole wrote:My pet hate ATM is writing "print" instead of "printf"... damn VBA screwed me up good :-D


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

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!?!?!?!" :-D


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.
Craig P.
Gerbil Team Leader
 
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN

Postposted on Wed Jul 16, 2003 6:53 am

Code: Select all
 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.
Code: Select all
if(something)
    do_stuff();

)
BigMadDrongo
Gerbil Elite
 
Posts: 913
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK

Postposted on Wed Jul 16, 2003 7:24 am

Wow!!!

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

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.
zgirl
Grand Gerbil Poohbah
 
Posts: 3938
Joined: Tue Jan 01, 2002 7:00 pm
Location: The dark side of the moon

Postposted on Wed Jul 16, 2003 9:35 am

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.
just brew it!
Administrator
Gold subscriber
 
 
Posts: 37495
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Postposted on Wed Jul 16, 2003 9:56 am

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).

Code: Select all
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.
liquidsquid
Minister of Gerbil Affairs
 
Posts: 2447
Joined: Wed May 29, 2002 10:49 am
Location: New York

Postposted on Thu Jul 17, 2003 9:38 am

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
fc34
Minister of Gerbil Affairs
 
Posts: 2816
Joined: Wed May 08, 2002 8:39 am
Location: Somewhere

Postposted on Thu Jul 17, 2003 9:52 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.
moog
Gerbil Elite
 
Posts: 836
Joined: Wed Jun 11, 2003 9:10 am
Location: Here

Postposted on Thu Jul 17, 2003 11:17 am

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().
Craig P.
Gerbil Team Leader
 
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN

Postposted on Thu Jul 17, 2003 2:26 pm

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?
BigMadDrongo
Gerbil Elite
 
Posts: 913
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK

Postposted on Thu Jul 17, 2003 2:54 pm

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
liquidsquid
Minister of Gerbil Affairs
 
Posts: 2447
Joined: Wed May 29, 2002 10:49 am
Location: New York

Postposted on Fri Jul 18, 2003 5:05 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.
Glorious
Darth Gerbil
Gold subscriber
 
 
Posts: 7837
Joined: Tue Aug 27, 2002 6:35 pm

Postposted on Sat Jul 19, 2003 5:22 pm

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
IntelMole
Grand Gerbil Poohbah
 
Posts: 3529
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub

Postposted on Mon Jul 21, 2003 12:02 am

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.
Craig P.
Gerbil Team Leader
 
Posts: 285
Joined: Tue Dec 31, 2002 3:12 am
Location: South Bend, IN

Postposted on Mon Jul 21, 2003 4:47 pm

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:

Code: Select all
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
IntelMole
Grand Gerbil Poohbah
 
Posts: 3529
Joined: Sat Dec 29, 2001 7:00 pm
Location: The nearest pub

Postposted on Mon Jul 21, 2003 5:52 pm

... 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
Code: Select all
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. :wink:

Edit: In gcd1, you can replace tmp with rem (get rid of tmp). (I know, useless quibbling is my specialty 8) )
moog
Gerbil Elite
 
Posts: 836
Joined: Wed Jun 11, 2003 9:10 am
Location: Here

Postposted on Mon Jul 21, 2003 6:23 pm

GCD (greatest common divisor) == GCD (greatest common denominator) == HCF (highest common factor).

Code: Select all
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.
BigMadDrongo
Gerbil Elite
 
Posts: 913
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK

Postposted on Mon Jul 21, 2003 6:25 pm

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

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?)
BigMadDrongo
Gerbil Elite
 
Posts: 913
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK

Postposted on Mon Jul 21, 2003 7:25 pm

x = x - y;
y = x + y;
x = -x + y;

At least, that's all i can come up with on the spot.
murray
Gerbil XP
Gold subscriber
 
 
Posts: 369
Joined: Wed Dec 26, 2001 7:00 pm
Location: Austin, TX

Postposted on Tue Jul 22, 2003 8: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)
moog
Gerbil Elite
 
Posts: 836
Joined: Wed Jun 11, 2003 9:10 am
Location: Here

Postposted on Tue Jul 22, 2003 4:03 pm

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.
BigMadDrongo
Gerbil Elite
 
Posts: 913
Joined: Mon Apr 29, 2002 12:57 pm
Location: London, UK

Postposted on Tue Jul 22, 2003 4:16 pm

If you're curious, murray's negation trick will look something like this in assembler (eax = x, ebx = y),

sub eax, ebx
add ebx, eax
neg eax
add eax, ebx
moog
Gerbil Elite
 
Posts: 836
Joined: Wed Jun 11, 2003 9:10 am
Location: Here

Postposted on Tue Jul 22, 2003 11:35 pm

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.
murray
Gerbil XP
Gold subscriber
 
 
Posts: 369
Joined: Wed Dec 26, 2001 7:00 pm
Location: Austin, TX


Return to Developer's Den

Who is online

Users browsing this forum: No registered users and 2 guests