Function definitions are given here for the C linked-list student program above ...
/* Function definitions ... */
char* getLine( FILE* fp )
{
int buf_chunk = 256;
int buf_len = buf_chunk;
char* buffer = (char*) calloc( buf_len, sizeof(char) );
int i=0, c;
myAssert( (buffer!=NULL), "Error: calloc failed to allocate memory" );
/* eats up WHOLE line ... including '\n' */
while( (c=fgetc(fp)) != EOF && c != '\n' )
{
if( i == buf_len-2 )
{
buf_len += buf_chunk;
buffer = (char*) realloc( buffer, buf_len );
myAssert( (buffer!=NULL), "Error: realloc failed to allocate memory" );
}
buffer[i++] = c; /* first assign then increment i ... */
}
buffer[i] = 0; /* confirm NULL terminated ... */
buffer = (char*) realloc( buffer, i+1 );
myAssert( (buffer!=NULL), "Error: realloc failed to allocate memory" );
return buffer;
}
/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pID( int n )
{
pStudent p = pHead;
if( p==NULL )
return NULL; /* List empty ... so all id numbers are available */
while( p!=NULL )
{
if( p->id == n )
return p; /* id number entered was already used */
/* Else ... get next p to compare */
p = p->next;
}
/* If reach here ... then id number not in list so ... */
return NULL;
}
void flushStdin()
{
while( getchar() != '\n' );
}
void exitNowYes()
{
int c, quit;
printf("\nPress 'X' to eXit ... ");
c = quit = getchar();
while(c != '\n') c=getchar(); /* flush stdin ... */
if( quit=='x' || quit=='X' )
{
if( fileFlag )
writeAllToFile();
printf("\nPress 'Enter' to exit right now ... or 'c' to continue ... ");
if( (c=getchar()) == '\n' )
{
FILE* fp = fopen( FILE_NAME, "r" );
if( fp==NULL )
{
printf
(
"\nError opening file %s. Perhaps it doesn't exit yet."
"\nPress 'Enter' to exit ... ",
FILE_NAME
);
flushStdin();
exit(0);
}
/* if reach here ... can show the file using a system editor ... */
fclose( fp );
/* if using a Win OS ... */
system( "notepad " FILE_NAME );
exit(0);
}
else
{
puts("\nOk ... Exit aborted ...");
while(c != '\n') c=getchar(); /* flush stdin ... */
}
}
}
void add() /* ... and insert in the proper place in the list. */
{
pStudent pS;
long ID = 0;
printf("Enter ID : ");
scanf("%ld", &ID); flushStdin();
if( pID(ID) || ID<=0 ) /* i.e. if pointer returned is NOT NULL, the id IS used */
{
printf("\nid %ld is NOT available.\n", ID );
return; /* Exit to menu right now ... */
}
/* If program reaches here, the ID just entered is available to use. */
pS = (pStudent) malloc(sizeof(Student));
myAssert( (pS!=NULL), "Error: malloc failed to allocate memory" );
pS->id = ID;
printf("Enter Last Name : ");
pS->last = getLine(stdin);
printf("Enter First Name : ");
pS->first = getLine(stdin);
printf("Enter DOB yyyymmdd : ");
scanf( "%ld", &pS->dob ); flushStdin();
printf("Enter CXC as 123456ABCDEF : ");
scanf( "%12s", pS->sCX ); flushStdin();
printf("Enter CAPE as 1234567ABCDEFG : ");
scanf( "%14s", pS->sCA ); flushStdin();
printf("Enter current area : ");
pS->currentArea = getLine(stdin);
printf("Enter desired area : ");
pS->desiredArea = getLine(stdin);
printf("Enter other info : ");
pS->otherInfo = getLine(stdin);
/* Set up link to this node */
insert( pS );
}
/* insert in list with last & first names in proper order */
void insert( pStudent pS )
{
pStudent q;
/* Firstly, we handle the case where 'this' should be the first element. */
if(pHead == NULL || StudentCmp(pS, pHead) < 0)
{
/* So ... it now becomes the first element ... */
pS->next = pHead; /* old pHead becomes 2nd in list ... */
pHead = pS; /* and ... this pS ... becomes the head of the list */
}
else /* If here ... search the linked list for the right location ... */
{
q = pHead; /* Get a working copy of pHead in q */
/* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
while(q->next != NULL && StudentCmp(q->next, pS) <= 0)
{
q = q->next; /* Traverse the list ... */
}
/*
Ok, insert after 'q' by relinking the pointers (similar to above)
( Includes inserting at end position ... where q->next == NULL )
*/
pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
q->next = pS; /* Now 'q' is updated to link to the new 'pS' element */
}
/* Update global variables. */
++numStudents;
fileFlag = 1;
}
void showAll()
{
pStudent p = pHead;
int c;
if(pHead==NULL)
{
puts("\nNo records in memory at present.") ;
return;
}
/* If reach here ... */
while( p!=NULL )
{
view( p ); /* show this record ...*/
printf("\nPress 'Enter' to continue ... or enter 'A' to abort ... ");
if( (c=getchar()) == 'a' || c == 'A' )
{
flushStdin();
return;
}
while(c != '\n') c=getchar(); /* flush stdin ... */
p = p->next;
}
}
void viewEdit()
{
int yes = 0;
long ID = 0;
pStudent p;
printf("Enter the id number to View/Edit : ");
scanf("%ld",&ID); flushStdin();
p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
if( p ) /* i.e. if pointer returned above was not NULL ... */
{
view(p);
printf("\nEdit (y/n) ? ");
yes = getchar();
if( yes=='y' || yes=='Y' )
{
while( yes!='\n' ) yes=getchar(); /* flush stdin */
edit(p);
}
else while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else printf("\nStudent with ID number %ld not found.\n", ID);
}
void view(pStudent pS)
{
printf
(
"ID number : %ld\n"
"Last name : %s\n"
"First name : %s\n"
"DOB : %ld\n"
"CXC : %s\n"
"CAPE : %s\n"
"Current area : %s\n"
"Desired area : %s\n"
"Other info : %s\n",
pS->id, pS->last, pS->first,
pS->dob, pS->sCX, pS->sCA,
pS->currentArea, pS->desiredArea, pS->otherInfo
);
}
void edit(pStudent pS)
{
long ID = 0;
long idTmp = pS->id; /* Firstly get a backup copy of this id ... */
pS->id = -1; /* Now ... reset old id number to a dummy value ... */
printf("Edit ID : ");
scanf("%ld", &ID); flushStdin();
if( pID(ID) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
{
printf("\nid %ld is NOT available.\n", ID );
pS->id = idTmp; /* Restore the id since this pS was NOT edited */
return; /* Exit to menu right now ... */
}
/* If reach hear ... */
del(pS);/* Delete old record ... etc */
pS = (pStudent) malloc(sizeof(Student)); /* get new memory for new record */
myAssert( (pS!=NULL), "Error: malloc failed to allocate memory" );
pS->id = ID;
printf("Edit Last Name : ");
pS->last = getLine(stdin);
printf("Edit First Name : ");
pS->first = getLine(stdin);
printf("Edit DOB : ");
scanf( "%ld", &pS->dob ); flushStdin();
printf("Edit CXC : ");
scanf( "%12s", pS->sCX ); flushStdin();
printf("Edit CAPE : ");
scanf( "%14s", pS->sCA ); flushStdin();
printf("Edit current area : ");
pS->currentArea = getLine(stdin);
printf("Edit desired area : ");
pS->desiredArea = getLine(stdin);
printf("Edit other info : ");
pS->otherInfo = getLine(stdin);
insert( pS );
}
void viewDel()
{
pStudent p;
int yes = 0;
long ID = 0;
printf("Enter the id number to View/Delete : ");
scanf("%ld",&ID); flushStdin();
p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
if( p ) /* i.e. if pointer returned above was not NULL ... */
{
view(p); /* show this record ... */
printf("\nDelete (y/n) ? ");
yes = getchar();
if( yes=='y' || yes=='Y' ) del(p);
while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else printf("\nStudent with ID number %ld not found.\n", ID);
}
void del(pStudent pS)
{
pStudent p,
pp; /* to hold the pointer to the previous record */
/* Handle special case of 'first in list' */
if( pS==pHead )
{
pHead = pS->next;
free( pS->first );
free( pS->last );
free( pS->currentArea );
free( pS->desiredArea );
free( pS->otherInfo );
free( pS );
--numStudents; /* update globals ... */
fileFlag = 1;
return;
}
/* Else not first in list, so ... */
p = pHead; /* set p to this initial value to start loop */
/* Now find the pointer to the previous record. */
while( p != pS )
{
pp = p; /* pp holds previous pointer value ... */
p = p->next; /* set to next pointer in link list chain */
}
/*
Now we have a pointer to the previous Student record, so ...
we can now point that previous record to one past this pS record
*/
pp->next = pS->next;
/* Now free the memory for this record and update the globals ... */
free( pS->first );
free( pS->last );
free( pS->currentArea );
free( pS->desiredArea );
free( pS->otherInfo );
free( pS);
--numStudents;
fileFlag = 1;
}
void delAll()
{
pStudent p = pHead; /* Set p to this initial value to start loop */
pStudent pNext; /* To hold the pointer to the next record */
while( p != NULL )
{
pNext = p->next; /* Get a pointer to the next record. */
free( p->first );
free( p->last );
free( p->currentArea );
free( p->desiredArea );
free( p->otherInfo );
free( p );
p = pNext; /* Update p ... */
}
/* Update globals ... */
pHead = NULL;
numStudents = 0;
fileFlag = 0;
}
/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
int yes;
if( pHead != NULL )
{
printf("\nDo you wish to overwrite the records in memory y/n ? ");
yes = getchar();
if( yes=='y' || yes=='Y' )
delAll(); /* re-sets globals ... */
else
{
if(numStudents==1)
puts("1 Student record was left intact in memory.");
else
printf("%d Student records were left intact in memory.\n",
numStudents);
}
while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else puts("\nThere were no records in memory to clear.");
}
void scramble( char s[] )
{
int i = 0;
int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
while( s[i]!=0 ) { s[i] = (char) ((int)s[i] - code[i]); ++i; }
}
void unscramble( char s[] )
{
int i = 0;
int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
while( s[i]!=0 ) { s[i] = (char) ((int)s[i] + code[i]); ++i; }
}
void writeAllToFile()
{
if( !fileFlag )
{
puts("\nNo changes ... so nothing filed ...");
return;
}
if( numStudents == writeFile() ) /* write all to file ... */
{
if( numStudents > 0 )
{
if( numStudents == 1 )
puts("\nThe 1 Student record was safely filed.");
else
printf
(
"\nAll %d Student records safely filed.\n",
numStudents
);
}
}
else
{
printf
(
"\nAn error occured while filing the Student records."
"\nPlease see the programmer for help with the problem.\n"
"\nExiting the program now. Press 'Enter' to continue ... "
);
flushStdin(); /* Holds window open to show above message. */
exit(0); /* Return error number to system. */
}
}
int writeFile()
{
int count; /* to track the records actually written to the file */
FILE* fp;
pStudent p = pHead;
if( pHead==NULL )
{
puts("\nNo records available ... so NO records written to file.") ;
return 0;
}
fp = fopen( FILE_NAME, "w" );
if( fp==NULL )
{
printf("\nError opening file %s. Press 'Enter' to continue ... ", FILE_NAME);
flushStdin();
return 0;
}
count = 0; /* to track the records actually written to the file */
while( p!=NULL )
{
fprintf
(
fp,
"%ld\n"
"%s\n"
"%s\n"
"%ld\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n",
p->id, p->last, p->first,
p->dob, p->sCX, p->sCA,
p->currentArea, p->desiredArea, p->otherInfo
);
++count;
p = p->next;
}
fclose( fp );
fileFlag = 0;
return count; /* Number of records written. */
}
int readFile()
{
int count;
long ID;
FILE *fp;
pStudent pS;
#if !READ_SORTED
pStudent pp=NULL;
#endif
fp = fopen( FILE_NAME, "r" );
if( fp==NULL )
{
printf
(
"\nError opening file %s.\n"
"Perhaps it hasn't been created yet?\n"
"Press 'Enter' to continue ... ",
FILE_NAME
);
flushStdin();
return 0;
}
/* BUT!!! may need to delete any records in memory first. */
init();
/*
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 exit with message ... */
{
if(numStudents==1)
puts("\nThe 1 former Student record was left in memory.");
else
printf("\nThe %d former Student records were left in memory.\n", numStudents);
return 0; /* So ...old count of Student records will NOT be updated. */
}
/* If the program reaches here ... then ... */
count = 0;
while( fscanf( fp, "%ld", &ID) != EOF )
{
pS = (pStudent) malloc(sizeof(Student));
myAssert( (pS!=NULL), "Error: malloc failed to allocate memory" );
pS->id = ID;
fgetc(fp); /* eats up the '\n' char left over from above 'ID read' */
pS->last = getLine(fp);
pS->first = getLine(fp);
fscanf( fp, "%ld", &pS->dob );
fgetc(fp); /* eats up the '\n' char left over ... */
fscanf( fp, "%s", pS->sCX );
fscanf( fp, "%s", pS->sCA );
fgetc(fp); /* eats up the '\n' char left over ... */
pS->currentArea = getLine(fp);
pS->desiredArea = getLine(fp);
pS->otherInfo = getLine(fp);
#if !READ_SORTED
if ( pp != NULL ) /* for 2nd and up records ...*/
pp->next = pS; /* now previous record points to this new one */
else pHead =pS; /* first record only has base pointer */
pS->next = 0; /* NULL terminate list ... */
pp = pS; /* Keep a copy of address of this pS in pp for next while loop. */
#else
insert( pS );
#endif
++count;
/* printf( "\nRecord number is %d\n", count ); */
}
fclose( fp );
if(count==1)
puts("\n1 record was read into memory from the disk file.");
else
printf("\n%d records were read into memory from the disk file.\n", count);
fileFlag = 0;
return count; /* Total number of Student records found in the file. */
}