Search code examples
cpointersfile-handling

How can I incorporate pointers in my finished C programs?


I just finished 2 of my C programs that are due today but when my professor checked out my work, he told me to incorporate pointers in them. We haven't learned about pointers and I'm really struggling to figure out what he meant. I tried adding things I learned through online tutorials but it just results to multiple error and I just can't make it work.

My first program is a Student Record. I want the Student's name, score 1, 2, 3 and also their final grade and be stored in a file but I can't figure out how. This is my code:

#include <stdio.h>
#include <stdlib.h>

#define max 3

void getscore(char *name, int *grade1, int *grade2, int *grade3);
void display();
float rate(float ave);
float average(int a, int b, int c);

float rating[max];
float ave[max];
char n[max][50];
int q1[max], q2[max], q3[max];

int main()
{
    int i;
    system("cls");
    for(i = 0; i<max; i++){
        system("cls");
        printf("\t\tInput Student Record");
        printf("\nStudent# %i", i+1);
        getscore(n[i], &q1[i], &q2[i], &q3[i]);
        ave[i] = average(q1[i], q2[i], q3[i]);
        rating[i] = rate(ave[i]);
    }
    display();
    getch(); //system("pause");
}

void getscore(char *name, int *grade1, int *grade2, int *grade3)
{
    printf("\nStudent Name: ");
    scanf("%s", name);

    printf("\nQuiz Score#1: ");
    scanf("%i", grade1);

    printf("\nQuiz Score#2: ");
    scanf("%i", grade2);

    printf("\nQuiz Score#3: ");
    scanf("%i", grade3);
}

float rate(float ave)
{
    /*5.00 - 74 below
      3.00 - 75 - 76
      2.75 - 77 - 79
      2.50 - 80 - 83
      2.25 - 84 - 87
      2.00 - 88 - 90
      1.75 - 91 - 93
      1.50 - 94 - 96
      1.25 - 97 - 98
      1.00 - 99 - 100
    */

    if(ave >= 75 && ave <= 76)
        return 3.00;
    else if(ave >= 77 && ave <=79)
        return 2.75;
    else if(ave >= 80 && ave <= 83)
        return 2.5;
    else if(ave >=84 && ave <= 87)
        return 2.25;
    else if(ave >= 88 && ave <= 90)
        return 2.00;
    else if(ave > 91 && ave <= 93)
        return 1.75;
    else if(ave > 94 && ave <= 96)
        return 1.50;
    else if(ave > 97 && ave <= 98)
        return 1.25;
    else if(ave > 99 && ave <= 100)
        return 1.00;
    else
        return 5.00;
}

float average(int a, int b, int c)
{
    return (a+b+c) / 3;
}

void display()
{
    int i;
    printf("\nStudent Grade Record\n");
    printf("\n\nNo. Name \t Quiz_1 \t Quiz_2 \t Quiz_3 \t Average \t Rating");
    for(i=0; i < max; i++)
    {
        printf("\n%i.) %s \t\t%i \t\t%i \t\t%i \t\t%.2f \t\t%.2f", i+1, n[i], q1[i],
               q2[i], q3[i], ave[i], rating[i]);
    }
}

I have tried adding few things I learned from online tutorials from youtube but it only resulted line and line of errors.


Solution

    1. It's not clear if you want the display() output to stdout like now and to a file, output to a file only, or a different format when writing to the file. The following demonstrate the writing to file by passing a FILE * to display and using fprintf() instead of print. If you want a different format create an alternative display() function for the file output and call that instead.

    2. Added a maximum field with to the function that reads a string.

    3. Eliminated global variables. This means the relevant variables now have to be passed to display().

    4. Move main() to the bottom. In small examples like that it means you can eliminate the prototypes.

    5. Removed the system calls so I could test this for you.

    6. Minimize scope of variables. With for loops prefer to scope the variables by the loop instead of before the loop (sometimes you need the variable and can't).

    7. You rate function is defective. For example, should the rate(98.5) return 5? I suggest you fix this by using a half-open interval of the averages [0; 75[, [75; 77[ etc. This makes the range contiguous and it's easier to see if you missed something. The next observation is that the end of one range is the start of the next so you only need to store of them. If you return then you don't need an else so combined it would look like this. What should happen if ave > 100?

      if(ave < 75)
         return 5;
      if(ave < 77)
         return 3;
      // ..
      
    8. (Not fixed) Prefer double to float.

    9. (Not fixed) Consider creating a struct for all the information you need for a single student. Then create an array of 3 students.

    10. (Not fixed) Consider eliminating the duplication in the revised rate() function by using a lookup table and a loop:

      struct {
          float max; // exclusive
          float rate;
       } grade[] = {
          {75, 5},
          {77, 3}
          // ...
       };
       size_t i = 0;
       for(; i < sizeof grade / sizeof *grade - 1; i++)
           if(ave < grade[i].max)
                return grade[i].rate;
       // what should happen if ave > 100?
       return grade[i].rate;
      
      

    Here is the resulting code:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define max 3
    #define NAME_LEN 49
    #define str(s) str2(s)
    #define str2(s) #s
    
    float average(int a, int b, int c) {
        return (a+b+c) / 3;
    }
    
    void display(FILE *f, char n[max][NAME_LEN+1], int q1[max], int q2[max], int q3[max], float ave[max], float rating[max]) {
        fprintf(f, "\nStudent Grade Record\n");
        fprintf(f, "\n\nNo. Name \t Quiz_1 \t Quiz_2 \t Quiz_3 \t Average \t Rating");
        for(int i=0; i < max; i++) {
            fprintf(f, "\n%i.) %s \t\t%i \t\t%i \t\t%i \t\t%.2f \t\t%.2f", i+1, n[i], q1[i],
                q2[i], q3[i], ave[i], rating[i]);
        }
    }
    
    void getscore(char *name, int *grade1, int *grade2, int *grade3) {
        printf("\nStudent Name: ");
        scanf("%" str(NAME_LEN) "s", name);
    
        printf("\nQuiz Score#1: ");
        scanf("%i", grade1);
    
        printf("\nQuiz Score#2: ");
        scanf("%i", grade2);
    
        printf("\nQuiz Score#3: ");
        scanf("%i", grade3);
    }
    
    float rate(float ave) {
        if(ave < 75)
            return 5;
        if(ave < 77)
            return 3;
        if(ave < 80)
            return 2.75;
        if(ave < 80)
            return 2.75;
        if(ave < 84)
            return 2.5;
        if(ave < 88)
            return 2.25;
        if(ave < 91)
            return 2;
        if(ave < 94)
            return 1.75;
        if(ave < 97)
            return 1.5;
        if(ave < 99)
            return 1.25;
        // what should happen if ave > 100?
        return 1;
    }
    
    int main() {
        FILE *file = fopen("output.txt", "a");
        if(!file) {
            fprintf(stderr, "could not open file\n");
            return 1;
        }
        float rating[max];
        float ave[max];
        char n[max][NAME_LEN+1];
        int q1[max], q2[max], q3[max];
        for(int i = 0; i<max; i++) {
            printf("\t\tInput Student Record");
            printf("\nStudent# %i", i+1);
            getscore(n[i], &q1[i], &q2[i], &q3[i]);
            ave[i] = average(q1[i], q2[i], q3[i]);
            rating[i] = rate(ave[i]);
        }
        FILE *handles[] = {stdout, file};
        for(size_t i = 0; i < sizeof handles / sizeof *handles; i++)
            display(handles[i], n, q1, q2, q3, ave, rating);
        fclose(file);
    }