Exam #1 February 23rd (Next Friday) input (scanf) and output (printf) format strings, and associated data types control structures - loops, conditionals function definition, parameters (pass by value and pass by reference), calling functions arrays recursion creating and using struct, typedef tracing C code to determine output and for identifying errors in code Note: code examples will be similar to assignments and exercises covered so far this semester
How do we pass structures into functions? We have the same two ways to pass structures into functions: pass by value - creates a copy of the entire structure that only the function can access - changes don’t affect the original pass by reference – just pass a pointer to the structure so that the function accesses the original structure Requires that we get a pointer to the structure so we can pass by reference
struct BOOK typedef struct { STRING title; STRING author; double cost; typedef char STRING[32]; typedef struct { STRING title; STRING author; double cost; } BOOK; BOOK my_book;
Pass a Structure by Value Assume we have a variable in main of type BOOK: BOOK my_book; Function header with a call-by-value parameter: void print_book(BOOK a_book); Calling the function: (passes a copy of the structure) print_book(my_book); Fields in the function are accessed in the same way as we would in main, using the dot: printf(“Title: %s\n”, a_book.title);
Pass a Structure by Reference Assume we have a variable in main of type BOOK: BOOK my_book; In main we create a pointer variable for a BOOK: BOOK *book_ptr; Next, we make it point to my_book: book_ptr = &my_book; Function header with a call-by-reference parameter: void print_book(BOOK *ptr); Calling the function: print_book(book_ptr); or print_book(&my_book);)
How do we access the fields? We have to use the -> operator to access fields when we pass by reference, not the dot operator: Assume we have called the function with: print_book(book_ptr); We access fields like this: printf(“Title: %s\n”, ptr->title); The -> says to “follow the pointer to the field” it works the same for numbers: printf("Cost: %5.2f\n", ptr->cost);
Putting it all together: typedef char STRING[255]; typedef struct { STRING title; STRING author; double cost; } BOOK; BOOK my_book; /* declare a BOOK variable */ BOOK *book_ptr; /* declare a pointer to a BOOK */ /* pass the BOOK variable by value */ void print_by_value(BOOK my_book); /* pass a pointer to a BOOK variable */ void print_by_reference(BOOK *ptr);
An Example Recall the following typedefs: typedef char STRING[32]; typedef struct { STRING course_name; double quiz_grades[5]; double average; } GRADE; STRING student_name; GRADE courses[10]; double gpa; } STUDENT_REC; STUDENT_REC students[100]; students array students[i] STUDENT_REC students[i].student_name string students[i].gpa double students[i].courses array students[i].courses[j] GRADE students[i].courses[j].course_name string students[i].courses[j].average double students[i].courses[j].quiz_grades array students[i].courses[j].quiz_grades[k] double
Problem Description Give a program that will input data for students from a file into an array of STUDENT_REC’s. Calculate the average for each class at student takes, and output the results (including all input data). Assume that there are 100 students, each student took 3 courses, and each course had 5 quizzes. Sample input file: smith 3.4 cse1001 94.2 97.0 96.4 93.9 100.0 mth2020 88.2 85.6 85.0 84.2 89.5 chm1400 75.6 72.3 77.0 76.1 70.2 jones 2.75 psy1201 74.2 77.0 76.4 73.9 70.0 aero2201 98.2 95.6 95.0 94.2 99.5 ece1040 85.6 82.3 87.0 86.1 80.2 :
Without Functions #include <stdio.h> typedef char STRING[32]; typedef struct { STRING course_name; double quiz_grades[5]; double average; } GRADE; STRING student_name; GRADE courses[10]; double gpa; } STUDENT_REC; int main(int argc, char *argv[]) { FILE *file_ptr = NULL; const int NUM_STUDENTS = 100; const int NUM_QUIZZES = 5; const int NUM_COURSES = 3; STUDENT_REC students[NUM_STUDENTS]; int i,j,k; double sum;
Without Functions /* open data file and input student data */ file_ptr = fopen(argv[1], "r"); if(file_ptr == NULL) printf("\n*** Error opening file: %s ***\n\n", argv[1]); else { for (i=0; i<=NUM_STUDENTS-1; i++) { fscanf(file_ptr,"%s %lf\n",students[i].student_name,&students[i].gpa); for (j=0; j<=NUM_COURSES-1; j++) { fscanf(file_ptr,"%s",students[i].courses[j].course_name); for (k=0; k<=NUM_QUIZZES-1; k++) { fscanf(file_ptr,"%lf",&students[i].courses[j].quiz_grades[k]); } smith 3.4 cse1001 94.2 97.0 96.4 93.9 100.0 mth2020 88.2 85.6 85.0 84.2 89.5 chm1400 75.6 72.3 77.0 76.1 70.2 jones 2.75 psy1201 74.2 77.0 76.4 73.9 70.0 aero2201 98.2 95.6 95.0 94.2 99.5 ece1040 85.6 82.3 87.0 86.1 80.2 :
Without Functions /* calculate averages */ for (i=0; i<=NUM_STUDENTS-1; i++) { for (j=0; j<=NUM_COURSES-1; j++) { sum = 0.0; for (k=0; k<=NUM_QUIZZES-1; k++) { sum+=students[i].courses[j].quiz_grades[k] } students[i].courses[j].average=sum/NUM_QUIZZES;
Without Functions /* output final results */ printf("\nOutput Final Student Data:\n"); printf("\n"); for (i=0; i<=NUM_STUDENTS-1; i++) { printf("student #%d: %s\ngpa: %lf\n\n", i+1,students[i].student_name,students[i].gpa); for (j=0; j<=NUM_COURSES-1; j++) { printf("%s\naverage: %lf: ", students[i].courses[j].course_name,students[i].courses[j].average); printf("\ngrades: "); for (k=0; k<=NUM_QUIZZES-1; k++) { printf("%lf ",students[i].courses[j].quiz_grades[k]); } printf("\n\n"); return 0;
Sample Output student #1: smith gpa: 3.400000 cse1001 average: 96.300000: grades: 94.200000 97.000000 96.400000 93.900000 100.000000 mth2020 average: 86.500000: grades: 88.200000 85.600000 85.000000 84.200000 89.500000 chm1400 average: 74.240000: grades: 75.600000 72.300000 77.000000 76.100000 70.200000 student #2: jones gpa: 2.750000 :
Exercises Type in, compile, and execute the program Clean up output formatting
With Functions A common design technique is to have a function to input a data structure. void input_student_data(FILE *fptr, STUDENT_REC student_list[]) { int i,j,k; for (i=0; i<=NUM_STUDENTS-1; i++) { fscanf(fptr,"%s %lf\n",student_list[i].student_name,&student_list[i].gpa); for (j=0; j<=NUM_COURSES-1; j++) { fscanf(fptr,"%s",student_list[i].courses[j].course_name); for (k=0; k<=NUM_QUIZZES-1; k++) { fscanf(fptr,"%lf",&student_list[i].courses[j].quiz_grades[k]); } return; /* Second parameter could also be STRUDENT_REC *student_list */
With Functions Similarly, it is common to have a function to output a data structure. void output_student_data(STUDENT_REC student_list[]) { int i,j,k; printf("\n"); for (i=0; i<=NUM_STUDENTS-1; i++) { printf("student #%d: %s\ngpa: %lf\n\n", i+1,student_list[i].student_name,student_list[i].gpa); for (j=0; j<=NUM_COURSES-1; j++) { printf("%s\naverage: %lf: ", student_list[i].courses[j].course_name,student_list[i].courses[j].average); printf("\ngrades: "); for (k=0; k<=NUM_QUIZZES-1; k++) { printf("%lf ",student_list[i].courses[j].quiz_grades[k]); } printf("\n\n"); return;
With Functions We will add one more to do the calculation…just for fun! void calculate_student_averages(STUDENT_REC student_list[]) { int i,j,k; double sum; for (i=0; i<=NUM_STUDENTS-1; i++) { for (j=0; j<=NUM_COURSES-1; j++) { sum = 0.0; for (k=0; k<=NUM_QUIZZES-1; k++) { sum+=student_list[i].courses[j].quiz_grades[k]; } student_list[i].courses[j].average=sum/NUM_QUIZZES; /* Parameter could also be STRUDENT_REC *student_list */
With Functions Now the main becomes: int main(int argc, char *argv[]) { FILE *file_ptr = NULL; STUDENT_REC students[100]; file_ptr = fopen(argv[1], "r"); if(file_ptr == NULL) printf("\n*** Error opening file: %s ***\n\n", argv[1]); else { input_student_data(file_ptr,students); fclose(file_ptr); calculate_student_averages(students); printf("\nOutput Final Student Data:\n"); output_student_data(students); } return 0;
With Functions Another version of the calculate function: void calculate_course_average(GRADE *course_data) { double sum = 0.0; int k; for (k=0; k<=4; k++) { sum+=course_data->quiz_grades[k]; } course_data->average = sum/NUM_QUIZZES; void calculate_student_averages(STUDENT_REC student_list[]) { int i,j,k; double sum; for (i=0; i<=NUM_STUDENTS-1; i++) { for (j=0; j<=NUM_COURSES-1; j++) { calculate_course_average(&student_list[i].courses[j]);