Author Topic: New thread especially for students of C and C++  (Read 94917 times)

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
New thread especially for students of C and C++
« on: November 19, 2008, 12:19:49 AM »
Update:   please see this next link:




For now ... Please consider this site as just a kind of

Quote

scratch pad . . .


to collect demo programs and later organize them for an e-text aimed at University Students beginning C or C++   It may eventually parallel my HLA site, also at this forum.

Click here (for links to these e-texts):

BEGINNING COMPUTER PROGRAMMING (using C++ or C)

or here ...


This site may be for you, a natural continuation, via the HLA/Python introduction, to a quick advance in C/C++ programming. 

If you have worked through this HLA/Python site  ...


... and worked through many of the example programs there ...

then ... you should have a BIG JUMP START to coding in C or C++.


Shalom,

David

2008-11-18

For appropriate credits due ... please see the introduction (partly copied below) from this link ...

http://developers-heaven.net/forum/index.php/topic,46.0.html

Acknowledgements:

This course and text would not be possible without the very gifted insights, teaching experiences, and programming skills of Randall Hyde,

http://en.wikipedia.org/wiki/Randall_Hyde

the Author, Creator, and so far, the Sustainer of HLA. I also would like to acknowledge the tremendous encouragement given by my youngest son Matthew, who's recent Engineering need to know a little C++, and then Assembly ... provided the incentive for a little more then that, from dad, (which led to HLA and now this attempt to benefit beginning computer students in general.)  Also, I would like to thank my students at Scarborough Christian High School, who besides being very promising young ladies and gentlemen, provided exemplary feedback as we went along into some not yet fully charted territory.



Table of Contents:

Chapter 01: The Computer prints a message
Chapter 02: The Computer gets some input
Chapter 03: The Computer adds some numbers
Chapter 04: The Computer repeats a procedure
Chapter 05: The Basic Elements of computer programming … and low level example(s)
Chapter 06: The Computer rolls the dice … a first simulation
Chapter 07: First Memory Flow Lab
Chapter 08: Memory Flow Lab2
Chapter 09: Memory Flow Lab3
Chapter 10: HLA (C/C++) Data Types
Chapter 11: The Computer does some Algebra with real numbers ... and Input Data Validation
Chapter 12: Pointers, Strings, your own Types, Records, Arrays, and dynamic things on the fly!
Chapter 13: The Computer files its Records
Chapter 14: The Computer reads its Files
Chapter 15: The Computer updates (edits, deletes, sorts, chops-duplicates-in) its Files
Chapter 16: The Computer … vast OS’s … and the garbage collects?  (Operating Systems ... what is DOS?)
Chapter 17: The Computer delivers daily Manna ... (gui Canadien ... eh?)
Chapter 18: OOP ... goes the computer?
Chapter 19: OOP 2
Chapter 20: Shaping OOP

Begin the e-text BEGINNING COMPUTER PROGRAMMING (with HLA) here ...

http://developers-heaven.net/forum/index.php?topic=2607.0
(Link updated 2013-05-24)
« Last Edit: September 06, 2018, 03:02:37 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #1 on: November 19, 2008, 01:59:21 AM »
NOTE: In the following programs, please be advised that you may still NEED to, or WANT to, revise/update them to handle the case of *** failure to allocate dynamic memory. ***

Here is some C code, and later, the same program in HLA.  You may thus easily see for yourself the many similarities in C and HIGH LEVEL HLA Assembly ;)

This program addresses a very common problem ... 'removing duplicates' in a data set.  One may not always care to pre-sort the data, so this 'remove' algorithm, (and probably using only a few recursive calls, to potentially vastly speed it up), zooms along your unsorted data and you soon end up with all your duplicates, each in neat groups, at the top of the data set.  

You may like to count and note the number of each unique duplicate and report that from this top-set 'side effect'.

Of course, if you want to use dynamic memory, and if you have MANY duplicates, you could re-size the memory allocated for this new and smaller data set of unique elements.  

One possible undesirable effect of this program, is that the first duplicate is replaced by the first 'top' element different to that search comparator. Thus ... some values at the top of the data set may appear near the front in the final data set of non-duplicates.


Here is the C version:


Code: [Select]
/*
    An efficient ...
    (and possibly slightly NEW METHOD - that uses recursive calls),
    of removing duplicates in an UNSORTED array of data ...
    
    by David W. Zavitz on 2008-11-16
    to contact, please see:
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include <stdio.h>

/*  
    Global variables used here for ease of testing purposes.
*/
int ARY[] = {0,0,1,5,8,8,9,1,1,2,3,4,3,2,2,2,7,9,9,3,3,3,4,4,4,6,2,2,1,1,0,0};
const int NUM = sizeof ARY / sizeof ARY[0];

/*
    'ARY' is the UNsorted array passed in, and ...
    'NUM' is the number of elements in that array.
    'unique' returns the index of the top non-duplicate element
    in the array after non duplicate elements moved down,
    and duplicates are now ... all at the 'top'.
*/
int unique(int array[], int n);
void swap(int array[], /* int start, */ int i, int *top);


int main()
{
    int i, topIndex;
    puts("\nArray BEFORE ...");
    for(i = 0; i < NUM; ++i)
            printf( "%d ", ARY[i] );
            
    topIndex = unique(ARY, NUM);
    printf
    (
        "\n\nArray AFTER 'unique(ARY, NUM)' called, "
        "returning 'topIndex' of %d ...\n",
        topIndex
    );
    for(i = 0; i <= topIndex; ++i)
            printf("%d ", ARY[i]);
    
    printf("\nThere were %d duplicates 'removed'.\n", NUM-1-topIndex);
    
    puts("\n\nArray AFTER ...");
    for(i = 0; i < NUM; ++i)
        printf("%d ", ARY[i]);
    printf
    (
        "\nshowing the NEW positions of all %d elements "
        "in the original array.", NUM
    );
    
    printf("\n\nPress 'Enter' key to continue ... ");      
    getchar();
    return 0;
}


void swap(int array[], /* int start, */ int i, int *top)
{
/*
    // for testing purposes ... (I also printed the 'start' index)
    printf
    (
        "\n\nInside swap, the start index is %d, "
        "the i index is %d, "
        "the top index is %d,\n"
        "the array is: ",
        start, i, *top
    );
    int j;
    for(j = 0; j < NUM; ++j)
        printf("%d ", ARY[j]);
*/
    if (i == *top) /* if at upper end of array, don't swap */
    {
        (*top)--;
        return;  
    }

    if(array[i] == array[*top]) /* recursive call since top element a duplicate */
    {
        (*top)--;
        swap(array, /* start, */ i, top);    
    }
    else /* swap values (at this 'i' and at this 'top') */
    {
        int temp = array[i];
        array[i] = array[*top];
        array[*top] = temp;
        (*top)--;
    }
}

int unique(int array[], int n)
{
    /* handle special cases: empty array, just one element */
    if (n <= 0) return -1;
    if (n == 1) return 0;
    
    int i;         /* i holds index of element being compared */
    int top = n-1; /* top holds running top index ...         */
    int start;     /* start holds running start index ...     */
    for(start=0; start<top; ++start)
    {
        for(i=start+1; i<=top; ++i) /* 'i' is index of element being compared */
        {
            if(array[start] == array[i]) /* if elements are different ... i++*/
                swap(array, /* start, */ i, &top);  
            /* else: get next i element to compare ... */
        }
    }
    return top;
}


Now see the similarities to HLA ...

and the extra control you have at your disposal to optimize the code, if desired. Note the 'similar feel' to C.

You may like to note the extra efficiency added by using  xchg(a, b); in the swaps ... And of course, you can use registers for all your counters ... There is no need, many times, to first copy a register to a variable, before you pass that value to a function.  Thus, you get a closer feel for all the steps involved ... with not that much more work than in C.

But to tell the truth, I first coded this in C ... and it took more than just a little while, to get it all debugged, and to feel that the logic and output matched, including making sure it correctly handled unusual values, like an array of just one element, or an array of all duplicates.

The translation process from C to HLA went fairly smoothly ... and was pretty straightforward.  But I was glad that I had on hand a seemly well tested/debugged C version ...

The algorithm did give me some difficulty in getting its seemly simple idea out of my head and into a C version. I gained confidence with much varied test data.  This helped confirm that the code would handle, as expected, all possible data sets.

Another thing I should mention, is that I used a GLOBAL array in HLA ... so that I didn't have to pass it to the procedures.  In C ... I can just use the pointer as the array inside my function... for example p[0] ...comparable to ary[0]  ... I may later, (now done - see the last program below, in this section), submit an HLA version that demonstrates an HLA pointer.


Code: [Select]
program removeDuplicates;
/*
    An efficient ...
    (and possibly slightly NEW METHOD - that uses recursive calls),
    of removing duplicates in an UNSORTED array of data ...
    
    by David W. Zavitz on 2008-11-17
    to contact, please see:
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include( "stdlib.hhf" )

?@nodisplay := true;
/*  
    Global variables used here for ease of testing purposes.

    'ARY' is the UNsorted array passed in, and ...
    'NUM' is the number of elements in that array.
    'unique' returns the number of non-duplicate elements
    in the array after non duplicate elements moved down,
    and duplicates are now ... all at the 'top'.
*/

static
ARY: int32[]:= [0,0,1,1,2,3,3,4,5,6,4,7,8,9,8,8,7,8,8,8,9,3,3,3,2,0,1,1,1,0,0,7];

// Array AFTER ... 0 7 1 2 3 9 8 4 5 6 4 8 8 8 8 8 9 3 3 3 3 2 1 1 1 1 7 7 0 0 0 0
// with duplicates all moved to the top end

// Array AFTER 'unique(ARY, NUM)' called, the returned 'topIndex' is 9
// 0 7 1 2 3 9 8 4 5 6
// There were 22 duplicates 'removed'.

const
NUM: int32:= @size(ARY) div @size(ARY[0]);

/* show 'thisNum' of int32's in array 'thisAry' */
#macro showAry( thisAry, thisNum );
    push( ecx );
    for( mov( 0, ecx ); ecx < thisNum; inc( ecx ) ) do
        stdout.puti32( thisAry[ecx*4] );
    endfor;
    pop( ecx );
#endmacro

/* uses Globals ARY, and NUM ... returns new 'top' value by reference */
procedure swap( start:int32;  i:int32; var top:int32);
begin swap;
    push( eax ); push( ebx ); push( ecx ); push( edx );

    /* dereference top ... get value into ebx */
    mov( top, ebx );
    mov( [ebx], ebx );

    /* for testing purposes ...I printed these:  'start' index, 'i' index, 'top' index */
    stdout.put
    (
        nl nl "Inside swap, the start index is ", start,
        ", the i index is ", i,
        ", the top index is ", (type int32 ebx), ",", nl
        "the array is: "
    );
    showAry( ARY, NUM );

    if (i == ebx) then /* if at upper end of array, don't swap */
        dec(ebx); /* top--; */  
     mov( top, edx );
mov( ebx, [edx] ); /* update top ... */
    else
mov( i, ecx );
mov( ARY[ecx*4], edx );
if( edx == ARY[ebx*4]) then          /* recursive call since top element is a duplicate */
       dec(ebx); /* top--; */
       mov( top, edx );
       mov( ebx, [edx] ); /* update top ... */
       swap( start, i, top);    
else        /* swap values (at this 'i' and at this 'top') */
    mov( ARY[ecx*4], eax );
       xchg( eax, ARY[ebx*4 ]);
       mov( eax, ARY[ecx*4]);
       dec(ebx); /* top--; */
     mov( top, edx );
mov( ebx, [edx] );        /* update top ... */
endif;
    endif;

    pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end swap;

/* uses Global array 'ARY' ... number of elements 'passed in' via 'n' */
/* eax returns the number of the top index in the 'new' array  */
procedure unique(n:int32); @returns("eax");
var
    top: int32;
    //i: int32; /* ecx=i holds index of element being compared */
    //start: int32;
begin unique;
    push( ebx ); push( ecx );

    /* handle special cases first */
    if (n <= 0) then /* (1.) empty array */
     mov( -1, eax );
    elseif (n == 1) then        /* (2.) just one element */
     mov( 0, eax );
    else
   mov( n, eax ); /* using eax as a 'scratch-pad' register */
   dec( eax ); /* n = n-1; */
   mov( eax, top ); /* top holds running top index ... initial top = n-1; */
   
   /* eax holds running 'start' index ...     */
   for( mov( 0, eax); eax<top; inc( eax ) ) do
    mov( eax, ecx );
    /* i begins with value i=start+1, thus the following begin with ... inc(eax) */
       for( inc(ecx); ecx<=top; inc(ecx) ) do /* ecx = 'i' is index of element being compared */
           mov( ARY[eax*4], ebx ); /* ebx holds 'start' value */
           if( ebx == ARY[ecx*4] ) then /* if elements are different ... i++*/
            //mov( ecx, i );
            //mov( eax, start);
               swap( eax, ecx, top ); //swap(start, i, top)
           endif;
           /* else: get next i=ecx element to compare ... */
       endfor;
   endfor;
   mov( top, eax );
    endif;
    pop( ecx ); pop( ebx );
end unique;

static
    topIndex: int32;
    dupRemoved: int32;

begin removeDuplicates;

    stdout.puts( nl "Array BEFORE ...");
    showAry( ARY, NUM );
    
    //unique(NUM); // returns eax // uses Global array ARY //    
    mov( unique(NUM), topIndex );
    stdout.put
    (
        nl nl "Array AFTER 'unique(ARY, NUM)' called, "
        "the returned 'topIndex' is ", topIndex, nl
    );
    inc( topIndex ); // set to equal instead, the number of elements
    showAry( ARY, topIndex );
    
    mov( NUM, eax );
    sub( topIndex, eax ); // 'topIndex' now holds the number of non-duplicate elements
    mov( eax, dupRemoved ); //dupRemoved = NUM - number_of_non-duplicate_elements
    stdout.put(nl "There were ", dupRemoved, " duplicates 'removed'." nl);
    
    stdout.puts(nl nl "Array AFTER ...");
showAry( ARY, NUM );
    stdout.put
    (
        nl "showing the NEW positions of all ", NUM,
        " elements in the original array."
    );    

end removeDuplicates;


Now here is that HLA version that passes the array by using a pointer ...


Code: [Select]
program removeDuplicates2; // pointer version
/*
    An efficient ...
    (and possibly slightly NEW METHOD - that uses recursive calls),
    of removing duplicates in an UNSORTED array of data ...
    
    by David W. Zavitz on 2009-01-03
    to contact, please see:
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include( "stdlib.hhf" )

?@nodisplay := true;

type
pAry: pointer to int32;

static
ARY: int32[]:= [0,0,1,1,2,3,3,4,5,6,4,7,8,9,8,8,7,8,8,8,9,3,3,3,2,0,1,1,1,0,0,7];

// Array AFTER ... 0 7 1 2 3 9 8 4 5 6 4 8 8 8 8 8 9 3 3 3 3 2 1 1 1 1 7 7 0 0 0 0
// with duplicates all moved to the top end

// Array AFTER 'unique(ARY, NUM)' called, the returned 'topIndex' is 9
// 0 7 1 2 3 9 8 4 5 6
// There were 22 duplicates 'removed'.

const
NUM: int32:= @size(ARY) div @size(ARY[0]);

/* show 'thisNum' of int32's in array 'thisAry' */
#macro showAry( pToArray, thisNum );
    push( ebx ); push( ecx );
    mov( pToArray, ebx ); /* get base address of array into ebx */
    for( mov( 0, ecx ); ecx < thisNum; inc( ecx ) ) do
        stdout.puti32( [ebx+ecx*4] );
    endfor;
    pop( ecx ); pop( ebx );
#endmacro

/* uses Globals ARY, and NUM ... returns new 'top' value by reference */
procedure swap( a:pAry; start:int32;  i:int32; var top:int32);
begin swap;
    push( eax ); push( ebx ); push( ecx ); push( edx ); push( edi );

    /* dereference top ... get value into ebx */
    mov( top, ebx );
    mov( [ebx], ebx );

    /* for testing purposes ...I printed these:  'start' index, 'i' index, 'top' index */
    stdout.put
    (
        nl nl "Inside swap, the start index is ", start,
        ", the i index is ", i,
        ", the top index is ", (type int32 ebx), ",", nl
        "the array is: "
    );
    showAry( a, NUM );

    if (i == ebx) then /* if at upper end of array, don't swap */
        dec(ebx); /* top--; */  
     mov( top, edx );
mov( ebx, [edx] ); /* update top ... */
    else
mov( i, ecx );
mov( a, edi ); /* get address in pointer to array into edi */
mov( [edi+ecx*4], edx );
if( edx == [edi+ebx*4]) then          /* recursive call since top element is a duplicate */
       dec(ebx); /* top--; */
       mov( top, edx );
       mov( ebx, [edx] ); /* update top ... */
       swap( a, start, i, top);    
else        /* swap values (at this 'i' and at this 'top') */
    mov( [edi+ecx*4], eax );
       xchg( eax, [edi+ebx*4 ]);
       mov( eax, [edi+ecx*4]);
       dec(ebx); /* top--; */
     mov( top, edx );
mov( ebx, [edx] );        /* update top ... */
endif;
    endif;

    pop( edi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end swap;

/* number of elements 'passed in' via 'n' */
/* eax returns the number of the top index in the 'new' array  */
procedure unique(a:pAry; n:int32); @returns("eax");
var
    top: int32;
    //i: int32; /* ecx=i holds index of element being compared */
    //start: int32;
begin unique;
    push( ebx ); push( ecx ); push( edx );
    
    mov( a, edx ); /* get base address of array into edx */

    /* handle special cases first */
    if (n <= 0) then /* (1.) empty array */
     mov( -1, eax );
    elseif (n == 1) then        /* (2.) just one element */
     mov( 0, eax );
    else
   mov( n, eax ); /* using eax as a 'scratch-pad' register */
   dec( eax ); /* n = n-1; */
   mov( eax, top ); /* top holds running top index ... initial top = n-1; */
   
   /* eax holds running 'start' index ...     */
   for( mov( 0, eax); eax<top; inc( eax ) ) do
    mov( eax, ecx );
    /* i begins with value i=start+1, thus the following begin with ... inc(eax) */
       for( inc(ecx); ecx<=top; inc(ecx) ) do /* ecx = 'i' is index of element being compared */
           mov( [edx+eax*4], ebx ); /* ebx holds 'start' value */
           if( ebx == [edx+ecx*4] ) then /* if elements are different ... i++*/
            //mov( ecx, i );
            //mov( eax, start);
               swap( a, eax, ecx, top ); //swap(arrayAddress, start, i, top)
           endif;
           /* else: get next i=ecx element to compare ... */
       endfor;
   endfor;
   mov( top, eax );
    endif;
    pop( edx ); pop( ecx ); pop( ebx );
end unique;

static
    topIndex: int32;
    dupRemoved: int32;

begin removeDuplicates2;

    stdout.puts( nl "Array BEFORE ...");
    showAry( &ARY, NUM );
    
    unique(&ARY, NUM); // returns eax    
    mov( eax, topIndex );
    stdout.put
    (
        nl nl "Array AFTER 'unique(&ARY, NUM)' called, "
        "the returned 'topIndex' is ", topIndex, nl
    );
    inc( topIndex ); // set to equal instead, the number of elements
    showAry( &ARY, topIndex );
    
    mov( NUM, eax );
    sub( topIndex, eax ); // 'topIndex' now holds the number of non-duplicate elements
    mov( eax, dupRemoved ); //dupRemoved = NUM - number_of_non-duplicate_elements
    stdout.put(nl "There were ", dupRemoved, " duplicates 'removed'." nl);
    
    stdout.puts(nl nl "Array AFTER ...");
showAry( &ARY, NUM );
    stdout.put
    (
        nl "showing the NEW positions of all ", NUM,
        " elements in the original array."
    );    

end removeDuplicates2;

« Last Edit: March 13, 2010, 05:43:54 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #2 on: November 19, 2008, 03:15:34 AM »
The previous program(s) used pointer or reference variables.

In HLA, 'val' indicates that the address was taken in the function header line.  This address must be de-referenced inside the procedure to get the value pointed at.  In C we also need to de-reference the address passed in via the pointer variable.

Thus ... it may be timely to back up some ... and to review several simple pointer basics?

The tricky part about C is often getting and using 'pointers' ...  :-\

You may have encountered already many conflicting points of view to point you on your way.

But in C ...a  pointer is simply a variable that holds the address of another variable (or fixed object).

So when first passing a pointer a value, you give it some 'valid address' of an other variable (or object) in memory. This is a way to reference a variable ... You make reference to it ... NOT NOW by it's name ... but by its pointer, i.e. its address, (held in the pointer variable.) So the pointer ... refers us back, (points us back), to the address of the original variable (or object).

To get at the value in the original variable, using a pointer, you must de-reference the pointer like this:

... if p is the pointer then *p is the value at that address pointed to ...

char tmp = 'A';
char *p = &tmp; /* char *p; p = &tmp; */
printf("\n %c is the same as %c \n", tmp, *p );


Now the often confusing part is that the pointer variable itself is a variable and has its own address in memory. So you can have a pointer to that address also ... thus ...a pointer to a pointer variable ... (Or 2 levels of indirection.)  8)



Ok ... let's take a simple example:


Code: [Select]
/* pointers 102 in C */

#include <stdio.h>
#include <ctype.h>

/* name is declared as a variable to hold an address of a char */
void show( char * name )
{
    /* get a copy of value in name into p  (name is a local pointer variable) */
    
    char *p = name;  /* p is declared as a variable to hold an address of a char */
    
    /* will NOT accept const char strings like myName2 */        /* <---<<< */
    while( *p != 0 ) { *p = toupper(*p); p++; }
    
    printf( "%s", name );
}

/*
    In this example of a C string,
    this also works ...
*/

/* name is declared as a variable to hold an address of a char */
void show2( char name[] )
{
    /* recall: "%s" takes an address to a NULL terminated array of char */
    printf( "%s", name );
}

int main()
{
    char myName1[] = "David W.";
    
    /* a const char C 'string' */
    char * myName2 =  "Zavitz";  /* myName2 is declared a pointer */
    
    /* Take the address at memory labeled myName1 with char offset 0 */
    //char * pMyName = &myName1[0];
    
    /*  or could use the below ... since ...*/
    
    char * pMyName = myName1;   /* recall myName1 is already an address */
    
    show( myName1 );
    printf( "... and again is " );
    show( pMyName );
    
    printf( "\n... and again is " );
    show2( myName1 );
    printf( "... and again is " );
    show2( pMyName );
    
    
    printf("\n\nOr ...\n\n");
    
    
    show( myName1 );
    printf( "... and again is " );
    /* show( myName2 ); */                                      /* <---<<< */
    
    printf( "\n... and again is " );
    show2( myName1 );
    printf( "... and again is " );
    show2( myName2 );  
    
    getchar();
    return 0;
}
« Last Edit: January 16, 2010, 05:52:39 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #3 on: November 19, 2008, 03:51:27 AM »
Changing the pace some ... and with a little play on words in an attempt to add some light hearted humour to this sobering subject of dates ... and perhaps, just how late the date is ...   :-X

re. how late the date is, please see:

http://sites.google.com/site/andeveryeyeshallseehim/

The following features the basic record keeping structure, a struct, common to both C and C++. Struct's have a little more relaxed useage in C++.  You could instead use a class with public data in C++.  In HLA we have type record and type class, somewhat comparable to C++.


Here is an HLA example of the header for Vector class ...


Code: [Select]
type
Vector:
class
var
x: real32;
y: real32;
procedure create;
procedure get_x; @returns( "st0" );
procedure get_y; @returns( "st0" );
method set_x( r:real32 );
method set_y( r:real32 );
procedure takeIn;
procedure display;
procedure findLength; @returns( "st0" );
procedure findAngle; @returns( "st0" );
endclass;


Or just a record ...


Code: [Select]
type
Vector:
record
x: real32;
y: real32;
endrecord;


Compare this with a fancied up record, a struct, in C


Code: [Select]
typedef struct Date 
{
   int  mm,
        dd,
        yy;
}Date;


The following C 'date' program uses lots of pointers and introduces the C/C++ notation for a pointer pointing to a record element ...

If d is a pointer to date, then d->yy is the year field content value.

You might like to scan this 'tongue in cheek' student guide to dating ... using C   :-*

Good 'dating' does require a few advanced techniques ...

but with a little patience and perseverance ...

and careful attention to details,

you will progress and have good success


Code: [Select]
/*
    Dates ... with C
   
    Some (a little and/or not so) novel 'dating' pointers ... for C students.
   
    To strengthen your foundations in programming,
    or to contact the author, please look here ...
   
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

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

typedef struct Date /* the main attraction */
{
   int  mm,
        dd,
        yy;
}Date;

/* 11 very forward declarations ...*/

Date * getNewDate();
Date * newCopy( Date *d );
void show( Date *d );
void advance( Date *d );
int isValid( Date *d );
int isLeapYear( int year );
int isLess( Date *d1, Date *d2 );
int isEqual( Date *d1, Date *d2 );
int exceedsDaysInMonth( Date *d );
int difference( Date d1, Date d2 );
int more();

/* Note well the progression above, but the main object is ... 'to get a Date'. */


int main() /* to test out all the 'dating tips' introduced above */
{
    Date *pd;
    Date *pd2;
    int i, n;
    do
    {
        pd = getNewDate();
        printf("You entered the Date : "); show( pd );
        advance( pd );
        printf("\nTomorrow's Date is   : "); show( pd );
       
        for(i=1; i<=6; ++i) advance( pd );
        printf("\nOne weeks Date is    : "); show( pd );
       
        for(i=1; i<=21; ++i) advance( pd );
        printf("\nFour weeks Date is   : "); show( pd );
       
        for(i=1; i<=365-28; ++i) advance( pd );
        printf("\n365 days Date is     : "); show( pd );
       
        printf("\n\nEnter a 'base' Date to count from ...");
        free( pd );
       
        pd = getNewDate();
        pd2 = newCopy( pd ); /*  make a 'new' backup copy ... */
        printf("You chose the Date   : "); show( pd );
       
        printf("\nEnter the number of days to advance : ");
        scanf("%d", &n);
        while(getchar() != '\n'); /* 'flush' stdin ... */
        for(i=1; i<=n; ++i) advance( pd );
        printf("%d days into the future is : ", n); show( pd );
       
        if( isLess( pd, pd2 ) ) printf("\nisLess( pd, pd2 ) is true.\n");
        else printf("\nisLess( pd, pd2 ) is false.\n");
       
        printf("\n\nDouble ckecking days between ...\n");
        show( pd ); printf( " and " );  show( pd2 );
        n =  difference( *pd, *pd2 );
        printf("\nDays between equals  : %d", n);
        printf("\nAs 'inclusive' days  : %d", 1+n);
     
        printf("\n\nDouble ckecking days between ...\n");
        show( pd2 ); printf( " and " );  show( pd );
        n =  difference( *pd2, *pd );
        printf("\nDays between equals  : %d", n);
        printf("\nAs 'inclusive' days  : %d", 1+n);
       
        free( pd2 );
        free( pd );
           
    }while( more() );
       
    return 0;
}


/* 11 not so secret Date function definition tips ...*/


int isLeapYear( int year )
{
    if(year%4 != 0) return 0;  /* not a leap year */
    if(year%100 == 0 && year%400 != 0) return 0; /* not a leap year */
    return 1;
}

int exceedsDaysInMonth( Date *d )
{
    int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
   
    if( !isLeapYear( d->yy ) )
    {
        if ( d->mm > 12 || d->dd > days[d->mm] ) return 1;   
       
        return 0;
    }
    else /* is leap year ... so need to handle case of month == Feb */
    {
        if ( d->mm == 2 && d->dd == 29 ) /* <-- the 'tricky' condition to get right */
            return 0;  /* NOTE: returns FALSE here since Date IS VALID */
        if ( d->mm > 12 || d->dd > days[d->mm] )
            return 1;
           
        return 0;
    }
}

void advance( Date *d )
{
    d->dd++;                       /* first increment the day */
    if( exceedsDaysInMonth( d ) )  /* if it crosses over to the next month */
    {
        d->dd = 1;                  /* the day becomes the first of next month */
        d->mm++;                    /* increment month in that case */
        if(d->mm > 12)              /* if it crosses over to the next year */
        {
            d->mm = 1;              /* the month becomes the first month */
            d->yy++;                /* of the next year */
        }
    }
}


int isValid( Date *d )
{
    /* if month not in 1..12 invalid ... */
    if( d->mm< 1 || d->mm > 12 ) return 0;
    if ( exceedsDaysInMonth( d ) ) return 0;
/*
    The following bit of text was copied from an HLA program by Randy Hyde
   
    The following is questionable.
    Who knows what ranges we should check? 1600 is probably a good starting year
    since this was shortly after the advent of the Gregorian calendar.  The upper
    end should be reasonably small so as to catch ridiculous Dates, but large
    enough so that we don't suffer from the "Y2K Syndrome".  9999 is probably
    way too big (2200 would probably be a good number for now), but who knows
    what to use here?   
*/
    if (d->yy <1600 || d->yy>9999) return 0;
    return 1;
}

int isLess( Date *d1, Date *d2 )
{
    if( d1->yy < d2->yy ) return 1;
    if( d1->yy == d2->yy && d1->mm < d2->mm ) return 1;
   
    if(
        d1->yy == d2->yy
        && d1->mm == d2->mm
        && d1->dd < d2->dd
       )   
        return 1;
    /* if reach here ... */
    return 0;   
}

int isEqual( Date *d1, Date *d2 )
{
    if (
            d1->yy == d2->yy
            && d1->mm == d2->mm
            && d1->dd == d2->dd
        )
        return 1;
    /* if reach here ... */
    return 0;
}

Date * newCopy( Date *d )
{
    Date * tmp = (Date*) malloc( sizeof(Date) );
    tmp->dd = d->dd;
    tmp->mm = d->mm;
    tmp->yy = d->yy;
    return tmp;
}
   
int difference( Date d1, Date d2 )
{
    int diffDays = 0;
    if( isLess( &d1, &d2 ) )
    {
        while( !isEqual(&d1, &d2) )
        {
            diffDays++;
            advance( &d1 );   
        }
    }
    else
    {
        while( !isEqual(&d2, &d1) )
        {
            diffDays++;
            advance( &d2 );   
        }
    }
    return diffDays;
}

Date * getNewDate()
{   
    Date * d = (Date*) malloc( sizeof(Date) );
    printf("\nEnter a valid Date in the format yyyy/mm/dd : ");
    for(;;) /* loop forever ... until break */
    {
        scanf("%d",&d->yy);
        getchar(); /* to 'eat' the '/' char's ... */
        scanf("%d",&d->mm);
        getchar();
        scanf("%d",&d->dd);
        while(getchar() != '\n'); /* 'flush' stdin ... */

        if( isValid(d) ) break;

        /* if program reaches here ... */
        printf
        (
            "\nInvalid Date. "
            "Enter Date in range 1600/1/1..9999/12/31 : "
        );
    }
    return d;
}

void show( Date *d )
{   
    char * nameOfMonth[]=
    {
        "***", "January", "February", "March",  "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
    };
    printf("%s %d, %d", nameOfMonth[d->mm], d->dd, d->yy);
}

int more()
{
    printf("\n\nMore (y/n) ? ");
    char reply;
    scanf("%c", &reply);
    int dummy = (int)reply;
    while(dummy!='\n') dummy = getchar();
    return !(reply=='n' || reply =='N');
}


Below is a C++ Date class program, (much like the C date struct program listed above) ...


Code: [Select]
/*
    Finds the days inclusive between two valid dates
    Demo of ...  Validation for input Dates
*/

#include<iostream>
#include<string>

using namespace std;

class Date
{
public:
    Date() { month=1; day=1; year=1900; }   
    Date( int m, int d, int y ) { month = m; day = d; year = y; }           
   
    int GetMonth() { return month; }
    int GetDay() { return day; }
    int GetYear() { return year; }
    int difference( Date &date2 );

    void display_date();   
 
    bool is_equal( Date& );
    bool is_less_than( Date& );
    bool isValid();
   
private:
    int month;
    int day;
    int year;
   
    bool isLeapYear();
    void advance();
    string month2string();
    bool exceedsDaysInMonth();
};


int main()
{
    int m, d, y, days_apart;
    char slash; 
    cout << "This program gives the number of days between two dates.\n\n"
         << "Press Ctrl C to exit the loop ...\n\n";
         
    for(;;)
    {
        cin.sync();
        cout<<"Please enter 1st date in the form yyyy/mm/dd : ";
        cin>>y>>slash>>m>>slash>>d;
        if ( !cin.good() )
        {
            cin.clear();
            cout << "\nERROR! Bad date entered ... \n\n";
            continue;
        }
        Date First_Date(m, d, y);
        if ( First_Date.isValid() )
        { 
            cout<<"1st Date is  : ";
            First_Date.display_date();
        }
        else
        {
            cout << "\nERROR! Bad date entered ... \n\n";
            continue;
        }
        Date Second_Date;
        for(;;)
        {       
            cin.sync();
            cout<<"\nPlease enter 2nd date in the form yyyy/mm/dd : ";
            cin>>y>>slash>>m>>slash>>d;
            if ( !cin.good() )
            {
                cin.clear();
                cout << "\nERROR! Bad date entered ... \n\n";
                continue;
            }
            Date temp(m, d, y);
            if ( temp.isValid() )
            { 
                Second_Date = temp;
                cout<<"2nd Date is  : ";
                Second_Date.display_date();
                break; // out of inner loop
            }
            else
            {
                cout << "\nERROR! Bad date entered ... \n\n";
                continue;
            }
        }
       
        cout << endl << endl;
        if( First_Date.is_equal(Second_Date) )
        { 
            cout<<"The first date you entered is the same as the second date."<<endl;
            days_apart = First_Date.difference(Second_Date);
        }
        else if( First_Date.is_less_than(Second_Date) )
        {
            cout<<"The first date you entered is earlier than the second date."<<endl;
            days_apart = First_Date.difference(Second_Date); 
        }
       
        else // the date can only be equal or less than ...or ELSE it is greater
        {   
            cout<<"The first date you entered is later than the second date"<<endl;
            days_apart = Second_Date.difference(First_Date);
        }
       
        cout<<"The two dates are "<< days_apart<<" days apart.\n"
            <<".. or have " << days_apart+1 << " inclusive days between them.\n\n"
            << flush;
    }
}


int Date::difference( Date &date2 )
{
    int diff_days = 0;
    while ( !this->is_equal(date2) )
    {
        diff_days++;
        advance();   
    }
    return diff_days;
}

bool Date::exceedsDaysInMonth()
{
    int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
   
    if( !isLeapYear() )
    {
        if ( month > 12 || day > days[month]) return true;   
       
        return false;
    }
    else // is leap year ... so need to handle case of month == Feb
    {
        if ( month == 2 && day == 29 ) //<-- the 'tricky' condition to get right
            return false; 
        if ( month > 12 || day > days[month] )
            return true;
           
        return false;
    }
}

// convert numeric month into string
string Date::month2string() 
{
    char *months[] =
    {"***", "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
    if ( !exceedsDaysInMonth() )
    {
        if ( month >= 1 && month <= 12 )
            return months[month];
        else
            return "Unknown month";
    }
    else
        return "Unknown month";
}

bool Date::isLeapYear()
{
    if (year%4 != 0) return false;  // not a leap year
    if (year%100 == 0 && year%400 != 0) return false; // not a leap year
    return true;
}

void Date::advance()
{
    day++;                          //first increment the day
    if( exceedsDaysInMonth() )      //if it crosses over to the next month
    {
        day = 1;                    //the day becomes the first of next month
        month++;                    //increment month in that case
        if(month > 12)              //if it crosses over to the next year
        {
            month = 1;              //the month becomes the first month
            year++;                 //of the next year
        }
    }
}

void Date::display_date()
{   
    string name_of_month[]=
    {
        "***", "January", "February", "March",  "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
    };
    cout <<  name_of_month[month]  <<  " "  <<  day  <<  ", "  << year;
}
   
bool Date::is_equal( Date& Second_Date )
{
    if (
            month==Second_Date.month
            && day==Second_Date.day
            && year==Second_Date.year
        )
        return true;
    // if reach here ...
    return false;
}
   
bool Date::is_less_than( Date& Second_Date )
{   
    if( year < Second_Date.year) return true;
    if( year <= Second_Date.year && month < Second_Date.month ) return true;
    if(
        year <= Second_Date.year
        && month <= Second_Date.month 
        && day < Second_Date.day
       )   
        return true;
    // if reach here ...
    return false;   
}

bool Date::isValid()
{
    // if month not in 1..12 invalid ...
    if( month< 1 || month > 12 ) return false;
    if ( exceedsDaysInMonth() ) return false;
/*
    The following is questionable.
    Who knows what ranges we should check? 1600 is probably a good starting year
    since this was shortly after the advent of the Gregorian calendar.  The upper
    end should be reasonably small so as to catch ridiculous dates, but large
    enough so that we don't suffer from the "Y2K Syndrome".  9999 is probably
    way too big (2200 would probably be a good number for now), but who knows
    what to use here?   
*/
    if (year <1600 || year>9999) return false;
    return true;
}


/*
Quick question, is the year 2000 a leap year? A suprising number of people give
the wrong answer. The correct answer is "yes", that is 2000 is a leap year.
Why do so many folks give the wrong answer to this simple question? In general,
a year is a leap year if it is evenly divisible by 4.
Most people also remember the exception which is a year is not a leap year if
it ends in "00" (ie., the year is even divisable by 100). So years like 1972,
1980, and 1996 are leap years, but 1800 and 1900 are not.

So why then is a 2000 a leap year? What many folks do not realize is that the
100 year exception itself has an exception. Years that are evenly divisable by
400 are leap years. So 2000 as well as 2400 will be leap years.

Programmers who write date conversion code and don't know about the "exception
to the exception" will end up creating software which will display incorrect
dates starting Feb. 29th, 2000. The incorrect conversions software will instead
give Feb. 29th as March 1. Even worse, all subsequent dates will likely be off
by one day also.

Although the Leap Year 2000 bug is not technically the same as the Y2K bug, it
is many times lumped together Y2K bug because it occurs so close to Jan. 1, 2000.

Over the years, operating systems and development tools have shipped with the
"Leap Year 2000" bug in them. This means that applications that use these broken
operating systems or tools will also have the bug. However, over the last 5
years with the all of the talk of the Y2K bug, most of the problems have been
fixed.

*/


A simple approach to 'Dates' in C++ is given below ... that would not fit in this page.
« Last Edit: August 31, 2012, 05:44:51 AM by David »

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: New thread especially for students of C and C++
« Reply #4 on: November 19, 2008, 10:32:34 AM »
Thanks David for all your efforts.

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #5 on: November 29, 2008, 01:09:18 PM »
Here is a simple approach to dates ... coded in C++ (that wouldn't fit in the 'date' section above) ...

Code: [Select]
// Find number of days from 1900-01-01 ...

#include <iostream>
#include <iomanip>

using namespace std;

const int daysInYear[ ] = {0,31,59,90,120,151,181,212,243,273,304,334,365};

bool more()
{
    cout << "\nMore (y/n) ? " << flush;
    char reply;
    cin.clear();
    cin.sync();
    reply=cin.get();
    cin.sync();
    return !(reply=='n' || reply=='N');
}

long toHrs( long days )
{
    return days*24;    
}

long toMins( long days )
{
    return days*24*60;
}

long long toSecs( long days )
{
    return ((long long)days)*24*3600;
}


int main ()
{
    long yr, mo, da, years, days;
    char c;
    
    cout << "This program reads a date and finds\n"
         << "the number of inclusive days since 1900-01-01.\n"
         << "Results valid in date range 1900-01-01 to 2099-12-31.\n";
    do
    {
        cout << "\nEnter a valid 'test' date yyyy-mm-dd : ";
        cin >> yr >> c >> mo >> c >> da;
    
        // first find the whole years that have passed ...
        years = yr-1900;
        
        // convert this to days ...adding one day for each leap year that has passed
        // note 1900 was NOT a yeap year but 2000 WAS a leap year ... so ...
        days = years*365 + years/4;
        
        // now add on the days for the whole months that have passed ...
        days = days + daysInYear[ mo-1 ];
        
        // now add on the days in this month that have passed ...
        days = days + da;
        
        // if in a leap year & if before March, correct for the already added day
        if( yr%4==0 && mo<3 && yr!=1900 ) --days;
        
        cout << "The number of inclusive days from 1900-01-01 to "
             << yr << "-" << setfill('0') << setw(2) << mo << "-"
             << setw(2) << da << " is " << days << ".\n"
             << "Or at midnight, " << toHrs(days) << " hours or "
             << toMins(days) << " minutes or " << toSecs(days) << " seconds.\n";
    
    }while( more() );
}


And here is a common student date problem ... printout a calander for any month in a year from ...? to ...?

Coded here in C ...

Code: [Select]
/*
    Print a calendar from 1600 to 9999
    
    For calibration ref. see ...
    http://www.nr.com/julian.html
*/

#include <stdio.h>

#define HEADER "This program prompts the user to enter a month and a year\n" \
                "and generates a calendar for that period. For example ...\n" \
                "Enter month : 5\n" \
                "Enter year  : 2018\n\n" \
                "Su  M Tu  W Th  F Sa\n" \
                "       1  2  3  4  5\n" \
                " 6  7  8  9 10 11 12\n" \
                "13 14 15 16 17 18 19\n" \
                "20 21 22 23 24 25 26\n" \
                "27 28 29 30 31\n"

#define HEADER_CAL "Su  M Tu  W Th  F Sa"

/*
    This function asks the user to ...
    Enter month : 5
    Enter year  : 2018
    
    And returns, by reference, month and year entered
    Note: Allows only valid input ... month range 1..12, year range 1900..9999
*/
void enterMonthYear(int *month, int *year)
{
    int numGood;
    for( ;; ) /* loop forever ... until break */
    {
        printf("Enter month : ");
        if( (numGood=scanf("%d", month))!=1 || *month<1 || *month>12 )
        {
            while( getchar() != '\n' ) ; /* flush stdin */
            printf("Valid months are 1..12  ");
        }
        else
        {
            while( getchar() != '\n' ) ; /* flush stdin */
            break;
        }
    }

    for( ;; )
    {
        printf("Enter year  : ");
        if( (numGood=scanf("%d", year))!=1 || *year<1600 || *year>9999 )
        {
            while( getchar() != '\n' ) ; /* flush stdin */
            printf("Valid years are 1600..9999  ");
        }
        else
        {
            while( getchar() != '\n' ) ; /* flush stdin */
            break;
        }
    }
}

/* returns 1 if leap year, else returns 0 */
int isLeapYear( int year )
{
    if(year%4 != 0) return 0;  /* not a leap year */
    if(year%100 == 0 && year%400 != 0) return 0; /* not a leap year */
    return 1;
}

/* returns the number of days for a month in any year 1900..9999*/
int daysInMonth(int month, int year)
{
    int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    if( month==2 && isLeapYear(year) ) return days[month] +1;
    else return days[month];
}

/* returns day number for any day and month in any year 1600..9999 */
int getDayNum(int month, int day, int year)
{
    int dayNum = 0;
    int monthNum;
    for( monthNum=1; monthNum<month; ++monthNum)
        dayNum += daysInMonth(monthNum, year);
    dayNum += day;
    return dayNum;
}

/* returns the number of days from 1/1/1600 to the end of the previous 'year' */
long yearsToDays(int year)
{
    int numDays =0;
    int yearNum;
    for(yearNum=1600; yearNum<year; ++yearNum)
        numDays += 365 + isLeapYear(yearNum);
    return numDays;
}

/*
    Outputs the calendar to the screen ...
    'startDay' says which day of the week is the first of the month
    (0 is Sunday, 1 is Monday, etc...)
    'numDays' is how many days in the month
*/
void printCalendar(int startDay, int numDays)
{
    int i;
    puts(HEADER_CAL);
    
    for(i=0; i<startDay; ++i)
        printf("   ");

    for(i=1; i<= numDays; ++ i)
    {
        printf("%2d ", i );
        if( i< numDays && (i+startDay)%7 == 0 ) puts("");
    }
}

/* defaults to 'yes' */
int more()
{
    char c, reply;
    printf("\n\nMore (y/n) ? ");
    reply=c=getchar();
    while( c != '\n' ) c = getchar(); /* flush stdin */
    return !(reply=='n' || reply=='N');
}


int main()
{
    int month, year, startDay;
    puts( HEADER );
    
    do
    {
        enterMonthYear( &month, &year );
/*
        printf("\n%d %s a leap year.\n",
                year, isLeapYear(year) ? "is" : "is not");
        
        printf("\nDay 1 of the %d month of year %d is day number %d\n",
                month, year, getDayNum(month, 1, year) );
                
        printf("\nNumber of days from 1600/01/01 to the end of the year %d is %d\n",
                year-1, yearsToDays(year) );
*/
        /* 2305448 1600/01/01 was a Saturday; 2415021 1900/01/01 was a Monday */
        startDay = (5 + yearsToDays(year) + getDayNum(month, 1, year)) % 7;
/*
        printf("\nStart day for month %d and year %d is %d\n",
                month, year, startDay +1\ );
*/
        printf("\nYour calender for month %d and year %d is ...\n\n", month, year);
        printCalendar(startDay, daysInMonth(month, year));

    }while( more() );

    return 0;
}

You may also like to check this student help link for an example of todays local date and time in C/C++ :

http://www.dreamincode.net/forums/index.php?showtopic=64722&st=0&p=422833&#entry422833
« Last Edit: November 28, 2009, 06:59:20 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #6 on: November 29, 2008, 02:36:25 PM »
Back to pointers ... in C ...

Here is a mini-tutorial on arrays in C ...

Code: [Select]
/*
    I am trying to add the contents of this array after entering the values
    of the array ... but I am confused as to how to do this, please help me.
*/
#include <stdio.h>

#define SIZE 5

int main()
{
    float dAry[ SIZE ];
    float sumInput =0, sumAry =0;
    int i, j, numGood;
    printf( "Enter %d floating point numbers ...\n", SIZE );
    for( i=0;  i<SIZE; ++i )
    {
        printf( "dAry[%d] = ", i );
        numGood = scanf( "%f", &dAry[i] );
        if( numGood==1 ) sumInput += dAry[i];
        else
        {
            --i;
            puts("Bad data ... enter numbers only.");
        }
        while( getchar() != '\n' ) ; /* flush stdin ... */
    }

    for( j=0; j<i; ++j ) sumAry += dAry[j];
   
    printf( "sumInput=%f and sumAry=%f", sumInput, sumAry );

    printf("\nPrint 'Enter' to continue ... ");
    getchar();
    return 0;
}


NOTE in the following code that 'ary' and 'pAry' both point to arrays of type 'int' ... with this important difference:

sizeof(ary) will give the number of bytes allocated for the array of int's in memory ... In the example here of 5 int's and if each int uses 4 bytes ... then sizeof(ary) returns 20

but

sizeof(pAry) will return 4, if in a 32 bit addressing environment ... since all pointer variables, and pAry was declared as a pointer to an int, use 4 bytes to hold an address, in a 32 bit addressing system.

Code: [Select]
#include <stdio.h>
#include <stdlib.h>

void show( int a[], int size )
{
    printf("\n\nArray  syntax  ... ");
    int i;
    for(i=0; i<size; ++i) printf("%d ", a[i]);
}

/* alt. version of above ... using a pointer syntax ... */
void show2( int *a, int size )
{
    printf("\n\nPointer syntax ... ");
    int i;
    for(i=0; i<size; ++i) printf("%d ", *a++);
}



int main()
{
    /*
        create an array in (static) memory with intitial values
        ary[0]=1, ary[1]=2, ..., ary[4]=5 
    */
    int ary[] ={1,2,3,4,5};
    int len_ary = sizeof(ary)/sizeof(ary[0]);
    show( ary, len_ary);
    show2( ary, len_ary);
   
    /*
        Create an array in dynamic memory
        with initial int values pAry[0]..pAry[4] undefined ...
        Or using alt. syntax, these initial int values are undefined ...
        *pAry, *(pAry+1), *(pAry+2),  *(pAry+3), *(pAry+4)

        Allocate (dynamic) memory for 5 int's.
        If an int is 32 bits or 4 bytes ...
        5 int's will need 5*4 = 20 (bytes).
        This new memory is 'cast' as type
        'a pointer to int', the same type as pAry.
    */
    int *pAry = (int*) malloc(sizeof(int)*len_ary);
   
    /* give it some values ... */
    int i;
    for(i=0; i<len_ary; ++i) pAry[i] = (i+1)*(i+1);
     
    show(pAry, len_ary); 
    show2(pAry, len_ary);
       
    /* NOTE: ary and pAry both point to arrays of type int */
       
    printf("\n\nPress 'Enter' to continue ... ");
    getchar();
    return 0;
}


Now here is an example of a 2DArrays with dynamic memory.  Note that it uses 'a pointer to a pointer to an int'.

This example demos the addition of two matrices.

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct twoDArray
{
    int **p;
    int rows;
    int cols;
}matrix;

typedef matrix * pMatrix;

/*
   'createMatrix' returns a pointer to a C struct ...
   The 'struct' holds a 'pointer to a pointer to int' for the 2-D array ... 
   AND ALSO holds the number of rows and cols for the 2-D array.
*/
pMatrix createMatrix(int, int);
void showMatrix(pMatrix);
void freeMatrix(pMatrix);


int main()
{
    int r = 2, c = 4;
    int count = r*c*2;
    pMatrix pM1, pM2, pM3;

    pM1 = createMatrix(r, c);
    /* fill in some values ... */
    int i, j;
    for(i=0; i<pM1->rows; ++i)
        for(j=0; j<pM1->cols; ++j)
            pM1->p[ i ][ j ] = count--;

    pM2 = createMatrix(r, c);
    /* fill in some values ... */
    for(i=0; i<pM2->rows; ++i)
        for(j=0; j<pM2->cols; ++j)
            pM2->p[ i ][ j ] = count--;
           
    pM3 = createMatrix(r, c);
    /* sum first two matrices ...*/
    for(i=0; i<pM2->rows; ++i)
        for(j=0; j<pM2->cols; ++j)
            pM3->p[ i ][ j ] = pM2->p[ i ][ j ] + pM1->p[ i ][ j ];
   
    puts("");

    /* showTwoDArray( pAry ); */
    puts("  Matrix1");
    showMatrix(pM1);
    puts("\n+ Matrix2");
    showMatrix(pM2);
    puts("\n= Matrix3");
    showMatrix(pM3);
    puts("\nfree3");
    freeMatrix(pM3);   
    puts("\nfree2");
    freeMatrix(pM2);   
    puts("\nfree1");
    freeMatrix(pM1);   
    printf("\n\nPress 'Enter' to continue ... ");
    getchar();
    return 0;
}

pMatrix createMatrix(int numrows, int numcols)
{
     pMatrix pM = (pMatrix)malloc(sizeof(matrix));
     assert(pM);

     pM->p = (int**)malloc(sizeof(int*)*numrows);
     assert(pM->p);
     int i; // j;
     for(i=0; i<numrows; ++i)
     {
          pM->p[ i ] = (int*)malloc(sizeof(int)*numcols);       
          assert(pM->p[ i ]);
          //for( j = 0; j < numcols; ++j )
              //pM->p[i][j] = 0; /* initialize all to zero  */                 
     }
     pM->rows = numrows;
     pM->cols = numcols;
     return pM;
}

void showMatrix(pMatrix pM)
{
    int i, j;
    for(i=0; i < pM->rows; ++i)
    {
         for(j=0; j < pM->cols; ++j)
              printf("%4d ", pM->p[ i ][ j ]);           
         puts("");
    }       
}

void freeMatrix(pMatrix pM)
{
     int i;
     for(i = pM->rows-1; i >= 0 ; --i)
     {
          printf( "pM->p[%d] = %d . ", i, (int)pM->p[ i ] );
          free( pM->p[ i ] );
     }   
     
     printf( "pM->p = %d . ", (int)pM->p );             
     free( pM->p );

     printf( "pM = %d",  (int)pM );
     free( pM );   
}


This example demos the multiplication of two matrices.

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct twoDArray
{
    int **p;
    int rows;
    int cols;
}matrix;

typedef matrix * pMatrix;

/*
   'createMatrix' returns a pointer to a C struct ...
   The 'struct' holds a 'pointer to a pointer to int' for the 2-D array ... 
   AND ALSO holds the number of rows and cols for the 2-D array.
*/
pMatrix createMatrix(int, int);
void showMatrix(pMatrix);
void freeMatrix(pMatrix);


int main()
{
    int r = 2, c = 4;
    int count = r*c*2;
    pMatrix pM1, pM2, pM3;

    pM1 = createMatrix(r, c);
    /* fill in some values ... */
    int i, j, k;
    for(i=0; i<pM1->rows; ++i)
        for(j=0; j<pM1->cols; ++j)
            pM1->p[ i ][ j ] = count--;

    pM2 = createMatrix(c, r);
    /* fill in some values ... */
    for(i=0; i<pM2->rows; ++i)
        for(j=0; j<pM2->cols; ++j)
            pM2->p[ i ][ j ] = count--;
           
    pM3 = createMatrix(r, r);
    /* x first two matrices ...*/
    for(i=0; i<r; ++i)
        for(j=0; j<c; ++j)
            for(k=0; k<c; ++k)
                pM3->p[ i ][ j ] += pM1->p[ i ][ k ] * pM2->p[ k ][ j ];
   
    puts("");

    /* showTwoDArray( pAry ); */
    puts("  Matrix1");
    showMatrix(pM1);
    puts("\nx Matrix2");
    showMatrix(pM2);
    puts("\n= Matrix3");
    showMatrix(pM3);
    puts("\nfree3");
    freeMatrix(pM3);   
    puts("\nfree2");
    freeMatrix(pM2);   
    puts("\nfree1");
    freeMatrix(pM1);   
    printf("\n\nPress 'Enter' to continue ... ");
    getchar();
    return 0;
}


pMatrix createMatrix(int numrows, int numcols)
{
     pMatrix pM = (pMatrix)malloc(sizeof(matrix));
     assert(pM);

     pM->p = (int**)malloc(sizeof(int*)*numrows);
     assert(pM->p);
     int i, j;
     for(i=0; i<numrows; ++i)
     {
          pM->p[ i ] = (int*)malloc(sizeof(int)*numcols);       
          assert(pM->p[ i ]);
          for( j = 0; j < numcols; ++j )
              pM->p[i][j] = 0; /* initialize all to zero  */                 
     }
     pM->rows = numrows;
     pM->cols = numcols;
     return pM;
}

void showMatrix(pMatrix pM)
{
    int i, j;
    for(i=0; i < pM->rows; ++i)
    {
         for(j=0; j < pM->cols; ++j)
              printf("%4d ", pM->p[ i ][ j ]);           
         puts("");
    }       
}

void freeMatrix(pMatrix pM)
{
     int i;
     for(i = pM->rows-1; i >= 0 ; --i)
     {
          printf( "pM->p[%d] = %d . ", i, (int)pM->p[ i ] );
          free( pM->p[ i ] );
     }   
     
     printf( "pM->p = %d . ", (int)pM->p );             
     free( pM->p );

     printf( "pM = %d",  (int)pM );
     free( pM );   
}


Now here is a Jacobi Iteration Solution-Method for strictly diagonally dominant square matrices ... (to solve a system of linear equations.)

Code: [Select]
/* was int ,,, now 2014-02-16 ,,, char SHOW_ITERS = 0; */ /* defaults to NO ... */

/* see credits to original source below ... this version features all */
/* dynamic arrays ... some input data validation ... results checking ... and */
/* also 2 (major) errors, in the code found on 2009-03-24 on the web, were fixed */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/* globals ... */

#define HEADER "**********************************************************\n" \
               "             JACOBI ITERATION SOLUTION METHOD             \n" \
               "    (for strictly diagonally dominant square matrices)    \n" \
               "**********************************************************\n"
#define EPSILON 0.0000001
#define MAX_PRINT_ITERS 333

char SHOW_ITERS = 0; /* defaults to NO ... */

/* input matrix elements */
void getInput( int, double** mat );
/* check if diagonally dominant */
int checkIfDD( int, double** mat );
/* calculate and display answers */
void jacobiCalcDisplay( int, double** mat );

double dotProd( int num, double* v1, double* v2 );

void showXcheck( int num, double** mat, double* v1, double* v2 );

int checkFlags( int num, int flags[] );

/* free dynamic memory occupied by 2D square matrix */
void freeMat( int num, double** sqMat );

int more()/* defaults to yes ... */
{
    int reply ;
    printf("\nMore ... (y/n) ? ");
    reply = getchar();
    if( reply != '\n' )
        while( getchar() != '\n' ) ; /* flush stdin ... */
    putchar( '\n' );
    return !(reply=='n' || reply=='N');
}



int main()
{
    double **mat;
    int num;

    do
    {
        puts( HEADER );

        printf( "Show each iteration result 1=Yes, 0=No ? " );
        scanf("%c", &SHOW_ITERS);
        if( SHOW_ITERS != '\n' )
            while( getchar() != '\n' ) ; /* flush stdin ... */

        if( !(SHOW_ITERS=='1'||SHOW_ITERS=='y'||SHOW_ITERS=='Y') )
        {
            puts("Ok ... 'No' it is ...");
            SHOW_ITERS =0;
        }
        else puts("Ok ... 'Yes' show iterations ... (This may take some time.)");

        printf("\nTo solve a system of linear equations ...\n");
        printf("Enter the number of 'equations/unknowns' to find: ");
        num = 0;
        scanf("%d", &num); /* num of unknowns */
        while( getchar() != '\n' ) ; /* flush stdin ... */

        mat = NULL;
        if( num>0 && (mat = (double**) malloc(num*sizeof(double*))) )
        {
            getInput(num, mat);
            if( checkIfDD(num, mat) ) jacobiCalcDisplay(num,mat);
            else freeMat(num, mat);
        }
        else
        {
            puts("Invalid choice or memory available was exceeded ... Try again.");
            if( mat != NULL ) free( mat );
        }
    }while( more() );
    return 0;
}


void getInput( int numUnKnowns, double** mat )
{
    int i, j;

    printf
    (
        "\nEnter values for the specified row and column below ...\n"
        "(The last column is the value for the RHS of the equation.)\n"
    );
   
    for( i = 0 ; i < numUnKnowns ; i++ )
    {
        mat[i] = (double*) malloc( (numUnKnowns+1)*sizeof(double) );
        puts("");
        for( j = 0 ; j < numUnKnowns+1 ; j++ )
        {
            printf("matrix[%d][%d] : ", i, j);
            if( scanf("%lf", &mat[i][j]) != 1 )
            {
                --j;
                puts("Bad entry ... try again with a 'real' number.");
            }
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
    }

    printf("\nThe matrix entered:\n\n");
    for( i = 0 ; i < numUnKnowns ; i++ )
    {
        for( j = 0 ; j < numUnKnowns+1 ; j++ ) printf("%+9f ", mat[i][j]);
        puts("");
    }

    printf("\nPress 'Enter' to start iteration ... ");
    getchar();
}

/* Check if the matrix entered is strictly diagonally dominant */
int checkIfDD( int numUnKnowns, double** mat )
{
    int   m, n, dd = 0;
    double* chkdd;
    double* sumdd = (double*) malloc( numUnKnowns*sizeof(double) );
    chkdd = (double*) malloc( numUnKnowns*sizeof(double) );

    for( m = 0 ; m < numUnKnowns ; m++ )
    chkdd[m] = sumdd[m] = 0; /* all set to zero ... */

    printf("\nChecking if the matrix is (strictly) diagonally dominant...");

    for( m = 0 ; m < numUnKnowns ; m++ )
    {
        for( n = 0 ; n < numUnKnowns ; n++ )
            sumdd[m] += fabs(mat[m][n] );
        sumdd[m] -= fabs(mat[m][m]);
        chkdd[m] = fabs(mat[m][m]);

        if(chkdd[m] > sumdd[m])
        {
            printf("\n%f > %f",chkdd[m],sumdd[m]);
            dd++;
        }
        else printf("\n%f !> %f",chkdd[m],sumdd[m]);
    }

    if(dd == numUnKnowns)
    {
        printf
        (
            "\nYES ..."
            "\nThe matrix is (strictly) diagonally dominant."
            "\nPress 'Enter' to continue with 'Jacobi Iterative Method'...\n"
        );
        getchar();
    }
    else
    {
        printf
        (
            "\nNO ..."
            "\nThe matrix is NOT (strictly) diagonally dominant ... so STOP!"
            "\n(But ... consider exchanging rows in the matrix "
            "and then to try again.)"

            "\n\nPress 'Enter' to continue ... "
        );

        getchar();
        free( sumdd );
        free( chkdd );
        return 0; /* false */
    }

    free( sumdd );
    free( chkdd );
    return 1; /* true */
}

/* uses global SHOW_ITERS ... */
void jacobiCalcDisplay( int numUnKnowns, double** mat )
{
    int* flag;
    int i, j, counter = 0;
    double* res;
    double* var = (double*) malloc( numUnKnowns*sizeof(double) );
    res = (double*) malloc( numUnKnowns*sizeof(double) );
    flag = (int*) malloc( numUnKnowns*sizeof(int) );

    for(i = 0 ; i < numUnKnowns ; i++ )
    var[i] = res[i] = flag[i] = 0;
    printf("The initial value of each array element was set to zero ...\n\n");

    printf( "*********************\n");
    printf( "START CALCULATING ...\n");
    printf( "*********************\n");

    do
    {
        counter++;
        /* for each iteration keep a copy of the old results ... */
        for(i = 0 ; i < numUnKnowns ; i++ )
        {
            var[i] = res[i];
        }

        if( SHOW_ITERS ) printf("\nIteration number %d ...\n", counter);

        for(i = 0 ; i < numUnKnowns ; i++ ) /* calculation */
        {
            res[i] = mat[i][numUnKnowns];
            for(j = 0 ; j < numUnKnowns ; j++ )
                res[i] = res[i] - mat[i][j]*var[j] ;

            res[i] = res[i] + mat[i][i]*var[i] ;
            res[i] = res[i] / mat[i][i] ;
            if( SHOW_ITERS ) printf("%c = %f\n", 'a'+i, res[i]);
            if( fabs(res[i] - var[i]) < EPSILON ) /* stop condition */
            flag[i]++;

            if( counter==MAX_PRINT_ITERS) SHOW_ITERS = 0;
        }
       
    }while( !checkFlags( numUnKnowns, flag ) );

    printf( "\n********************************\n");
    printf( "The RESULTS of %d ITERATIONS ... \n", counter);
    printf( "********************************\n");

    /*  cross check ...*/

    for( i = 0 ; i < numUnKnowns ; i++)
        var[i] = dotProd( numUnKnowns, mat[i], res );

    showXcheck( numUnKnowns, mat, res, var );

    /* show sol'n vector (again) ... and free up all dynamic memory  */

    printf("\nSolution vector ...\n");
    for( i = 0 ; i < numUnKnowns ; i++)
    {
        printf("%c = %+f\n", 'a'+i, res[i]);
        free(mat[i]);
    }
    free( mat );
    free( flag );
    free( res );
    free( var );
}

int checkFlags( int num, int flags[] )
{
    int i;
    for( i=0; i<num; ++ i)
        if( flags[i] == 0 ) return 0;
    return 1;
}

double dotProd( int num, double* v1, double* v2 )
{
    int i;
    double sum =0;
    for( i=0; i<num; ++i ) sum += v1[i]*v2[i];
    return sum;
}

void showXcheck( int num, double** mat, double* v1, double* v2 )
{
    int i, j;
    puts("\nCross checking ... \nMatrix times sol'n vector ="
         " cal. vector vs. original RHS vector");
    for( i = 0 ; i < num ; i++)
{
        printf("|");
        for( j =0 ; j < num ; j++ )
            printf("%+9f ", mat[i][j] );
        printf("| |%+9f| |%+9f|vs|%+9f|\n", v1[i], v2[i], mat[i][num]);
    }
}


void freeMat( int num, double** sqMat )
{
    int i;
    for( i=num-1; i>=0; --i )
        free( sqMat[i] );
    free( sqMat );
}


/*
Title: Jacobi Iteration for a system of linear equations ...

Consider a 4 unknowns linear system

7a - 2b +  c + 2d =  3
2a + 8b + 3c +  d = -2
-a      + 5c + 2d =  5
     2b -  c + 4d =  4

In my program, when asked for number of unknown, just enter 4.

When asked for value enter, it should be like this referred to the above linear system:

_____________________________________________
                JACOBI ITERATION
         AUTOMATIC ITERATION CALCULATOR
                 PUBLIC VERSION
_____________________________________________
Current available unknown calculation is from 1 until 26.
Please enter the number of unknown: 4
Enter values for the specified row and column below,
Row 1, Column 1 : 7
Row 1, Column 2 : -2
Row 1, Column 3 : 1
Row 1, Column 4 : 2
Row 1, Column 5 : 3
Row 2, Column 1 : 2
Row 2, Column 2 : 8
Row 2, Column 3 : 3
Row 2, Column 4 : 1
Row 2, Column 5 : -2
Row 3, Column 1 : -1
Row 3, Column 2 : 0
Row 3, Column 3 : 5
Row 3, Column 4 : 2
Row 3, Column 5 : 5
Row 4, Column 1 : 0
Row 4, Column 2 : 2
Row 4, Column 3 : -1
Row 4, Column 4 : 4
Row 4, Column 5 : 4

Next is just calculation and result will print on screen.

by AlexTan
Segamat Baru 85000
Segamat, Johor
Malaysia
*/

You may also want to check here ...

http://www.dreamincode.net/forums/topic/64817-solving-linear-equations-using-iteration/
« Last Edit: February 17, 2014, 01:37:09 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #7 on: November 29, 2008, 08:13:31 PM »
C++ Student class ... a very common student problem ...

Update: moved to here ...

http://developers-heaven.net/forum/index.php/topic,2585.0.htm


A demo simpler class Student ...

Code: [Select]
// a very simple student class that also demos overloading the << operator
#include <iostream>

using namespace std;

class student

public:
    student(string n = "", string d = "") : name(n), department(d) {}
    string get_name() const { return name; }
    string get_department() const { return department; }
    void set_name(const string& n) { name = n; }
    void set_department(const string& d) { department = d; }
private:
    string name;
    string department;
};

ostream& operator << (ostream& os, const student& s )
{
    return os<<s.get_name()<<", "<<s.get_department();
}

int main()
{
  student s( "Billy Kid", "Zoology" );
  student t, w;
  t = s;
  w.set_name( "Bobby Stone" );
  w.set_department( "Geology" );
  t.set_department( w.get_department() );
    cout << s << endl << t << endl << w << endl;
   
  system("pause");
return 0;
}


And an Entry class ...

Code: [Select]
// using a vector to hold objects of class Entry
// a 'shell'... for a contact/address data base

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cctype>

using namespace std;

class Entry
{
    friend istream&operator>>(istream&, Entry&);
    friend ostream&operator<<(ostream&, Entry&);
   
public:
   
    // default constructor
    Entry() {}
   
    // constructors
    Entry(string N, string A1, string A2, string P)
    {
        Person=N; Add1=A1; Add2=A2; Phone=P;
    }
   
    void setPerson(string temp) {Person=temp;}
    void setAdd1(string temp) {Add1=temp;}
    void setAdd2(string temp) {Add2=temp;}
    void setPhone(string temp) {Phone=temp;}
   
    // accessors
    string getPerson() {return(Person);}
    string getAdd1() {return(Add1);}
    string getAdd2() {return(Add2);}
    string getPhone() {return(Phone);}
   
private:
    string Person, Add1, Add2, Phone;
};

// friend function to overload the >> operator for input
istream &operator>>(istream &input, Entry &e)
{
   string temp[5];
   for(int i=0; i<5; i++) getline(input, temp[i], '\n');
   Entry e_temp(temp[0],temp[1],temp[2],temp[3]);
   e=e_temp;
   return(input);
}

// friend function to overload the << operator for output
ostream&operator<<(ostream &output, Entry &e)
{
    output << e.Person<<endl
           << e.Add1<<endl
           << e.Add2<<endl
           << e.Phone<<endl;
    return(output);
}

// prototypes of functions used in 'main'
void appendBook(vector< Entry>&);           // add to book from keyboard ...
void printBook(vector< Entry >&);           // print the current book to screen
void readBook(const char[], vector< Entry >&);  // read book from file
void writeBook(const char[], vector< Entry >&); // write the current book to file

// Globals ...
const char line[] = "-----------------------------------";
const char fName[] = "MyBBook.dat";

int main()
{
    vector < Entry > Book;          // construct a new vector Book for 'entries'
    appendBook(Book);               // add to Book from keyboard ...
   
    cout << "\nHere is the 'book' you just entered ...\n";
    cout << line << endl;
    printBook(Book);                // show book on screen
    writeBook(fName, Book);         // write Book to file
    cout << "\nThe 'last' record is " << Book.size() << "\n\n";
    system("pause");
   
    vector< Entry > v;
    Book = v;                       // set to empty ...
    readBook(fName, Book);          // read Book from file
    cout << "\nHere is the 'book'  read  from file ...\n";
    cout << line << endl;
    printBook(Book);
    cout << "The 'last' record is " << Book.size() << "\n\n";
    system("pause");
}

// definitions of functions used in 'main'
string takeIn(string message)
{
    cout<<message<<": ";
    string inStr;
    getline(cin, inStr, '\n');
    return(inStr);
}

void appendBook(vector< Entry > &b)
{
    Entry e;
    do
    {
        e.setPerson(takeIn("Enter name            "));
        e.setAdd1  (takeIn("Enter address 1st line"));
        e.setAdd2  (takeIn("Enter address 2nd line"));
        e.setPhone (takeIn("Enter phone           "));
        b.push_back(e);
       
    }while( tolower(takeIn("More y/n ?            ")[0]) != 'n' );
}

void printBook(vector< Entry > &b)
{
    for(size_t i=0; i<b.size(); ++i) cout << b[i] << endl;
}

void writeBook(const char f[], vector< Entry > &b) // write the current book to file
{
    // 5 lines of data are written for each 'entry' (includes 5th blank line)
    ofstream OUTFILE( f );
    for(size_t i=0; i<b.size(); i++) OUTFILE << b[i] << endl;
    OUTFILE.close();
}

void readBook(const char f[], vector< Entry > &b)
{
    ifstream INFILE( f );
    Entry e;
    while(INFILE >> e) { b.push_back(e); }
    INFILE.close();
}
« Last Edit: July 30, 2011, 04:44:28 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #8 on: January 14, 2009, 03:06:53 PM »
A C way to handle student records using a linked list of C struct ... ("Student GRADES MANAGEMENT SYSTEM")

moved/updated ... now appears later here (near the end, at present ... click on the next link to jump to there right now:)

http://developers-heaven.net/forum/index.php/topic,106.msg273.html#msg273


« Last Edit: February 24, 2010, 02:46:16 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #9 on: January 14, 2009, 03:08:44 PM »
The following function definitions belong to the program above ...

Code update/moved as per notice on above page ...
« Last Edit: April 24, 2009, 12:30:15 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #10 on: January 14, 2009, 03:35:20 PM »
A similar program to the above coded in HLA ....

Code: [Select]
program studentList_test;

// A mini demo of student record keeping
// using an HLA 'list' type student record structure.
// Each new student is inserted in order of unique
// student ID number (an HLA int32).

#include( "stdlib.hhf" )

?@nodisplay:=true;
const
fName: string:="studentInfo.txt";
max: int32:= 3; // using a small number here to keep this demo simple

type
Student:
record
id: int32;
sname: string;
marks: int32[max];
next: pointer to Student;
endrecord;

pStudent: pointer to Student;

static
pHead: pStudent:= NULL;
pTail: pStudent:= NULL; // used by append( pS:pStudent );
fileFlag: boolean:= false;
cnt: int32:= 0;

const
header1: string:= "STUDENT GRADES MANAGEMENT SYSTEM" nl;
header2: string:= "1. (I)nitialize student record list in RAM" nl
                  "2. (A)dd i.e. insert in order, by ID, a NEW student record" nl
                  "3. view/(D)elete a student record" nl
                  "4. view/(E)dit a student record" nl
                  "5. (S)how all student records (as inserted BY ID)" nl
                  "6. show all student records sorted by (N)ame" nl
                  "7. (F)ile all student records presently in RAM" nl
                  "8. (R)ead all student records on file into RAM" nl
                  "9. e(X)it" nl;

// Return a pointer to the Student if ID found in list; else return NULL
procedure pID( n:int32 ); @returns("eax");
begin pID;
push( ecx );

mov( pHead, eax ); // get address of pHead into eax
mov( n, ecx ); // using ecx to hold ID number to check in 'n'
   
//while( eax != NULL ) do
while1:
cmp( eax, NULL );
je endwhile1;
cmp( (type Student[eax]).id, ecx );
je endit; // return address eax, since id number entered was already use

// else ... get next pointer to compare
mov( (type Student[eax]).next, eax );
//endwhile;
jmp while1;
endwhile1:
       
// If reach here ... then id number not in list so ...
mov( NULL, eax ); // return NULL;
   
 endit:
pop( ecx );
end pID;

// A function to compare two Student records to permit sorting by ID number ...
procedure studentCmp( pS1:pStudent; pS2:pStudent ); @returns("eax");
begin studentCmp;
push( ebx ); push( ecx );
mov( pS1, ebx );
mov( pS2, ecx );
mov( (type Student[ecx]).id, ecx );
if( (type Student[ebx]).id < ecx ) then
mov( 1, eax );
else
mov( 0, eax );
    endif;
pop( ecx ); pop( ebx );
end studentCmp;

// insert new Student in list with id's in proper order
procedure insert( pS:pStudent );
begin insert;
push( eax ); push( ebx ); push( ecx );
mov( pS, ebx );

mov( pHead, ecx ); // Get a working copy of pHead in ecx
    // Firstly, we handle the case where 'this' should be the first element.
if( pHead == NULL || studentCmp(pS, pHead) ) then
// So ... it now becomes the first element ...
// mov( pHead, ecx );
mov( ecx, (type Student[ebx]).next );  // old pHead becomes 2nd in list ...
mov( ebx, pHead); // pHead = pS; ... this pS becomes the head of the list
else // If here ... search the linked list for the right location ...
// mov( pHead, ecx ); // Get a working copy of pHead in ecx
// Start comparing with element AFTER 'ecx' ... i.e. the 'next in' ...
while( (type Student[ecx]).next != NULL && studentCmp((type Student[ecx]).next, pS) ) do
mov( (type Student[ecx]).next, ecx ); // Traverse the list ...
endwhile;

// Ok now to insert after 'working copy' by relinking the pointers (similar to above)
// ( Includes inserting at end position ... where (type Student[ecx]).next == NULL )
     
mov( (type Student[ecx]).next, eax );
mov( eax, (type Student[ebx]).next ); // Inserted 'pS' is linked to 'upstream element'
mov( ebx, (type Student[ecx]).next ); // Now 'ecx' is updated to link to the new 'pS' element
endif;

// Update global variables.
inc( cnt );
mov( true, fileFlag );
pop( ecx ); pop( ebx ); pop( eax );
end insert;


procedure get_i( message:string ); @returns( "eax" );
begin get_i;
forever
try
stdout.put( message, ": " );
stdin.flushInput();
stdin.geti32();
unprotected
break;
exception( ex.ValueOutOfRange )
stdout.puts( "Out of range ... " );
exception( ex.ConversionError );
stdout.puts( "Illegal numeric value ... "  );
anyexception
stdout.puts( "Illegal entry, integers only ... "  );
endtry;
endfor;
end get_i;


procedure addInsertNew; // ... and insert in the proper place in the list.
var
tmpStr: string;
good: boolean;
begin addInsertNew;
push( eax ); push( ebx ); push( ecx );

get_i( "Enter ID (0 to abort)" );
cmp( eax, 0 );
je endit;

mov( eax, ebx ); // get a copy of ID into ebx
if( pID(ebx) ) then // i.e. if pointer returned is NOT NULL, the id IS used
stdout.put( nl "ID ", (type int32 ebx), " is already taken.", nl );
jmp endit; // Exit right now ...
endif;
   
mov( mem.alloc(@size(Student)), ecx ); 
mov( ebx, (type Student[ecx]).id ); // pS->id = ID;
   
stdout.puts( "Enter Name (Last, First): " );
stdin.flushInput();
stdin.a_gets();
mov( eax, (type Student[ecx]).sname );

for( mov( 0, ebx ); ebx<max; inc( ebx ) ) do
push( ebx ); push( ecx ); // preserve across exception handling
mov( str.alloc( 32 ), tmpStr ); // get a tmp string to hold 'input prompt message'
inc( ebx ); // for 1,2,3... instead of 0,1,2....
str.put( tmpStr, "Enter mark ", (type int32 ebx):3 );
//dec( ebx ); // restore ebx to 0,1,2... // see pop( ebx ) ... below
get_i( tmpStr ); // returns int32 in eax
pop( ecx ); pop( ebx ); // preserved across exception handling
mov( eax, (type Student[ecx]).marks[ebx*4] ); // update marks with this mark
str.free( tmpStr );
endfor;
   
insert( ecx ); // Set up links to this node
   
 endit:
pop( ecx ); pop( ebx ); pop( eax );
end addInsertNew;


procedure view( pS:pStudent );
begin view;
push( eax ); push( ebx ); push( ecx );
mov( pS, ecx );
stdout.put
(
"ID number: ", (type Student[ecx]).id:-4, 
" Name: ", (type Student[ecx]).sname:-20, " Marks: "
);
for( mov( 0, eax ); eax < max; inc( eax ) ) do
mov( eax, ebx );
shl( 2, ebx ); // ebx*4
stdout.put( (type Student[ecx]).marks[ebx], " " );
  endfor;
  pop( ecx ); pop( ebx ); pop( eax );
end view;


procedure showAll;
begin showAll;
if( pHead == NULL ) then
stdout.puts( nl "No records in memory at present." nl );
else
push( ecx );
mov( pHead, ecx );
while( ecx != NULL ) do
view( ecx );
stdout.newln();
mov( (type Student[ecx]).next, ecx );
endwhile;
stdout.newln();
pop( ecx );
endif;
end showAll;


procedure del( pS:pStudent );
begin del;
push( eax ); push( ebx ); push( ecx ); push( edx );

/* Handle special case of 'first in list' */
mov( pS, ecx );
if( ecx == pHead ) then
mov( (type Student[ecx]).next, pHead );//phead = pS->next;
//str.free( (type Student[ecx]).sname ); //free( pS->first );
//mem.free( ecx );//free( pS );
jmp endit; //return;   
endif;
   
/* Else not first in list, so ... */
   
mov( pHead, ebx );/* set p to this initial value to start loop */
   
/* Now find the pointer to the previous record. */
while( ebx != pS ) do
mov( ebx, edx );/* pp holds previous pointer value ... */
mov( (type Student[ebx]).next, ebx );/* set to next pointer in link list chain */
endwhile;
   
/*
Now we have a pointer to the previous student record, so ...
we can now point that previous record to one past this pS record           
*/
mov( (type Student[ecx]).next, eax );
mov( eax, (type Student[edx]).next );
   
/* Now free the memory for this record and update the globals ... */
 endit:
str.free( (type Student[ecx]).sname );
mem.free( ecx );
 
dec( cnt );
if( cnt>0 ) then
mov( true, fileFlag );
else
mov( false, fileFlag );
endif;
   
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end del;


procedure viewDel;
begin viewDel;
push( eax ); push( ebx ); push( ecx );

get_i( "Enter the id number to View/Delete" );
mov( eax, ebx ); // ID in ebx
   
mov( pID( ebx ), ecx ); /* See if pointer exists; i.e. get value or NULL */

if( cl ) then /* i.e. if pointer returned above was not NULL ... */
view( ecx );
stdout.puts( nl "Delete (y/n) ? ");
stdin.flushInput();
stdin.getc();
if( al=='y' || al=='Y' ) then
del( ecx );
endif;
else
stdout.put( nl, "Student with ID number ", (type int32 ebx), " not found.", nl );
endif;
pop( ecx ); pop( ebx ); pop( eax );
end viewDel;


procedure delAll;
begin delAll;
push( ebx ); push( ecx );

mov( pHead, ecx );
while( ecx != NULL ) do
mov( (type Student[ecx]).next, ebx ); // Get a pointer to the next record.
str.free( (type Student[ecx]).sname );
mem.free( ecx );
mov( ebx, ecx ); // Update ecx ...
endwhile;
   
// Update globals ...
mov( NULL, pHead );
mov( 0, cnt );
mov( false, fileFlag );

pop( ecx ); pop( ebx );
end delAll;

/* Note: calling delAll() here ... will re-set globals as above ... */
procedure init;
begin init;
push( eax );

if( pHead != NULL ) then
stdout.puts( nl "Do you wish to overwrite the records in memory y/n ? " );
stdin.flushInput();
stdin.getc();
if( al=='y' || al=='Y' ) then
delAll(); /* re-sets globals ... */
else
if( cnt==1 ) then stdout.puts( "1 student record was left intact in memory." );
else stdout.put( cnt, " student records were left intact in memory.", nl );
endif;
endif;
else
stdout.puts( nl "There were no records in memory to clear." nl );
endif;
   
pop( eax );
end init;


procedure viewEdit;
begin viewEdit;
push( eax ); push( ebx ); push( ecx );

get_i( "Enter the id number to View/Edit" );
mov( eax, ebx ); // ID in ebx
   
mov( pID( ebx ), ecx ); /* See if pointer exists; i.e. get value or NULL */

if( ecx ) then /* i.e. if pointer returned above was not NULL ... */
view( ecx );
stdout.puts( nl "Edit (y/n) ? ");
stdin.flushInput();
stdin.getc();
if( al=='y' || al=='Y' ) then
del( ecx );
mov( true, fileFlag );
addInsertNew();
endif;
else
stdout.put( nl, "Student with ID number ", (type int32 ebx), " not found.", nl );
endif;
   
pop( ecx ); pop( ebx ); pop( eax );
end viewEdit;


procedure writeFile; @returns( "eax" );
var
fp: dword;
begin writeFile;
push( ebx ); push( ecx ); push( edx );
 
mov( pHead, ecx );
if( ecx==NULL ) then
stdout.puts( nl "No records available ... so NO records written to file." nl );
mov( 0, eax );
jmp endit;
endif;

fileio.openNew( fName );
mov( eax, fp );

mov( 0, eax ); /* to count the records actually written to the file */
while( ecx!=NULL ) do
fileio.put
(
fp,
(type Student[ecx]).id, nl,
(type Student[ecx]).sname, nl
);
for( mov( 0, edx ); edx < max; inc( edx ) ) do
mov( edx, ebx );
shl( 2, ebx ); // ebx*4
fileio.put( fp, (type Student[ecx]).marks[ebx], nl );
  endfor;
       
mov( (type Student[ecx]).next, ecx );
inc( eax );
endwhile;
fileio.close( fp );
mov( false, fileFlag );
   
 endit:
pop( edx ); pop( ecx ); pop( ebx );
end writeFile;

// uses globals pHead and pTail ...
procedure append( pS:pStudent );
begin append;
push( ebx ); push( ecx );

mov( pS, ecx );
if( pHead != NULL ) then
mov( pTail, ebx ); // get tail address into ebx
mov( ecx, (type Student[ebx]).next ); // point old tail to next
mov( NULL, (type Student[ecx]).next ); // point new tail next to NULL
mov( ecx, pTail ); // update address for tail
else // is first record ... so
mov( ecx, pHead ); // get new address for pHead
mov( NULL, (type Student[ecx]).next ); // point next to NULL
mov( ecx, pTail ); // update address for tail
endif;

pop( ecx ); pop( ebx );
end append;


procedure readFile; @returns( "eax" );
var
fp: dword;
count: int32;
exists: boolean;
tmpStr: string;
begin readFile;
push( ebx ); push( ecx ); push( edx );

str.alloc( 32 );
mov( eax, tmpStr );

mov( 0, count );
try
fileio.open( fName, fileio.r );
mov( eax, fp );
mov( true, exists );
anyexception
mov( false, exists );
stdout.put
(
nl "Error opening file ", fName, "." nl
"Perhaps it hasn't been created yet?" nl
"Press 'Enter' to continue ... "
);
stdin.readLn();
endtry;

cmp( exists, false );
je endit;
   
init(); // BUT!!! may need to delete any records in memory first.
/*
NOTE: we need pHead to be equal to NULL in the following ...
to be permitted to set pHead ... 
to point to the first student record in memory (read in from the file).
*/
if( pHead != NULL ) then // then exit with message ...
if( cnt==1 ) then
stdout.puts( nl "The 1 former student record was left in memory." nl );
else
stdout.put( nl "The ", cnt, " former student records were left in memory." nl );
//mov( 0, count );// done above ... So old count of student records will NOT be updated.
jmp endit;
endif;
endif;
   
// If the program reaches here ... then ...

while( !fileio.eof( fp ) ) do
mem.alloc(@size(Student));
mov( eax, ecx );
fileio.get( fp, tmpStr  );
conv.strToi32( tmpStr, 0 );
mov( eax, (type Student[ecx]).id );
fileio.a_gets( fp );
mov( eax, (type Student[ecx]).sname );
for( mov( 0, edx ); edx < max; inc( edx ) ) do
mov( edx, ebx );
shl( 2, ebx ); // ebx*4
fileio.get( fp, tmpStr );
conv.strToi32( tmpStr, 0 );
mov( eax, (type Student[ecx]).marks[ebx] );
  endfor;
       
//insert( ecx );
append( ecx ); // ... since file already in order ... sorted by ID
       
inc( count );
endwhile;
fileio.close( fp );
   
if( count==1 ) then
stdout.puts( nl "1 record was read into memory from the disk file." nl );
else
stdout.put( nl, count, " records were read into memory from the disk file." nl );
endif;

 endit:
str.free( tmpStr );     
if( count>0 ) then mov( false, fileFlag ); endif;
mov( count, eax ); // return count of student records found in the file.
 
pop( edx ); pop( ecx ); pop( ebx );
end readFile;

// sort an array of pointers
// sort in ascending order of the names pointed to ...
procedure bubbleSort( a:dword );
var
noswap: boolean;
begin bubbleSort;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi ); push( edi );

mov( a, ebx );
// repeat
repeatTop:

mov( true, noswap );

//for( mov( 1, edx ); edx < cnt; inc( edx ) ) do
mov( 1, edx );
beginLoop:

mov( edx, ecx );
sub( 1, ecx );
mov( [ebx+ecx*4], esi ); // get 1st pointer into esi
mov( [ebx+edx*4], edi ); // get 2nd pointer into edi
if( str.gt( (type Student[esi]).sname, (type Student[edi]).sname ) ) then
mov( esi, [ebx+edx*4] );
mov( edi, [ebx+ecx*4] );
mov( false, noswap );
endif;

//endfor;
inc( edx );
cmp( edx, cnt );
jb beginLoop;

// until( noSwap );
cmp( noswap, true );
jne repeatTop;

pop( edi ); pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end bubbleSort;

#macro showByName( a );
if(  cnt==0 ) then
stdout.puts( nl "No records in memory at present." nl );
else
push( ecx ); push( edx );
for( mov( 0, ecx ); ecx<cnt; inc( ecx ) ) do
mov( a, edx );
mov( [edx+ecx*4], edx ); // get next pointer into edx
view( edx );
stdout.newln();
endfor;
stdout.newln();
pop( edx ); pop( ecx );
endif;   
#endmacro

procedure showAllByName;
var
ary: dword;
begin showAllByName;
push( eax ); push( ecx );

// create an array of pointers to hold pointers in list
mov( cnt, eax );
shl( 2, eax ); // eax*4
mem.alloc( eax );
mov( eax, ary );

// copy list pointers to ary
mov( pHead, ecx );
while( ecx != NULL ) do
mov( ecx, [eax] ); // copy pointer into array
add( 4 , eax ); // get next ary address
mov( (type Student[ecx]).next, ecx ); // get next pointer in list
endwhile;
//showByName( ary ); // cnt records

// sort ary of pointers, with cnt linked names, by name
bubbleSort( ary ); // cnt records

// show cnt records sorted by name, used sorted array of pointers
showByName( ary ); // cnt records

mem.free( ary );
pop( ecx ); pop( eax );
end showAllByName;


procedure menu; @returns( "al" );
begin menu;
stdout.puts( header1 );
if( cnt == 1 ) then stdout.puts( "Presently there is 1 record in RAM." nl nl );
else stdout.put( "Presently there are ", cnt, " records.", nl, nl );
endif;
stdout.puts( header2 );
stdout.puts( nl "Please enter your selection: ");
stdin.flushInput();
stdin.getc();
end menu;



begin studentList_test;

mov( readFile(), cnt );
showAll();
forever

menu();
if ( al=='1' || al=='i' || al=='I' ) then init();
elseif ( al=='2' || al=='a' || al=='A' ) then addInsertNew();
elseif ( al=='3' || al=='d' || al=='D' ) then viewDel();
elseif ( al=='4' || al=='e' || al=='E' ) then viewEdit();
elseif ( al=='5' || al=='s' || al=='S' ) then showAll();
elseif ( al=='6' || al=='n' || al=='N' ) then showAllByName();
elseif ( al=='7' || al=='f' || al=='f' ) then
if( fileFlag ) then
mov( writeFile(), cnt);
stdout.put( cnt, " records were filed." nl );
endif;
elseif ( al=='8' || al=='r' || al=='R' ) then
// If any were read ... will update Global variable pHead
if( readFile() > 0 ) then
mov( eax, cnt ); // update Global cnt
endif;
elseif  ( al=='9' || al=='x' || al=='X' ) then
if( fileFlag ) then
mov( writeFile(), cnt );
stdout.put( cnt, " records were filed." nl );
endif;
break;
else stdout.puts( nl "Not implemented yet ..." nl);
endif;

endfor;

end studentList_test;

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #11 on: January 15, 2009, 02:37:59 AM »
Just a simple Student shell in C++ ... to demo a vector of struct using push_back ...

Code: [Select]
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;

struct Data
{
    string name;
    string id;
    int balance; // in cents maybe ?
};

bool more();

int main()
{
    // create a empty vector like this
    vector< Data > myBank;

    // now using push_back ... read in the file

    Data tmp; // create a tmp entry
    do
    {
        cout << "Name    : ";
        getline( cin, tmp.name );
        cout << "ID      : ";
        getline( cin, tmp.id );
        cout << "Balance : ";
        cin >> tmp.balance;
        if( !cin.good() )
        {
            cin.clear(); // clear error flag(s) ...
            cin.sync(); // flush cin stream ...
            continue; // right now ... from the condition (at the bottom) in the 'do loop' ... (so skips push_back)
        }
        cin.sync();
        myBank.push_back( tmp ); // now ... enlarge the vector
    }while( more() );
   
    // show elements in vector  ...
    for (unsigned i=0; i<myBank.size(); ++i )
    {
        cout << setw(4)<< i+1 << " "
             << left << setw(20) << myBank[i].name << " "
             << setw(8) << myBank[i].id << " "
             << right << setw(8) << myBank[i].balance
             << endl;
    }
    //system("pause");
    cout << "\nPress 'Enter' to continue ..." << flush; cin.sync(); cin.get();  
}

bool more()
{
    cout << "More (y/n) ? ";
    int reply = cin.get();
    cin.sync(); // flush cin stream ...
    return !(reply=='n' || reply=='N');
}


Or even simpler, an array of struct ...

Code: [Select]
// This program should use an array of at least 20 structures.
// It should let the user enter data into the array, change
// the contents of any element (*yet to be done* ) and display
// all the data stored in the array ... (for starters.)

// You could do something like this ... ( as a shell to get started )

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

const int MAX = 20;

struct Data
{
    string name;
    string id;
    int balance; // in cents
};

bool more();

int main()
{
    // create a empty vector like this
    Data myBank[MAX];
    int i=0;
    do
    {
        cout << "Name    : ";
        getline( cin, myBank[i].name );
        cout << "ID      : ";
        getline( cin, myBank[i].id );
        cout << "Balance : ";
        cin >> myBank[i].balance;
        if( !cin.good() )
        {
            cin.clear();
            cin.sync();
            continue;
        }
        cin.sync();
        ++i;
       
    }while( more() && i<MAX );
   
    // show elements in vector ...
    for (int j=0; j<i; ++j )
    {
        cout << setw(4)<< j+1 << " "
             << left << setw(20) << myBank[j].name << " "
             << setw(8) << myBank[j].id << " "
             << right << setw(8) << myBank[j].balance
             << endl;
    }
    cout << "\nPress 'Enter' to continue ... " << flush;
    cin.sync();
    cin.get();           
}

bool more()
{
    cout << "More (y/n) ? ";
    int reply = cin.get();
    cin.sync();
    return !(reply=='n' || reply=='N');
}


Now ... really backing up here ... (for C++beginners)

A mini-introduction to arrays ...

Code: [Select]
// A few examples of passing arrays in C++ ... beginning with a fairly simple 1-D array

// Note: In C/C++ 'arrays are always (automatically) passed by reference'
// See what this means below ...

// When passing arrays ... the address to the first element is copied into
// a local copy of that array address ... (the compiler adds code to do this)
// SO ... NO copy of the array, (all the array values), is made by the function.
// Thus ... since the address is being used...  changes made to the array,
// inside the function, are really changes made to the array itself.

// In C++, objects (other than arrays) can be passed by reference by adding
// a '&' before the variable (i.e. after the type) in the function def'n header
// line ... See below for an example function prototype:

// void getInteger( string prompt, int & intToGet );

// then call the function with syntax like this:

// int myLocalInt;  getInteger( "Please enter a number: ", myLocalInt );

// See the '&' that tells the compiler that this is a 'pass by ref' and so to
// add the appropriate code to take care of ... all of that.

// BUT with arrays, you don't add this '&' ...
// since ... 'arrays are always passed by ref' in both C and C++

// Note: in C, 'passing by ref' syntax is NOT available.
// In C, the addresses may be passed, but you have to code all this your-self,
// taking/passing the address when you call the function and taking the value
// at that address inside the function when you want the value (not the address)

// In C (and C++) pointer passing works like this:

// /* this function returns a good positive int ... or a neg value if error ... */
// void getPosInteger( char prompt[], int * intToGet )
// {
//     /* here we de-reference the address and deal with the value there ... */
//     *intToGet = -1; /* set to -1 sentinel value here */
//     printf("%s", prompt);
//     /* note that here, intToGet is already an address, as expected by scanf */
//     scanf("%d", intToGet);
// }

// Then calling that ... works like this ... (in C or in C++)

// int myLocalInt;
// ...
// getInteger( "Please enter a number: ", &myLocalInt );

// NOTE the  ...  & ... (i.e. take the address of the variable) in the call!


// Ok ... now to the C++ demo re. arrays...

// Passing 1-D arrays is easy ...
#include <iostream>
using namespace std;


// Passing an array of int ...
// Reads ... 'a' is an array of int
void showAryInts( int a[], int size )
{
    for( int i = 0; i < size; ++i )
        cout << a[i] << " ";
    cout << endl;
}


// Just a little more care to ...
// pass an array of pointers ...to char
// (This array is called 'a ragged array' ... because
//  each C string there may be a different length.
//  Recall the C strings are really arrays of char ...
//  (or pointers to char) that ALWAYS have a '\0' char
// at the end of their sequence of char's in memory

// Reads ...  'a' is an array of pointers to char
void showAryCStrings( char *a[], int size )
{
    for( int i = 0; i < size; ++i )
        cout << a[i] << endl;
}


const int SECOND_DIM = 3;

// Passing a 2D array ...
// NOTE: We MUST specify the 2nd dimension here.
void show2DAryInts( int a[][SECOND_DIM], int firstD  )
{
    for( int i = 0; i < firstD; ++i )
    {
        for( int j = 0; j < SECOND_DIM; ++j )
            cout << a[i][j] << " ";
        cout << endl;
    }
}


int main()
{
    // delare AND initialize some arrays ...

    // a 1-D array ... of 'int' ...
    int testInts[ ] = { 1, 2, -6, 7, 99, 11, 33, 0, 9, 10 } ;

    // a 'ragged array' of C strings (is really an array of pointers to char)
    char *testChars[] = { "Apple", "Banana", "Cherry" };
   
    // 2-D arrays of 'int'
    // The compiler needs the 2nd-dimension at compile time ...
    // so it knows THEN ... how many elements are in each column ... so that
    // it can then count ... how many rows it needs
    int testMatrix[][SECOND_DIM] = { {1,2,3}, {4,5,6} };
    int testMatrix2[][SECOND_DIM] = { 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5 };

    cout << "Note the C++ syntax in this program regarding ...\n"
         << "\nShowing a simple 1-D array of int's ...\n";
    showAryInts( testInts, sizeof(testInts)/sizeof(int) );
   
    cout << "\nShowing a simple 1-D (ragged) "
         << "array of pointers to char's ...\n";
    showAryCStrings( testChars, sizeof(testChars)/sizeof(testChars[0]) );

    cout << "\nShowing 2-D arrays of int's ...\n";
    show2DAryInts( testMatrix, sizeof(testMatrix)/sizeof(testMatrix[0]) );
    cout << endl;
    show2DAryInts( testMatrix2, sizeof(testMatrix2)/sizeof(testMatrix2[0]) );

    cout << "\nPress 'Enter' to exit ... " << flush;
    cin.get();
}
« Last Edit: March 25, 2009, 11:18:23 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #12 on: January 15, 2009, 02:50:47 AM »
Time out for a little reflection on computers and computing ...

i.e. standing back a little to SEE the BIG PICTURE ...

NOTE WELL the process, putting little things together ... until we end up with some amazingly big and powerful packages.  But this one thing ... should be obvious ... but it is NOT so obvious THESE dumbed down DAYS ...

NOW ... Here it is ...

It took somebody ... (many somebodies to put it all <i.e. the first computer> together) ...

And so ... In the beginning God created the heavens and the earth ... it did NOT just all happen by itself!

Even a beginner can see that it took a lot of intelligence, work, material ... to put together the first CPU ... and it took materials, energy, planning, work, design, purpose, language, coding, decoding ...etc ...to get it to do anything purposeful ... get the drift ... And look at all the work, planning, thinking ... since then to get to OOP ... and INTEL and LINUX !!!


Shalom shalom,


David

P.S.  Take a further look at Chapter 17 ... (see next link to link to 'Chapter 17')

http://developers-heaven.net/forum/index.php/topic,46.0.html

and the program there.  It is just a little French and English intro to the Good News of our Creator ... and soon coming King of Kings. Please see these links also: 

http://sites.google.com/site/andeveryeyeshallseehim/home
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://sites.google.com/site/andeveryeyeshallseehim/he-comes-part1

Yes ... it may NOT be that much longer until this most awesome event transpires:

    * Behold, he cometh with clouds;
    * and every eye shall see him,
    * and they also which pierced him:
    * and all kindreds of the earth shall wail because of him.
    * Even so,
    * Amen.
    * (Revelation 1:7)
« Last Edit: December 18, 2009, 09:11:02 PM by David »

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: New thread especially for students of C and C++
« Reply #13 on: January 20, 2009, 09:16:23 AM »
Thanks David, Go on...

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: New thread especially for students of C and C++
« Reply #14 on: March 13, 2009, 09:26:44 AM »
A little demo of a C++ list container to hold Student records ... (makes it easy to delete a record)

Code update/moved to appear later ... (near the end at present ... click on the next link to jump to there right now:)

http://developers-heaven.net/forum/index.php/topic,106.msg272.html#msg272



Click on the small 2 in page 2 (in the lower left corner) to continue on ...
« Last Edit: September 07, 2010, 06:54:29 AM by David »