Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Tander

macrumors 6502a
Original poster
Oct 21, 2011
676
1
Johannesburg, South Africa
Hi guys,

I am busy learning C on my MacBook through xCode as the DE.

The reason I am doing it this way is due to also going into iOS development. So, to be a better iOS developer, I want to make sure I understand the C language better too, as well as Objective-C. :D

I have started reading the book: Learn C on Mac (4th edition) by David Mark's, I think.

Now, the following bit of code I am having issues with - I understand how this code works 99% - the challenge in the code is to make the program compute prime numbers 1 to 100.

I have having difficulty figuring out how / where to implement a for / while loop to count to 100 (candidate is the int I need to get from 1 to 100)

Code:
#include <stdio.h>
#include <math.h> //used for extra math functions
#include <stdbool.h> // Used for the definition of truth

int main(int argc, const char * argv[])
{
    bool isPrime;
    int startingPoint, candidate, last, i;
    
    startingPoint = 235;
    
    if ( startingPoint < 2){
        candidate = 2;
    }
    else if ( startingPoint == 2 ) {
        candidate = 3;
    }
    else {
        candidate = startingPoint;
        if (candidate % 2 == 0 ) /*Test only odd numbers */
            candidate --;
        do {
            isPrime = true;
            candidate +=2;
            last = sqrt( candidate );
            
            for (i =3; (i <= last) && isPrime ;i +=2 ) {
                if ( (candidate % i) == 0)
                    isPrime = false;
            }
        }while ( ! isPrime );
        
        printf ( "The next prime number afer: %d is %d, Happy?" , startingPoint, candidate); 
         return 0;
}
}

After trying a few methods, I am stuck.

Can anyone help a newbie to C out and show me how this is done?

Also, if you can explain a little and not just provide the code, that would be great!

Thanks guys!
 

chown33

Moderator
Staff member
Aug 9, 2009
10,751
8,423
A sea of green
After trying a few methods, I am stuck.

What have you tried? Be specific. Post code, if you wrote code. Otherwise post concise descriptions.


In everyday conversation, how would you tell another person to repeat something 100 times? Again, be specific. Think through exactly what you'd tell them. If you were telling an adult you might not need to give specifics, so imagine you're telling a 4-year-old child who needs every step described in the correct order.

In general, a loop consists of a loop action, which defines the action to perform at each iteration of the loop, and looping conditions, which define a range of values the action is performed over. Look at your description of how to tell a 4-year-old to loop, and how to tell a computer to loop with a 'for' loop, and identify what's the action and what's the looping conditions.



Please explain this code:
Code:
    startingPoint = 235;
Why does it start at 235?

Where did the posted code come from? Did you write it yourself, or copy it from somewhere? If the latter, where was it copied from?
 

Tander

macrumors 6502a
Original poster
Oct 21, 2011
676
1
Johannesburg, South Africa
What have you tried? Be specific. Post code, if you wrote code. Otherwise post concise descriptions.


In everyday conversation, how would you tell another person to repeat something 100 times? Again, be specific. Think through exactly what you'd tell them. If you were telling an adult you might not need to give specifics, so imagine you're telling a 4-year-old child who needs every step described in the correct order.

In general, a loop consists of a loop action, which defines the action to perform at each iteration of the loop, and looping conditions, which define a range of values the action is performed over. Look at your description of how to tell a 4-year-old to loop, and how to tell a computer to loop with a 'for' loop, and identify what's the action and what's the looping conditions.



Please explain this code:
Code:
    startingPoint = 235;
Why does it start at 235?

Where did the posted code come from? Did you write it yourself, or copy it from somewhere? If the latter, where was it copied from?

Thank you for the insightful reply.

With me starting out programming, I really need to practice more "thought-patern" and steps to solving these problems. :cool:

Okay - so I understand for / while / do loops pretty well i think.

This is what I changed and it didn't work:

Code:
 bool isPrime;
    int startingPoint, candidate, last, i;
    
    startingPoint = 5;
    
    if ( startingPoint < 2){
        candidate = 2;
    }
    else if ( startingPoint == 2 ) {
        candidate = 3;
    }
    else {
      [COLOR="Lime"] // candidate = startingPoint;[/COLOR]
      [COLOR="Red"]  for (candidate = startingPoint; candidate < 100; candidate++) {
        [/COLOR]
        
        if (candidate % 2 == 0 ) /*Test only odd numbers */
            candidate --;
        do {
            isPrime = true;
            candidate +=2;
            last = sqrt( candidate );
            
            for (i =3; (i <= last) && isPrime ;i +=2 ) {
                if ( (candidate % i) == 0)
                    isPrime = false;
            }
        }while ( ! isPrime );
        
        printf ( "The next prime number afer: %d is %d, Happy?" , startingPoint, candidate); 
 
            return 0;
}
    [COLOR="red"]}[/COLOR]
}

Okay - so the above code runs - however, it runs ones and it doesn't enter the loop at all.

What I am unsure of is this:

1. Can I have a do loop and another for loop inside a a main for loop - or is this the reason the code won't run the way I intend it to do?

The original code comes from a book published by Apress:

Learn C on the Mac (4th edition) - Author: Dave Mark's

I know to a child I would say:

"Go through all these numbers (1 to 100 ) pick up the prime numbers (numbers that cannot be divided evenly) then write them down for me."

Translating that to the computer is my stumbling block - I mean I can do a simple for loop that counts to 100 which is easy. But I feel I am missing something obvious here.

Can you tell me if I am at least heading down the right direction with my modified code?

I'm going to try work on it tomorrow.

The answer to this question has been given to me on another programming bored - I haven't looked at the code yet because I want to try work my way to the answer.

Thanks again for your assistance.

Edit:

Code:
 startingPoint = 235

This is a random number - there is no real reason for starting at 235. Yes, it's above the 100 boundary - I have modified it in the second code I posted.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,751
8,423
A sea of green
When your posted code "doesn't work", exactly what does it do? What output is produced? If none, then say that.

If you take out the 'for' loop, and only that, leaving other values the same, what output is produced?

Here are some Rules of Thumb:
1. Be specific.
2. Post your code.
3. Describe what you expected to happen.
4. Describe what actually happened.

You're sorta doing #1, definitely doing #2, but you're not doing #3 or #4.

These aren't just rules of thumb for posting, they're guidelines for how to think about debugging your program. For example, if you don't know what's expected to happen, then you don't understand the code. If you don't compare the expectation against the actual result, then you're not testing systematically.

"It doesn't work" could mean almost anything. "I expected it to say '5' but instead it said '12'" is a very specific statement, and if accompanied by the code that was used can be debugged.


Have you mentally stepped through your original code? The code in your first post? You should be able to manually do each step, perhaps using a calculator, and write down the results of each statement. If you follow it logically, you'll be manually performing the same steps the computer does. If you don't know how to do that, then it suggests you don't have as good a grasp of the fundamentals as needed. In other words, if you can't read the code and actually work out what it does, then you have a problem that suggests more studying is needed.


You have two separable problems in your first post:
1. How to use a for loop.
2. How to find a prime number.

You can learn to use a for loop by practicing it with simpler problems. For example, use a for loop to print the numbers from 1-12, one per line. Next, use it to print the odd numbers between 1 and 21, including both end-points. This should teach you how for loops work, because the action done at each iteration is quite simple. You're learning how to loop and how to set up the correct looping conditions.

Once you learn how for loops work (and you can come up with more exercises than just those two above), you can learn how the prime-finding code works. I suggest stepping through it manually. Start with values that will give specific expected results, such as 5 as the starting point, and find the first prime after that. You know the answer, so make sure the answer comes out. Then do it again with a slightly different starting point, such as 7. Again, you know the answer, but it's not the next odd number (9), it's 11. So again, manually step through and make sure it works out.

You can also run the program without a for loop and make sure that an input of 5 produces 7, and an input of 7 produces 11. I suggest doing that BEFORE manually stepping thru the code, because otherwise you have no idea if the code even works. If a single run doesn't produce the expected output, then you need to solve that problem first, before putting it inside a for loop.


I know to a child I would say:

"Go through all these numbers (1 to 100 ) pick up the prime numbers (numbers that cannot be divided evenly) then write them down for me."
Imagine it's a younger child. You have to show each step. Step by step. Do this. Then do this. Then do this. Every. Single. Step.


The original code comes from a book published by Apress:

Learn C on the Mac (4th edition) - Author: Dave Mark's
Which chapter? Which exercise?

From the site for the book:
http://www.apress.com/9781430218098

Referring to the Source Code/Downloads zip file, exactly which project number are you working from?
 
Last edited:

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,561
6,059
You mentioned its not entering the loop at all - how do you know whether it is or isn't, or are you just guessing? Since you don't know any better techniques right now to find out, I suggest putting some sort of printf statement in the loop that let's you know each time it runs.
 

mrichmon

macrumors 6502a
Jun 17, 2003
873
3
First issue, you have no way of knowing whether you are entering the for loop since you don't have a print statement at the top of the for loop.

Try inserting the printf shown below in your code:

Code:
for (candidate = startingPoint; candidate < 100; candidate++) {
    printf("in for loop: candidate= %d startingPoint=%d\n", candidate, startingPoint);

    if (candidate % 2 == 0) /* Test only odd numbers */


That will give you some information about what is happening when you run the code.

You also have the following at the end of your code:
Code:
            return 0;
}
[COLOR="Red"]    }
[/COLOR]}

The indentation suggests that you intend that the red colored brace will close the for statement brace. However, in C indentation is irrelevant. The red closing brace is actually closing the brace for the else statement.

This would also be a lot easier to reason about if you wrote a function to check whether a number is prime. Break the problem down into:
  1. Write main() method that will call a function to determine if a number is prime.
  2. Write function to determine if a number is prime.
  3. Modify main method to loop over 1 to 100 and print all prime numbers.

So, for part 1 get the following working:

Code:
bool is_prime(int n) {
    /* fill in this function */
}

int main(int argc, const char * argv[]) {

    int number = 1; /* change value to test implementation of is_prime() function */
    if(is_prime(number)) {
        printf("%d is prime\n", number);
    } else {
        printf("%d is not prime\n", number);
    }
}

When you have that code working, try to adapt the main function to solve your original problem. The key is that the is_prime function will not need to be modified if you get it working correctly in step 2.

One more thing:
Tander said:
1. Can I have a do loop and another for loop inside a a main for loop - or is this the reason the code won't run the way I intend it to do?
The code will never run the way you intend it to. It will only ever run the way you have written it to run.
 
Last edited:

DesertEagle

macrumors 6502a
Jan 10, 2012
609
8
/home @ 127.0.0.1
You can have one loop inside another ("nested loops"). What kind of loops you decide to use doesn't matter. You should keep as few levels of nesting as possible, or the program will take very long time to terminate.

One obvious problem with your code is that you're setting isPrime to true when you can't know for sure if the number at hand ("candidate") is prime or not. All you know is that it's an odd number.

In most cases, the for-loop won't be executed. When the variable "last" has not been assigned any value, it will be using whatever was in its assigned part of the memory (usually 0 but it can be anything). So if last == 0, it will never be the case that candidate <= last, and the condition for running the loop will not be fulfilled.
 

Tander

macrumors 6502a
Original poster
Oct 21, 2011
676
1
Johannesburg, South Africa
Hi guys :D

Okay, so a lot to reply to here:

@Chown33:

Your reply really help me. I thought I understood the code 99% from the first example that I posted. I then took your advice and went step-by-step through the code on my own, with a calculator to see if I could match the computers result with my result.

I was around 60% accurate and thus I knew I was missing the point of some of the code. I tracked it down to the do-while, loop. It seems I was expecting it start at the top of the loop every time and increment candidate, even if it wasn't a prime.

So after some fiddling and putting printf statements all over the place so I could "see" when / where candidate and last (The sqrt of candidate ) were incremented and sometime why - it was only then I figured out exactly how it works.

So, to test this new found knowledge of how the code works I wrote down 15 random numbers between 20 and 600. I then calculated the next prime number for all those numbers and matched it to the computer 100% of the time!! :D:cool:

So, now I understood exactly how this code was getting the next prime number I decided to tackle my original problem.

Looking at the second code I posted I realized it would never work for two reasons:

1. Having the for loop start within the else statement was not a good idea and this did not work too well. (Unpredictable results) (I'm going through the code again to see exactly what it does when I put it inside the else statement)

2. I had terminaled the loop with:
Code:
 return 0;
- this termination happened inside the for loop - so I was forcing the for loop to end - regardless of results - silly me! :rolleyes:

I picked this up when I was the I was only getting one printf statement in the console - which, was correct and was the first next prime number after 3. So I figured my for loop was ending prematurely. :mad:

Once I realized these things - I moved the termination code (Code that tells the computer program ran okay, no errors, correct?) to outside of the loop, at the end of the main function:

I then moved the for loop to start at the very top and for it to initialize "startingPoint"

This is the modified code:

Code:
int main(int argc, const char * argv[])
{
    bool isPrime;
    int startingPoint, candidate, last, i;
    
    for (startingPoint = 0; startingPoint <= 100; ++startingPoint){

    
    if ( startingPoint < 2){
        candidate = 2;
    }
    else if ( startingPoint == 2 ) {
        candidate = 3;
    }
    else {
        candidate = startingPoint;
        
        
        if (candidate % 2 == 0 ) /*Test only odd numbers */
            candidate --;
        do {
            isPrime = true;
            candidate +=2;
            last = sqrt( candidate );
                      for (i = 3; (i <= last) && isPrime ;i +=2 )
                      {
                              if ( (candidate % i) == 0)
                    isPrime = false;
                                                    }
            
        }
        while ( ! isPrime );
        
        printf ( "The next prime number afer: %d is %d, Happy?\n" , startingPoint, candidate);
    }
    
    }
     return 0;
}

The output is as expected:

Code:
 The next prime number afer: 3 is 5, Happy?
The next prime number afer: 4 is 5, Happy?
The next prime number afer: 5 is 7, Happy?
The next prime number afer: 6 is 7, Happy?
The next prime number afer: 7 is 11, Happy?
The next prime number afer: 8 is 11, Happy?
The next prime number afer: 9 is 11, Happy?
The next prime number afer: 10 is 11, Happy?
The next prime number afer: 11 is 13, Happy?
The next prime number afer: 12 is 13, Happy?
The next prime number afer: 13 is 17, Happy?
The next prime number afer: 14 is 17, Happy?
The next prime number afer: 15 is 17, Happy?
The next prime number afer: 16 is 17, Happy?
The next prime number afer: 17 is 19, Happy?
The next prime number afer: 18 is 19, Happy?
The next prime number afer: 19 is 23, Happy?
The next prime number afer: 20 is 23, Happy?
The next prime number afer: 21 is 23, Happy?
The next prime number afer: 22 is 23, Happy?
The next prime number afer: 23 is 29, Happy?
The next prime number afer: 24 is 29, Happy?
The next prime number afer: 25 is 29, Happy?
The next prime number afer: 26 is 29, Happy?
The next prime number afer: 27 is 29, Happy?
The next prime number afer: 28 is 29, Happy?
The next prime number afer: 29 is 31, Happy?
The next prime number afer: 30 is 31, Happy?
The next prime number afer: 31 is 37, Happy?
The next prime number afer: 32 is 37, Happy?
The next prime number afer: 33 is 37, Happy?
The next prime number afer: 34 is 37, Happy?
The next prime number afer: 35 is 37, Happy?
The next prime number afer: 36 is 37, Happy?
The next prime number afer: 37 is 41, Happy?
The next prime number afer: 38 is 41, Happy?
The next prime number afer: 39 is 41, Happy?
The next prime number afer: 40 is 41, Happy?
The next prime number afer: 41 is 43, Happy?
The next prime number afer: 42 is 43, Happy?
The next prime number afer: 43 is 47, Happy?
The next prime number afer: 44 is 47, Happy?
The next prime number afer: 45 is 47, Happy?
The next prime number afer: 46 is 47, Happy?
The next prime number afer: 47 is 53, Happy?
The next prime number afer: 48 is 53, Happy?
The next prime number afer: 49 is 53, Happy?
The next prime number afer: 50 is 53, Happy?
The next prime number afer: 51 is 53, Happy?
The next prime number afer: 52 is 53, Happy?
The next prime number afer: 53 is 59, Happy?
The next prime number afer: 54 is 59, Happy?
The next prime number afer: 55 is 59, Happy?
The next prime number afer: 56 is 59, Happy?
The next prime number afer: 57 is 59, Happy?
The next prime number afer: 58 is 59, Happy?
The next prime number afer: 59 is 61, Happy?
The next prime number afer: 60 is 61, Happy?
The next prime number afer: 61 is 67, Happy?
The next prime number afer: 62 is 67, Happy?
The next prime number afer: 63 is 67, Happy?
The next prime number afer: 64 is 67, Happy?
The next prime number afer: 65 is 67, Happy?
The next prime number afer: 66 is 67, Happy?
The next prime number afer: 67 is 71, Happy?
The next prime number afer: 68 is 71, Happy?
The next prime number afer: 69 is 71, Happy?
The next prime number afer: 70 is 71, Happy?
The next prime number afer: 71 is 73, Happy?
The next prime number afer: 72 is 73, Happy?
The next prime number afer: 73 is 79, Happy?
The next prime number afer: 74 is 79, Happy?
The next prime number afer: 75 is 79, Happy?
The next prime number afer: 76 is 79, Happy?
The next prime number afer: 77 is 79, Happy?
The next prime number afer: 78 is 79, Happy?
The next prime number afer: 79 is 83, Happy?
The next prime number afer: 80 is 83, Happy?
The next prime number afer: 81 is 83, Happy?
The next prime number afer: 82 is 83, Happy?
The next prime number afer: 83 is 89, Happy?
The next prime number afer: 84 is 89, Happy?
The next prime number afer: 85 is 89, Happy?
The next prime number afer: 86 is 89, Happy?
The next prime number afer: 87 is 89, Happy?
The next prime number afer: 88 is 89, Happy?
The next prime number afer: 89 is 97, Happy?
The next prime number afer: 90 is 97, Happy?
The next prime number afer: 91 is 97, Happy?
The next prime number afer: 92 is 97, Happy?
The next prime number afer: 93 is 97, Happy?
The next prime number afer: 94 is 97, Happy?
The next prime number afer: 95 is 97, Happy?
The next prime number afer: 96 is 97, Happy?
The next prime number afer: 97 is 101, Happy?
The next prime number afer: 98 is 101, Happy?
The next prime number afer: 99 is 101, Happy?
The next prime number afer: 100 is 101, Happy?

YAY!!! :D:D:D

So happy when I made this realization - once I figured out exactly how the original code worked - it took a whole of 30 seconds to modify to to work as I wanted it to! :D :D:D

Once again, thank you Chown33!

@ ArtOfWarfare:

I wasn't guessing at first - I could only see the first result in the console and this was a clue that the loop only ran once or not at all. I later figured out adding more printf statements would help me track the problem down!

Thanks! :D

@ mrichmon

I realize now you actually provided me with a clue (indentation) which was the biggest problem with the modified code I posted. Tomorrow I will look at your own code and see if I can fill that function in - although I now understand my original code 100% - I must keep getting better at this and more practice!

@ DesertEagle

isPrime is set to true at the top of the do-while, loop - at the bottom we check to see if candidate really is prime - if it is not - we set isPrime to false - the loop will continue to run until we can not divide candidate
evenly by " i " and thus, leaving isPrime as true - terminating the do-while, loop.


"Last" will always have a value as it gets assigned the square root of candidate - and candidate gets its value from startingPoint, which always has a value:

So:

startingPoint is initilized to a value by the for loop at the top (Modified code)
half way down, we assign startingPoint's value to candidate:

Code:
        candidate = startingPoint;

This is after we check and make sure candidate is higher than 3 - since we know, 2 is the next prime number after 1 and 3 is after 2.

Once that happens and we get into the d-while, loop (I am skipping a bit of code here, I know, but I don't think it needs me to explain? )
we then get the square root of candidate

Code:
 last = sqrt( candidate );

So, as far as I understand it - last will always have a value.
Also, the do-while, loop is not conditioned upon last having a value - it's conditioned upon this:

Code:
        while ( ! isPrime );

I may have it wrong - but this is how I understand some of the code?

I didn't feel it was needed for me to explain the whole code, step by step?

I think i will give myself a pat on the back? :D

Appreciate all the help guys - I know this was a "simple" problem, but it has helped me a lot I will now make sure I understand the code 100% before trying to change it. It has also taught me more about loops and math functions than before. So I guess it's good progress?
 
Last edited:

PatrickCocoa

macrumors 6502a
Dec 2, 2008
751
149
chown FTW

I'd lilke to add to OP's praise of chown's teaching style. I've seen chown help a lot of people in this forum. Their underlying problem is that they've bitten off more than they can chew and don't know it. chown's analysis method (to paraphrase: baby steps, MF'er) is the best path to both solving whatever your current problem is, and to having a method to solve future problems.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.