Author Topic: Six Fast Steps to Programming in C  (Read 32892 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in C
« Reply #15 on: October 19, 2011, 05:50:09 PM »
4.  Finally, here we use readLine (instead of fgets with a large buffer) ... and also we use xxx.h files ... readLine.h, Cvec.h and Cvec_func's.h ... to facilitate coding and code re-use. 

Note: you will need all 3 of these following linked files, to be available to include, before you compile this 4th demo program in this series ...

readLine.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

Cvec.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2862.html#msg2862

Cvec_func's.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2866.html#msg2866

Code: [Select]
/* phnBook4.c */  /* 2016-10-12 */


/* using readLine.h and Cvec.h and Cvec_func's.h ... */


#include "readLine.h" /* includes <stdio.h>, <stdlib.h>, <string.h>, etc... */


#define MENU "Contact Menu ...\n" \
             "\t\t\t(1)\tAdd Contact\n" \
             "\t\t\t(2)\tDelete Contact\n" \
             "\t\t\t(3)\tShow All Contacts\n" \
             "\t\t\t(4)\tsOrt All Contacts\n" \
             "\t\t\t(5)\teXit ...\n" \
             "Enter your choice 1..5 > "
             
#define VEC_CHUNK_SIZE 2 /* if not defined here, defaults to initial cap = 8 */

/* first ... define Rec ... */
typedef struct myContact
{
    char* firstName;
    char* lastName;
    char* phoneNumber; /* num of char's for phoneNumber is 10 + terminal 0 */
} Rec ;

/* and then define void freeVrec( Rec* ); ... */
void clearRec( Rec* rc )
{
    free( rc->phoneNumber );
    free( rc->lastName );
    free( rc->firstName );
}

/* now can ... */
#include "Cvec.h"
#include "Cvec_func's.h"


/* you also need to define 'equals'... via a 'your_cmp_equals' 2 Rec's function */
int cmp_equals( const Rec* a, const Rec* b ) /* for findCvec( .. ) to work */
{
    if( strcmp(a->firstName, b->firstName) == 0
        && strcmp(a->lastName, b->lastName) == 0 ) return 0; /* def'n equals */
    else return 1;
}

int my_sort_cmp( const Rec* a, const Rec* b ) /* for msortCvec( .. ) to work */
{
    int eq = strcmp(a->lastName, b->lastName);
    if( eq == 0 ) return strcmp(a->firstName, b->firstName);
    /* else ...*/
    return eq;
}

void addContact( Cvec* );
void deleteContact( Cvec* );
void showAllContacts( Cvec* );

char* takeInLine( const char* msg )
{
    printf( msg );
    return readLine( stdin );
}
char* takeInLineMinMax( const char* msg, int min, int max )
{
    char* line;
    int len;
    for( ; ; ) /* loop forever ... until break ... */
    {
        line = takeInLine( msg ); /* using readLine.h included above ... */
        len = strlen(line);
        if( min <= len && len <= max )
            return line;
        /* else... */
        printf( "\nERROR! Input must have length in range %d..%d\n", min, max );
        free( line );
    }
}
char* takeInLineSize( const char* msg, int len )
{
    char* line;
    for( ; ; ) /* loop forever ... until break ... */
    {
        line = takeInLine( msg ); /* using readLine.h included above ... */
        if( (int)strlen(line) == len ) return line;
        /* else... */
        printf( "\nERROR! Input must have length %d\n", len );
        free( line );
    }
}

int isValidPhoneNum( const char* s )
{
    int i = strlen( s ) - 1;
    for( ; i >= 0; --i ) if( !isdigit( s[i] ) ) return 0;
    /* else ... if reach here .. */
    return 1;
}

/* 's' is the C string passed in ... and WAS validated as 10 digits long */
void printFormattedPhoneNum( const char* s )
{
    const char* p = "xxx-xxx-xxxx";
    /* printf( "Number: " ); */
    for( ; *p != 0 ; ++p )
    {
        if( *p == 'x' )
        {
            putchar( *s );
            ++s;
        }
        else  putchar( *p );
    }
    /* putchar( '\n' ); */
}

void printRec( Rec* rc )
{
    printFormattedPhoneNum( rc->phoneNumber );
    printf( ": %s %s", rc->firstName, rc->lastName );
}




int main( void )
{       
    int reply;
    Cvec phonebook;
    initCvec( &phonebook );
   
    printf( "Size of each record = sizeof(Rec) = %d bytes ...\n", (int)sizeof(Rec) );

    do
    {
        reply = toupper(takeInChar( MENU ));
       
        if( reply == '1' || reply == 'A' )
            addContact( &phonebook ); /* Cvec updated since address passed */
        else if( reply == '2' || reply == 'D' )
            deleteContact( &phonebook ); /* Cvec updated ... */
        else if( reply == '3' || reply == 'S' )
            showAllContacts( &phonebook ); /* no copy made ... address passed */
        else if( reply == '4' || reply == 'O' )
            { puts( "Now sorted ..." ); msortCvec( &phonebook, my_sort_cmp ); }
        else if( reply == '5' || reply == 'X' )
        {
            clearCvec( &phonebook ); /* Cvec updated ... */
            printf( "\nWill exit now ... Press 'Enter' to continue ... " );
            fflush( stdout );
            getchar();
        }
        else if( reply == '\n' ) printf( "\nYou need to enter something ...\n" );
        else printf( "\nChoice '%c' NOT implemented here ...\n", reply );
    }
    while( !(reply == '5' || reply == 'X') );

    return 0;
   
} /* end of main ... */




void addContact( Cvec* phonebook )
{
    do
    {
        Rec r;
        r.firstName = takeInLineMinMax( "First Name   : ", 1, 80 ); /* pointer copied */
        r.lastName =  takeInLineMinMax( "Last Name    : ", 1, 80 );
        strToTitleCase(r.firstName);
        strToTitleCase(r.lastName);
        for( ; ; )
        {
            r.phoneNumber = takeInLineSize( "Phone Number : ", 10 );
            if( isValidPhoneNum( r.phoneNumber ) ) break;
            /* else ... */
            printf( "\n%s is not all digits ...\n", r.phoneNumber );
            free( r.phoneNumber );
        }
       
        if( tolower(takeInChar( "Ok (y/n) ? ")) == 'y'  )
        {
            push_backCvec( phonebook, &r ); /* copies Rec pointers into array memory */
            printRec( &r );
            printf( " was successfully added ...\n" );
        }
        else
        {
            printRec( &r );
            printf( " NOT added ...\n" );
            clearRec( &r );
        }
    }
    while( more() ) ;
}
   
void deleteContact( Cvec* phonebook )
{
    int i;
    Rec r;
    r.firstName = takeInLineMinMax( "First Name   : ", 0, 100 ); /* pointer copied */
    r.lastName = takeInLineMinMax( "Last Name    : ", 0, 100);
   
    i = findCvec( phonebook, &r, cmp_equals ); /* uses def'n 'cmp_equals function' */
    if( i != -1 ) /* findCvec returns index if found ... or -1 if not found */
    {
        eraseCvec( phonebook, i ); /* 'phonebook' is already an address */
        printf( "Contact deleted from Cvec ...\n" );
    }
    else printf("Contact NOT found ...\n");
   
    clearRec( &r ); /* free memory of dynamic C strings in this Rec 'r' ... */
}

void showAllContacts( Cvec* phonebook )
{
    int x = 0;
    printf( "\nContacts:" );
    for( x = 0; x < phonebook->size; ++x )
    {
        printf( "\n(%d)\n", x+1);
        printf( "Name: %s %s\n",
                phonebook->ary[x].firstName, phonebook->ary[x].lastName );
        /* printf( "Number: %s\n", phonebook->ary[x].phoneNumber ); */
        printf( "Number: " );
        printFormattedPhoneNum( phonebook->ary[x].phoneNumber );
    }
    printf( "\nsize = %d, capacity = %d\n", phonebook->size, phonebook->cap );
}
« Last Edit: October 17, 2016, 03:08:10 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to Programming in C
« Reply #16 on: October 29, 2011, 01:26:05 AM »
This next series of 2 programs, further illustrates using a Cvec of struct ... a stuct that also contains a Clist ... This series is to demo a C emulation of some C++ program's at this next link ...

http://developers-heaven.net/forum/index.php/topic,2019.msg2909.html#msg2909

Now here are the C versions ... the 2nd one just uses arrays of struct Student ... that has the array size fixed at compile time ...
1.
Code: [Select]
/* readShowCvecOfStructStudentFile.c */  /* 2016-10-08 */


/* a Cvec of struct that contains a Clist */

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

const char* MY_FILE = "studentData.txt";

/* data file is structured like this ... */
/*
Smith, Jane
97 83 97 87 66 76 37 85 97 93
Jones, Bob (Robert)
98 91 96 98 62 65 86 68 65 9
Costello, Judy Ann
98 90 96 99 72 85 55 9 75 99
*/

#include "readLine.h" /* includes stdio.h, stdlib.h, string.h, etc ... */

typedef struct myNode
{
    int val;
    struct myNode* next;
} Node ;

typedef Node* pNode;

void clearNode( pNode p )
{
    /* no dynamic memory to free ... */
    p = p;
}

#include "Clist.h"
#include "Clist_func's.h"

int compareLst( const pNode a, const pNode b )
{
    if( b->val < a->val ) return -1;
    if( b->val > a->val ) return 1;
    return 0;
}


typedef struct myStudent
{
    char* name; /* to hold the name of a Student... */
    Clist marks; /* to hold a list of integer marks for a Student object */
} Rec ;

void clearRec( Rec* r )
{
    clearClist( & r->marks );
    free( r->name );
}

#include "Cvec.h"
#include "Cvec_func's.h"

int compareVec( const Rec* a, const Rec* b )
{
    return strcmp( a->name, b->name );
}



int main()
{
    FILE* fin;
    char *line1, *line2;
    int i;
    pNode pls;
    Cvec myStuds;
    initCvec( &myStuds );
   
    fin = fopen( MY_FILE, "r" );
    myAssert( (fin != NULL), "File failed to open." );

    /* while still more students in file, get next student 2 lines of data ... */
    while( (line1 = readLine(fin)) && (line2 = readLine(fin)) )
    {
        char* p;
        Rec tmp; /* construct an empty tmp Student Rec */
       
        /* first get this student's name */
        tmp.name = line1;
        initClist( &tmp.marks );

        /* then get this student's marks ...
          get marks ... into this student's list of marks ... */
        p = strtok( line2, " " );
        for( ; ; )
        {
            Node lst;
            lst.val = atoi( p );
            push_backClist( &tmp.marks, &lst );
            p = strtok( NULL, " " );
            if( !p ) break;
        }
       
        push_backCvec( &myStuds, &tmp ); /* append this rec to vector */
        free( line2 );
    }
    fclose( fin );
   
    /* ok ... now show SORTED file content's to the screen ... */
    printf( "Here is the student data (now sorted) that was in the file %s"
            " ...\n\n", MY_FILE );

    msortCvec( &myStuds, compareVec );
    for( i = 0; i < myStuds.size; ++i )
    {
        int sum = 0;
        printf( "%s\n", myStuds.ary[i].name ); /* show this student name ... */
        /* now show all marks SORTED in descending order for this student ... */
        msortClist( &myStuds.ary[i].marks, compareLst );
        for( pls = myStuds.ary[i].marks.start; pls != NULL; pls = pls->next )
        {
            printf( "%4d", pls->val ); /* show this mark to right of 4 char field */
            sum += pls->val;
        }
        printf( ", Sum = %d, Average = %.1f\n",
                sum, ((double)sum)/myStuds.ary[i].marks.size );
    }
   
    clearCvec( &myStuds );
   
    printf( "\nPress 'Enter' to continue/exit ... " ); fflush( stdout );
    getchar(); /* keep 'Window' open until 'Enter' key is pressed ... */
    return 0;
}


2.
Code: [Select]
/* readShowArrayOfStructStudent.c */ /* Note: array sizes pre-fixed at compile time */

#include "readLine.h" /* includes stdio.h, stdlib.h, string.h, etc ... */


#define MAX_ARY_SIZE 100 /* adjust here, so able to hold expected size */
#define MAX_GRADES 20    /* adjust here, so able to hold expected size */

const char* FNAME = "studentData.txt"; /* or, use your own data file name */

typedef struct myStudent
{
    char* name;
    int grades[MAX_GRADES];
    int grades_size;
} Student ;

/* returns size of array actually loaded up to max_size ... */
int load( Student ary[], int max_size );

void show( Student ary[], int size );

/* compare function re. qsort ... */
int compare( const void* a, const void* b )
{
    const Student* x = (Student*) a;
    const Student* y = (Student*) b;
    return strcmp( x->name, y->name ); /* sort names in ascending order ... */
}

int compareGrds( const void* a, const void* b )
{
    const int* x = (int*) a;
    const int* y = (int*) b;
    if( *x > *y ) return -1; /* sort marks in descending order ... */
    if( *x < *y ) return 1;
    return 0;
}



int main()
{
    Student students[MAX_ARY_SIZE]; /* reserve space for array of Student records */

    int i, size = load( students, MAX_ARY_SIZE ); // get file data into array ...
   
    if( !size ) { puts("File failed to read any data." ); goto EXIT_NOW; }

    show( students, size ); /* show Student data on console screen ... */
   
    printf( "\nAfter sort ...\n\n" );
    qsort( students, size, sizeof(Student), compare );
    for( i = 0; i < size; ++ i )
        qsort( students[i].grades, students[i].grades_size, sizeof(int), compareGrds );
   
    show( students, size ); /* show Student data on console screen ... */

    for( i = size-1; i >= 0; --i )
        free( students[i].name );

EXIT_NOW:
    printf( "\nPress 'Enter' to continue/exit ... " ); fflush( stdout );
    getchar(); /* keep window open until 'Enter' key is pressed ... */
    return 0;
}


int load( Student ary[], int max_size )
{
    FILE* fin = fopen( FNAME, "r" );
    char *line1, *line2;
    int i = 0;
    if( !fin ) return 0;
   
    while( i < max_size && (line1 = readLine(fin)) && (line2 = readLine(fin)) )
    {
        int j = 0;
        char* p = strtok( line2, " " );
        ary[i].name = line1; /* get name into array for this ith index ... */
        while( j < MAX_GRADES )
        {
            ary[i].grades[j++] = atoi( p ); /* j is incremented AFTER assignment */
            p = strtok(NULL, " ");
            if( !p ) break;
        }

        free( line2 );
        ary[i].grades_size = j; /* j will be a value in the range 0..MAX_GRADES */
       
        ++i;
    }
    fclose( fin );
    return i;
}

void show( Student ary[], int ary_size )
{
    int i, j;
    for( i = 0; i < ary_size; ++i )
    {
        printf( "%s\n", ary[i].name );
        for( j = 0; j < ary[i].grades_size; ++j )
            printf( "%4d", ary[i].grades[j] );

        putchar( '\n' );;
    }
}
« Last Edit: October 17, 2016, 03:11:43 AM by David »