Some things of note: from readAttendance.cc We went into the function called void printStudent(const Student_S & s) { ... } and asked why we have (const Student_S &s) reason to protect us from stuff like doing this by accident: if (s.username = NULL) return; If we include that, we get the following kinds of errors: > make readAttendanceFile CC -o readAttendanceFile readAttendanceFile.cc "readAttendanceFile.cc", line 36: Error: The left operand cannot be assigned to. 1 Error(s) detected. *** Error code 1 make: Fatal error: Command failed for target `readAttendanceFile' The error from CC is clear: the left operand cannot be assigned to. > g++ -o readAttendance readAttendanceFile.cc readAttendanceFile.cc: In function `void printStudent(const Student_S &)': readAttendanceFile.cc:36: assignment of member `Student_S::username' in read-only structure readAttendanceFile.cc: In function `int main(int, char **)': readAttendanceFile.cc:104: implicit declaration of function `int atoi(...)' The error from g++ is a bit more convoluded, but tells us the same info We also see that if you get "implicit declaration of function" errors, it means one of two things: (1) if the function it complains about is a library function such as atoi, you probably forgot an include file, in this case: #include (2) If the function it complains about is a user-defined function such as "printMyLovelyStructThingy" it means that you have a function call, but you do not have function prototype (or a function defintion) before the call. If you have either of those before the call, the error will go away. > g++ -c readAttendanceFile.cc readAttendanceFile.cc: In function `void printStudent(const Student_S &)': readAttendanceFile.cc:36: assignment of member `Student_S::username' in read-only structure readAttendanceFile.cc: In function `int main(int, char **)': readAttendanceFile.cc:104: implicit declaration of function `int atoi(...)' > Also note that we can compile a main program with -c if we just want to check syntax and not bother linking. (2) Next thing to note about this code: The error checking early in the main ensures that the command line must be exactly the program name followed by one word, and that one word must be a readable file: > g++ -o readAttendance readAttendanceFile.cc > CC -o readAttendance readAttendanceFile.cc > ./readAttendance Usage: ./readAttendance inputFileName > ./readAttendance foo bar fum Usage: ./readAttendance inputFileName > ./readAttendance foo Could not open the file: foo > Be sure before the final exam to look over the code in readAttendanceFile.cc and the examples above, and understand how this is working. I may make some final exam questions based on your understanding of this. (3) The declaration of the array of structs: Student_S students[MAX_NUM_STUDENTS]; That makes an array which is on the stack. However, in each element of that array, two of the fields are pointers to char. Those fields are four bytes long, and only contain a place for the address of some character data. There is not room for names like "mmt", "madvena", "nystc", etc.. (Well, there's room for mmt\0, but not the others, and that's beside the point anyway.) The actual character data gets stored not inside these structs, but in some space allocated on the heap. That space is allocated by code like this: students[count].username = new char[strlen(theUsername) + 1]; ... students[count].firstname = new char[strlen(theFirstName) + 1]; We allocate a blob of memory from the heap that is just the right size for the actual name. If I were to say: Foo_S *p; p = new Foo_S; then the type of the thing on the right hand side of the assignment is (Foo_S *). Here are some expressions and their types: Expression Type new int int * new double double * new char [5] char * new char char * new char * char ** new Foo_S Foo_S * new Foo_S* Foo_S ** new Foo_S[10] Foo_S * new Foo_S *[10] Foo_S ** // an array on the heap, where each elem is a ptr