============================================================================ Faculty of Applied Science and Engineering, University of Toronto CSC181: Introduction to Computer Programming, Fall 2000 Tutorial Notes, Week 4 ============================================================================ ----------------- Summary of Topics ----------------- - C structs ------- Example ------- The following program models students who have the following attributes: - a student ID - a name - a list of marks ---- Code ---- #include #include #define NAME_LENGTH (20) #define MARKS_LENGTH (10) struct student { int id; char name[NAME_LENGTH]; int marks[MARKS_LENGTH]; int marksSize; }; typedef struct student Student; Student studentAddMark(const Student student, const int mark); double studentAverage(const Student student); Student studentAddMark(const Student s, const int i) { Student result = s; result.marks[result.marksSize] = i; result.marksSize++; return result; } double studentAverage(const Student s) { if (s.marksSize == 0) { return 0.0; } else { int sum = 0; int i; for (i = 0; i != s.marksSize; i++) { sum += s.marks[i]; } return (double)sum/s.marksSize; } } main() { Student s = {3, "bob", {0}, 0}; printf("ID: %i\n", s.id); printf("Name: %s\n", s.name); printf("Average (%d marks): %.2lf\n", s.marksSize, studentAverage(s)); s = studentAddMark(s, 80); printf("Average (%d marks): %.2lf\n", s.marksSize, studentAverage(s)); s = studentAddMark(s, 70); s = studentAddMark(s, 92); printf("Average (%d marks): %.2lf\n", s.marksSize, studentAverage(s)); } --- end code --- --- Run --- ID: 3 Name: bob Average (0 marks): 0.00 Average (1 marks): 80.00 Average (3 marks): 80.67 -------- 'struct' -------- 'struct's are used to group related data together. The 'student' struct is declared as follows: struct student { int id; char name[NAME_LENGTH]; int marks[MARKS_LENGTH]; int marksSize; }; This 'struct' has four "fields" (synonyms include "attributes", "members"), representing: the student ID (as an int), the name (as a char array) and its marks (as an int array with an accompanying int to keep track of how many marks are stored in the array). To define a 'struct student' variable, we use the following statement: struct student s; For convenience, we define a type equivalent to 'struct student' called 'Student. We can now use the shorter 'Student' whereever we can use 'struct student': Student s; We can also initialize the student while defining it: Student s = {3, "bob", {0}, 0}; This will give it an initial 'id' of 3 and 'name' of "bob", and will initialize the 'marks' array to contain zeroes (and its accompanying 'marksSize' to zero, since the student initially has no marks). To access the fields in a struct, we use the dot operator '.'. For example, the following statement will change s's 'id' to 5: s.id = 5; We can assign structs using the assignment operator '='. This copies the values of the fields (including the contents of any array fields!) from the right operand into the fields of the left operand: Student s1 = {3, "bob", {80, 70, 90}, 3}; Student s2 = s1; /* s2 now has a copy of s1's fields */ Note that after the assignment, changes to the right operand of the assignment won't affect the left operand of the assignment, and vice-versa: s1.id = 2; s2.marks[1] = 40; printf("%d\n", s1.id); /* prints "2" */ printf("%d\n", s2.id); /* prints "3" */ printf("%.2lf\n", studentAverage(s1)); /* prints "80.00" */ printf("%.2lf\n", studentAverage(s2)); /* prints "70.00" */ Finally, it is important to note that since C uses pass-by-value, we cannot change a struct proper passed as an argument to a function. To get around this, we can use the following approach: 1) have a function modify a copy of the (const) struct argument, and return that copy 2) take the return value from (1) (which is a copy of the local struct variable modified inside the function) and assign it to the variable holding the original struct argument In the example above, this can be seen with the 'studentAddMark' function, and its usage in the 'main' function. Obviously, passing and returning copies of structs can be quite inefficient. This is where pointers come in handy.