Thread: Stumped on role of a particular statement in a program with Arrays & Nested For Loops

  1. #1
    Registered User
    Join Date
    Dec 2016
    Posts
    45

    Stumped on role of a particular statement in a program with Arrays & Nested For Loops

    I'm teaching myself C with this book: Amazon.com: C Programming: A Modern Approach, 2nd Edition (8601300250168): K. N. King: Books

    I have been going through examples providing by the author, and adding my own notes in Visual Studio.

    I get the "big picture" of the loops contained within the program, but some of the details are lost on me.

    I was hoping you could enlighten me on the role of the statement that is circled in red below in the pictures? What is it doing?

    Within the context of that first loop's brackets, the statement in red seems unnecessary. But when I delete it, I get a program that doesn't function as intended. So it must be tied to one of the two loops below it. I'm scratching my head what it actually does.

    Any help would be much appreciated!

    Hobbit, are you around?

    I included the text from the book, some screenshots from Visual Studio containing my notes, and the source code below

    The author alludes to the purpose in orange below but he isn't 100% explicit what is going on. It's strange because the statement in red deals with an array containing the Initial Balance, but in the loop it is contained in deals with the interest rate labels on the top row of the print


    "The second row is a little trickier, since its values depend on the numbers in the first row. Our solution is to store the first row in an array as it's computed, then use the values in the array to compute the second row."


    -----------------------------------------------------------------------------

    Computing Interest

    Our program prints a table showing the value of $100 invested at different rates of interest over a period of years. The user will enter an interest rate and the number of years the money will be invested. The table will show the value of the money at one-year intervals---at that interest rate and the next four higher rates---assuming that interest is compounded once a year. Here's what a session with the program looks like:

    Enter interest rate: 6
    Enter number of years: 5

    Stumped on role of a particular statement in a program with Arrays & Nested For Loops-chart-png


    Clearly, we can use a For Statement to print the first row.

    The second row is a little trickier, since its values depend on the numbers in the first row. Our solution is to store the first row in an array as it's computed, then use the values in the array to compute the second row.

    Of course, this process can be repeated for the third and later rows.

    We will end up with two For Statements, one nested inside the other:
    -The outer loop will count from 1 to the number of years requested by the user
    -The inner loop will increment the interest rate from its lowest value to its highest value

    Not the use of NUM_RATES to control two of the For Loops. If we later change the size of the array called value, the loops will adjust automatically.



    -----------------------------------------------------------------------------------------------------------------------------------



    CLICK FOR BIG PICTURES WITHOUT COMPRESSION

    Stumped on role of a particular statement in a program with Arrays & Nested For Loops-initial-balance-jpg
    Stumped on role of a particular statement in a program with Arrays & Nested For Loops-program2-jpg




    -----------------------------------------------------------------------------------------------------------------------------------

    <img src="http://i.cubeupload.com/lQ5fzp.jpg">


    Code:
    #include<stdio.h>
    Code:
    
    
    #define NUM_RATES(sizeof(value)/sizeof(value[0]))    /*   NUM_RATES is a macro thatfinds the length of the array 
                                                          based on the SIZE OF THE ARRAY in bytes ( size of(value) ) DIVIDED BYthe SIZE OF EACH ELEMENT ( sizeof(value[0]) )   */
    #defineINITIAL_BALANCE 100.00
    
    
    
    main()
    {
    intlow_rate;                         /*Userinput --- the lowest interest rate*/
    intnum_years;                        /*Userinput --- the number of years*/
    inti; 
    intyear;
    floatvalue[5];                      /*Remember that the number in the brackets represents the number ofelements --- 1 for each of the 5 year timeline in this case */
    
    printf("Enterinterest rate: ");
    scanf("%d",&low_rate);
    printf("Enternumber of years: ");
    scanf("%d",&num_years);
    
    
    printf("\nYears");                 /*This statement prints outthe label for the "YEAR" column on the left side of the chart */
    
    
    
    /*This loop prints out the LABELS FOR THE INTEREST RATE ROW AT THE TOP.  Right next to the "Year" */
    
    for(i = 0; i < NUM_RATES; i++) {   /*   NUM_RATES is 5 here
     Remember that NUM_RATES, seen above, is amacro for (sizeof(value)/sizeof(value[0]))
         This macro measures the LENGTH of thearray by dividing the array size in bytes by the element size in bytes
         The macro format makes it easy for theloops to adjust if we need to CHANGE THE SIZE OF THE ARRAY   */
    
    printf("%6d",low_rate +i);                /* Prints out the low rate + i  according to the loop above */
    
    
    value[i]= INITIAL_BALANCE;
    }
    
    
    
    printf("\n");                       /*   This statement starts a new line for theloop below   */
    
    
    
    /*   This loop prints the numbers IN THE YEARSCOLUMN.    Counts from 1 to the number ofyears entered by the user   */
    
    for(year = 1; year <= num_years; year++) {
    printf("%3d    ", year);
    
    
    
    /*   This NESTED loop increments the interestrate FROM ITS LOWEST VALUE TO ITS HIGHEST VALUE AND MULTIPLIES IT BY $100.Occurs right after the year column entry printed   */
    for(i = 0 ;  i < NUM_RATES ; i++) {
    value[i]= value[i] + ( ((low_rate + i) / 100.0) *  value[i]);
    printf("%7.2f",value[i]);
    }
    printf("\n");             /*This statement causes the valueto be placed on the next line*/
    }
    
    return0;
    
    }


    Attached Images Attached Images Stumped on role of a particular statement in a program with Arrays &amp; Nested For Loops-output2-jpg 
    Last edited by potomac; 12-05-2016 at 07:52 AM.

  2. #2
    Registered User
    Join Date
    Dec 2016
    Posts
    45
    I can't seem to edit any post anymore.

    Just to be clear, the statement I'm confused about is this one: value[i]= INITIAL_BALANCE;

  3. #3
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I don't know what you mean by your note "gets expected output here". Is that the expected output? Only the header line of the table? Why is that "expected"? It's not what I expected. And where is the rest of the code in the second listing? Is it there but you just don't show it, or did you remove that too?

    Anyway, the loop in question is doing two things at once.
    It's printing out the top row of the table (incorrectly spaced!).
    And it is also INITIALIZING the value array.
    Without initialization, the value array will contain arbitrary values.

  4. #4
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Your post is quite thorough ... a bit too much, in my opinion. I just glossed over to find the question at hand.

    The statement you're asking about in the first "for()" loop initializes all elements in the "value" array.

    This is because afterwards, the first operation on each element of the "value" array (in the third loop) depends upon the initial value of each element (value[i] = value[i] + ...). If the array is not initialized first, each element contains garbage, so the result of the subsequent operations are garbage.

    Does that answer your question?

    In the future, I would suggest avoiding images of code and output. Output can be posted in code tags, as well as the code itself. Also be sure the code is properly formatted before submitting (try "paste as text" to prevent unnecessary markup, so the formatting remains intact and the forum's code highlighting works properly), and preview your post to ensure the code looks right.

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Note that neither Matticus or I are able to explain your output. Without the initialization line, I would expect the table to be printed with arbitrary values, whereas your output shows that only the header line was printed. That makes no sense to me.

    Here's your code in a readable format:
    Code:
    #include <stdio.h>
    
    #define NUM_RATES ((int)(sizeof(value)/sizeof(value[0])))
    #define INITIAL_BALANCE 100.00
    
    int main() {
        int low_rate;
        int num_years;
        int i;
        int year;
        float value[5];
    
        printf("Enter interest rate: ");
        scanf("%d", &low_rate);
        printf("Enter number of years: ");
        scanf("%d", &num_years);
    
        printf("\nYears  ");
    
        for(i = 0; i < NUM_RATES; i++) {
            printf("%7d", low_rate + i);
            //value[i] = INITIAL_BALANCE;   // with this commented out, it still prints the table body.
        }
        printf("\n");
    
        for (year = 1; year <= num_years; year++) {
            printf("%3d    ", year);
            for (i = 0; i < NUM_RATES; i++) {
                value[i] += (low_rate + i) / 100.0 *  value[i];
                printf("%7.2f", value[i]);
            }
            printf("\n");
        }
    
        return 0;
    }

  6. #6
    Registered User
    Join Date
    Dec 2016
    Posts
    45
    Quote Originally Posted by algorism View Post
    I don't know what you mean by your note "gets expected output here". Is that the expected output? Only the header line of the table? Why is that "expected"? It's not what I expected. And where is the rest of the code in the second listing? Is it there but you just don't show it, or did you remove that too?

    Anyway, the loop in question is doing two things at once.
    It's printing out the top row of the table (incorrectly spaced!).
    And it is also INITIALIZING the value array.
    Without initialization, the value array will contain arbitrary values.
    Thanks algorism. By the output, I mean that I get the same output for both fragments below when put with the declarations and directives at the top:

    Code:
            for (i = 0; i < NUM_RATES; i++) {    
        
            printf("%6d", low_rate + i);         /* Prints out the low rate + i   according to the loop above */
                                                        
            value[i] = INITIAL_BALANCE;
        }

    Same output as the following without the statement: value[i] = INITIAL_BALANCE;

    Code:
            for (i = 0; i < NUM_RATES; i++) {    
        
            printf("%6d", low_rate + i);         /* Prints out the low rate + i   according to the loop above */
                                                        
        }
    The output for both is displayed as: Stumped on role of a particular statement in a program with Arrays &amp; Nested For Loops-output2-jpg


    But as you both explained, that statement in question is for the use of the other two loops that come later

  7. #7
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by potomac View Post
    By the output, I mean that I get the same output for both fragments below
    So only printing out the table header is "expected" by you? I can't see how that could happen with the code in my post above, for instance. Try copying/pasting/running it. It will print the table body with or without the line in question.

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I think I can explain the formula some more.

    The formula for compound interest is: P(1 + r/n)(nt)
    where
    P = principle, a.k.a initial investment
    r = rate as a percent (so 5/100.0 for 5%)
    n = number of times compounded per term
    t = number of terms.

    The code in question makes a number of important simplifications. One is that since t=1 you can essentially ignore it. Another is how the exponent is handled.
    Code:
    value[i] += (low_rate + i) / 100.0 *  value[i];
    The whole left side of the equation is just interest - rate times value - so if you earned $6 in a year that's what the interest is supposed to be, so you have to add this interest to the principle, which is also supposed to be different from the $100 you started with.

    What I don't get is how this results in compound interest. It looks like the calculation relies on the current value of `value[i]` while it tries to assign to `value[i]`.

    There are ways to write this calculation that definitely don't invoke undefined behavior.
    Last edited by whiteflags; 12-05-2016 at 11:03 AM.

  9. #9
    Registered User
    Join Date
    Dec 2016
    Posts
    45
    Thanks VERY MUCH algorism, matticus, whiteflags for the responses. They are helpful.

    I get the purpose of the array initializer now.

    Would it be reasonable to conclude that the author put the array initializer in the same loop as the interest rate labels for presentation purposes/to conserve space on the page? It seems he was trying to cram as much in as little space as possible.

    If this was production code, wouldn't it be better to put the array initializer and the interest rates in separate functions with For Loops?

    Or why not just initalize the array at the top by saying this at the top?

    float value[5] = { 100 };

    I guess the effect of that would be less flexibility to modify the array since you lose the macro?

    That decision to conserve real estate space didn't seem logical to me at first, and that's partially where I lost my train of thought. Now I understand his motives
    Last edited by potomac; 12-07-2016 at 02:59 AM.

  10. #10
    Registered User
    Join Date
    Dec 2016
    Posts
    45
    Whoops, I meant to type:

    Code:
    float value[5] = { 100, 100, 100, 100, 100 };

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    My honest advice is to rework the code, make those changes, and see if it still works. I can't think of a reason why it wouldn't work. It simply wasn't written that way. Perhaps the original author realized it wasn't necessary?

    Either way, you're wrong about the macro not being useful here. It's fine.
    Code:
    float value[] = { INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE };

  12. #12
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Quote Originally Posted by potomac View Post
    Would it be reasonable to conclude that the author put the array initializer in the same loop as the interest rate labels for presentation purposes/to conserve space on the page?
    Sort of - it looks like the author was trying to reduce the number of loops by having all that work done in the first loop.

    Quote Originally Posted by potomac View Post
    If this was production code, wouldn't it be better to put the array initializer and the interest rates in separate functions with For Loops?
    There is nothing wrong with the current method, as in this case it's guaranteed that the number of array elements is the same as the number of column headers to print. In cases where quantities like this may differ, even if they happen to be the same at the time of writing, it is best to separate them (as a change to one later on would make those values different).

    There is no hard and fast rule for whether to separate the header prints and the array initialization as in this case. This is where you can see the subjectivity of code writing. The more important factor is that, whichever way it is done, the code is clear and easy to understand.

    Quote Originally Posted by potomac View Post
    Code:
    float value[5] = { 100, 100, 100, 100, 100 };
    As you said, this would lead to more maintenance work. Using named constants allows values to easily be changed without hunting down and modifying the actual code that uses those constants, which would have to be done if the array were initialized as shown.

    Also consider what you'd have to do to update the initializer list if you change the number of elements from 5 to 1000.

  13. #13
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Quote Originally Posted by whiteflags View Post
    My honest advice is to rework the code, make those changes, and see if it still works. I can't think of a reason why it wouldn't work. It simply wasn't written that way. Perhaps the original author realized it wasn't necessary?

    Either way, you're wrong about the macro not being useful here. It's fine.
    Code:
    float value[] = { INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE, INITIAL_BALANCE };
    I am assuming the OP was referring to the NUM_RATES macro, not INITIAL_BALANCE.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 01-07-2015, 10:08 AM
  2. c program printing out garbage (arrays and for loops)
    By starbucks10v3r in forum C Programming
    Replies: 27
    Last Post: 11-20-2013, 01:23 AM
  3. Replies: 10
    Last Post: 12-09-2012, 08:17 AM
  4. Replies: 5
    Last Post: 07-09-2012, 08:18 AM
  5. Replies: 4
    Last Post: 02-19-2012, 09:11 PM

Tags for this Thread