0

I am currently learning C and trying to create an app that allows students to input their name, address, student id and any subject id they have while at university (yes this is a task part of foundations of tech course). Basically the following code tries to create an array of students (that is unlimited in size) by using dynamic allocating memory. Further a student can have unlimited amounts of subjects (that is nested within the student subject and is dynamically allocated)

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

int main()
{


    typedef struct {
        char subjectID[10];
        char subjectName[10];
        float grades;

        }subject;

    typedef struct {
        char name[10];
        int id;
        struct subject *enrol;
        char address[100];
        int status;
        int totalSubject;
    }student; // This structure is to act like an unlimited list of students

    int option=0, q=0, j=0, k=0, p=0, delete=0, position=0;
    int count=0;    // keeps the count of numbers added
    student * studentAddress; 
    studentAddress = NULL; //Init structure
    studentAddress->enrol = NULL; // Init nested structure
    int flag = 0; //variable to indicate whether the number to delete is found or not

    while (1) // Life cycle of the app
    {
        printf("1 - Add new student\n");
        printf("2 - Display all students\n");
        printf("3 - Delete student by id \n");
        printf("4 - Delete student by name \n");
        printf("5 -  Quit\n");

        scanf("%d",&option);

        switch (option)
        {
            case 1: studentAddress = realloc(studentAddress, sizeof(student)*(count+1)); //using realloc memory is requested for the new number
                printf("Enter your name\n");
                fflush(stdin);
                gets(studentAddress[count].name);
                fflush(stdin);
                printf("Enter your id\n");
                scanf("%d", &studentAddress[count].id);
                printf("Enter your address\n");
                fflush(stdin);
                gets(studentAddress[count].address);
                fflush(stdin);
                int subjectCounter = 0;


                subjectCounter = 0;
                char subjectContinue[10];
                for (p = 0; p < subjectCounter; p++)
                {
                    studentAddress[count].enrol = (struct subject *)realloc(studentAddress[count].enrol, (sizeof(subject)*(subjectCounter+1)));
                    // studentAddress[count].enrol[subjectCounter] = (struct subject *)realloc(sizeof(subject)*(subjectCounter+1));
                    // Above is teacher paste
                    printf("What is the id of your subject %d\n", (subjectCounter+1));
                    fflush(stdin);
                    gets(studentAddress[count].enrol[subjectCounter].subjectID);

                    fflush(stdin);
                    printf("Would you like to add another subject id\n");
                    fflush(stdin);
                    gets(subjectContinue);
                    fflush(stdin);
                    if (strcmp(subjectContinue, "Y") == 0)
                    {
                        subjectCounter++;

                    }
                    studentAddress[count].totalSubject = subjectCounter;
                }

                count++;
                printf("\n");
                break;

        case 2: 

            for (j=0; j<count; j++)
            {
                if(studentAddress[j].status != 0)
                    printf("%s\n %d\n %s\n", studentAddress[j].name, studentAddress[j].id, studentAddress[j].address);
                    for (q = 0; q < studentAddress[count].totalSubject; q++)
                    {
                        printf("%s", studentAddress[j].enrol[q].subjectID);
                    }

            }
            printf("\n");
            break;

        case 3: k=count;
            flag=0;
            printf("Type the id of the person record you want to delete\n");
            scanf("%d", &delete);
            for (j=0; j < count; j++)       
            {
                if (delete == studentAddress[j].id)     
                {
                    strcpy(studentAddress[j].name, " ");
                    strcpy(studentAddress[j].address, " ");
                    studentAddress[j].id = 0;
                    studentAddress[j].status = 0;
                    flag = 1;
                }                   
            }
            if(flag==0)
                printf("id not in the list ...\n");
            else
                printf("Deletion successful ...\n");

            printf("\n");
            break;

        case 4:   
            flag=0;
            char deletChar[100];
            printf("Type the name of the person record you want to delete\n");
            fflush(stdin);
            gets(deletChar);
            fflush(stdin);
            for (j=0; j < count; j++)       
            {
                if (strcmp(deletChar, studentAddress[j].name)==0)   
                {
                    flag = 1;
                    strcpy(studentAddress[j].name, " ");
                    strcpy(studentAddress[j].address, " ");
                    studentAddress[j].id = 0;
                    studentAddress[j].status = 0;
                    flag = 1;
                }                   
            }
            if(flag==0)
                printf("name not in the list ...\n");
            else
                printf("Deletion successful ...\n");

            printf("\n");
            break; 

                return 0;
        case 5:     

                return 0;
    }
}
return 0;
}

I try running this code and get the error on line 68 and similar on line 95

subscript of pointer to incomplete type 'struct subject'
                                        gets(studentAddress[count].enrol[subjectCounter].subjectID);

plus I get this note (from the compiler) below the error

forward declaration of 'struct subject' struct subject *enrol;

My tutor and lecture have both tried helping me, but they have had no success. They are like most of my code looks correct, but it will not work. Sorry I am new to stack overflow so if you want me to add more information please let me know.

  • 2
    There is no `struct subject` defined in your code, only a `typedef` of an anonymous `struct` to `subject` (without the `struct` before it) – UnholySheep May 26 '20 at 07:58
  • @UnholySheep wait so something like `typedef struct subject{}subject;`? –  May 26 '20 at 08:03
  • Yes, that would be the common idiom (as described here: https://stackoverflow.com/a/1675446/2878796) – UnholySheep May 26 '20 at 08:04
  • @UnholySheep my goodness the error is gone, thank you so much. Also any tips on why their is a segmentation fault? –  May 26 '20 at 08:05
  • Sorry, I did not look at the code beyond the compiler error. If you get a new problem you should open another question and reduce the code to a [mcve] (currently there is too much code to pinpoint the exact issue) – UnholySheep May 26 '20 at 08:08
  • Although the line `studentAddress->enrol = NULL;` is most certainly wrong, you are dereferencing a nullpointer (`studentAddress`) here – UnholySheep May 26 '20 at 08:09
  • 1
    The overall structure of your program is terrible. You absolutely need to decompose it into smaller functions. And `fflush(stdin)` is UB, and [never ever use `gets`](https://stackoverflow.com/q/1694036/898348). – Jabberwocky May 26 '20 at 08:12
  • Just so you know, your way of using gets to get the student name, address, and such is going to allow the program to possibly crash due to corrupted memory if the user enters a string that is too long for the variable. A better solution for the reads from the user might be to always read into a really large buffer that it would be unlikely that a user would type that many characters or use some other function that limited the characters read. I usually just declare the buffer as 1024 or 8192 bytes long and figure that will work for most casual entry mistakes. – Grumpy OldMan May 26 '20 at 08:12
  • 1
    Ouch!! `studentAddress->enrol = NULL;` after `studentAddress = NULL;`?? (you cannot derefernce a `NULL` pointer...) `studentAddress` is `NULL`, so `studentAddress->enrol` is *Undefined Behavior* (and a likely SegFault) – David C. Rankin May 26 '20 at 08:17
  • strongly suggest 1) forget you ever heard of the function: `gets()` as it is nolonger part of the c language. 2) use something like: `fgets()` which avoid the perils of `gets()`, however, has a different parameter list, so read the MAN page before using. Especially note that `fgets()` wlll include the trailing '\n' so need to remove that with something similar to: `buffer[ strcspn( buffer, "\n" ) ] = '\0';` – user3629249 May 27 '20 at 16:11

1 Answers1

0

The easiest way to solve this is to create a function.

struct student* allocate_student() {
     struct subject* new_subject = allocate_subject();
     struct student* new_struct = malloc(sizeof(struct student));
     // initialize all fields, which will eventually include
     new_struct->enrol = new_subject;
     return new_struct;
}

This code fails to check for any error conditions. You should add that. In addition, allocate_subject() is also not defined. Considering the offered example, odds are good you can figure out how to write allocate_subject().

If you add in parameters, allocate_student() might be a bad method name. With enough parameters to construct any student, you might want to call it construct_student(...)

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138