-2

I'm a student I want to ask if it is possible in array to add continuously,

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

typedef struct
{
    int dd;
    int mm;
    int yy;
}DATE;

typedef struct
{
    char name[20];
    int ID;
    DATE DOB;
    char course[20];
    int yrlvl;
}Student;

int main()
{
    Main_Actions();
    return 0;
}

void Main_Actions()
{
    char  *arr_Actions[] = {"default","Add Student","Edit Student Information","View all Records","Search Student","Exit","\0"};
    int choice_Actions;
    int loop_Actions;
    printf("\n ========= Actions =========\n");
    for(loop_Actions = 1; loop_Actions < 6; loop_Actions++)
    {
        printf("[%d]\t",loop_Actions);
        printf(arr_Actions[loop_Actions]);
        printf("\n");
    }
        printf("==============================");
        printf("\n Choice: ");
        scanf("%d",&choice_Actions);

    switch(choice_Actions)
    {
        case 1:
            Add_Student();
        break;
        default:
            printf("\n Invalid input!");
        break;
    }
}

void Add_Student()
{
    int intStudentMax;

        printf("\n Enter the number of students will be record ");
        scanf("%d",&intStudentMax);  // Number of students will be added
        system("cls");

    Student students[intStudentMax]; // Set Student using an Array

        for(int i=0; i<intStudentMax; i++) //Loop based on the User Input
        {
            printf("================================\n");
            printf("=========== STUDENT [%d]=========\n",i+1);
            printf("================================\n");

            printf("\n Student[%d] Student ID Number: ",i+1);
            scanf("%d", &students[i].ID);

            printf("\n Student[%d] Student Name: ",i+1);
            scanf("%s",&students[i].name);

            printf("\n Student[%d] Student Course: ",i+1);
            scanf("%s",&students[i].course);

            printf("\n Student[%d] Student Year Level: ",i+1);
            scanf("%d",&students[i].yrlvl);


            printf("\n Student[%d] Student Birthday: ",i+1);
            printf("\n Month: ",i);
                scanf("%d",&students[i].DOB.mm);
            printf("\n Day: ",i);
                scanf("%d",&students[i].DOB.dd);
            printf("\n Year: ",i);
                scanf("%d",&students[i].DOB.yy);
            system("cls");
        }

        for(int j = 0; j < intStudentMax; j++ )
        {
            printf("%d\t%s\t%s\t%d\n",
            students[j].ID, students[j].name, students[j].course,students[j].yrlvl);
        }
        Main_Actions();
}

This is my scenario for example (Adding Students) I want to add 5 Students and then input the needed details and save them in an Array after the loop for 5 students it will go back to the menu screen then once the user chooses again the add students and input again another 5 students then my data in my array consist of 10 students is it possible?

JHO
  • 1
  • 1
  • 1
    Can you make the example in the question simpler? What's the smallest program that shows the part you're stuck on? (Rule of thumb: if you got an answer to that, would you be able to solve the big problem? If so, it's a suitable example.) – wizzwizz4 Sep 28 '22 at 12:08
  • 2
    No. An array can't change size. Never. But.... you can use dynamic memory allocation like `realloc` and it will work just like an array – Support Ukraine Sep 28 '22 at 12:09
  • students is local to Add_Student and will disappear when you exit that function. – stark Sep 28 '22 at 12:10
  • Or you can use a linked list, if that's possible. – Zakk Sep 28 '22 at 12:10
  • You actually do not add to an array. You have a weird recursive program logic. You will actually add to another array that is not related to the array you added before. The arrays `students` in `Add_Student` are not the same between calls. – Gerhardh Sep 28 '22 at 12:10
  • 1
    `scanf("%s",&students[i].name);` should be `scanf("%s", students[i].name);` (without that `&`). – Zakk Sep 28 '22 at 12:14
  • 2
    You know C arrays use a 0-based indexing, right? – Sourav Ghosh Sep 28 '22 at 12:15
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – abdo Salm Sep 28 '22 at 19:25
  • Note that correct type for specifying array sizes and alike actually is `size_t` (from `stddef.h`). It is an unsigned type (negative sizes are meaningless anyway) and specifically defined to be of a type large enough to hold any data allocatable on your system. Similarly I'd think about other types as well, e.g. negative ids don't appear meaningful to me either, so I'd prefer an unsigned type as well to express this fact (-> self-documenting code). – Aconcagua Oct 04 '22 at 08:05

2 Answers2

2

“Is it possible...”

Yes. Of course. The trick is to use a loop. A simple one would simply ask

Do you wish to add another student (Y/N)?

after asking for the information for each student.

By the way, you have several problems:

  • Your list of students needs to be somewhere outside the Add_Student() function. Right now it is a local variable. For a program like this, it is OK to make it a global variable.

    Likewise, have a maximum number of students and a separate variable to store the current number of students in that array.

 

#define MAX_STUDENTS 100
Student students[MAX_STUDENTS];
int num_students = 0;
  • Input is a pain. I recommend you use a function to get it, and return an enum to act.

 

typedef enum { ADD_STUDENTS, EDIT_STUDENT, LIST_STUDENTS, ... } Main_Menu_Action;

Main_Menu_Action Main_Menu()
{
  printf( "%s",
    "Main Menu:\n"
    "  add  : Add students\n"
    "  edit : Edit student\n"
    etc 
    "? " );
  while (1)
  {
    char s[100] = "";
    fgets( s, sizeof(s), stdin );

    if (strcmp( s, "add\n" ) == 0) return ADD_STUDENTS;
    ...
    
    printf( "%s", "Invalid response. Try again.\n" );
  }
}
  • Your program has an infinite recursion problem. main() calls Main_Actions() which calls Add_Student() which calls Main_Actions() which calls... etc. Get it? A proper menu needs to let the functions it calls return.

 

void Main_Actions()
{
  while (1)
    switch (Main_Menu())
    {
      case ADD_STUDENT: Add_Students(); break;
      ...
      case QUIT: return;
    }
}

int main(void)
{
  Main_Actions();
  return 0;
}
  • Finally, getting a student. Put it in a loop:

 

bool Ask_YN( const char * prompt )
{
  printf( "%s (Y/N)? ", prompt );

  char s[10] = "";
  fgets( s, sizeof(s), stdin );

  if ((s[0] == 'n') || (s[0] == 'N')) return false;
  return true;
}

void Add_Students()
{
  do Add_Student();
  while (Ask_YN( "Would you like to add another student" ));
}

Notice how we make liberal use of utility functions to do stuff (especially input)? Make your life as simple as possible here.

BTW, the idea to use a list of actions is a good one. You can still do that with my suggestion. There is an idiom to do just that:

#define MAIN_ACTIONS(F) \
  F( ADD_STUDENT,   "add",  "Add students" ) \
  F( EDIT_STUDENT,  "edit", "Edit student" ) \
  F( LIST_STUDENTS, "list", "List students" ) \
  ...

#define ENUM_F(e,n,d) e,
typedef enum { MAIN_ACTIONS(ENUM_F) NUM_ACTIONS } Main_Menu_Action;
#undef ENUM_F

void Print_Main_Menu()
{
  printf( "\n ========= Actions =========\n" );
  #define PRINT_F(e,n,d) printf( "%6s : %s\n", n, d );
  MAIN_ACTIONS(PRINT_F)
  #undef PRINT_F
  printf("==============================\n Choice: ");
}

Main_Menu_Action Main_Menu()
{
  Print_Main_Menu();
  while (1)
  {
    ...
  }
}

You don’t have to use this idiom, of course. The nice thing about it is that it keeps all the definitive pieces of the actions together, instead of in several structures (an enum and an array) when then have to both be maintained separately. You could still use the array, just define and use your *_F macro properly. For example:

struct Main_Action_Info
{
  Main_Menu_Action action;
  const char * name;
  const char * description;
};
#define ARRAY_F(e,n,d) { e, n, d },
struct Main_Action_Info Main_Action_Info_Array[] =
{
  MAIN_ACTIONS(ARRAY_F)
  { NUM_ACTIONS, NULL, NULL }
};
#undef ARRAY_F
Dúthomhas
  • 8,200
  • 2
  • 17
  • 39
  • X-macro the technique/idiom is called... – Aconcagua Oct 04 '22 at 07:13
  • Just a (funny?) side note: Infinite recursion *can* work reliably *if* you absolutely can rely on tail-call-optimisation (functions need to be properly designed for – not in the mood now to analyse if the case *here*) – not that I would advocate for, of course… – Aconcagua Oct 04 '22 at 07:17
  • I'd be careful with over-stressing the helper function principle, a function consisting in nearly just calling another one doesn't really provide too much value, especially if the called one is just as simple and *not intended to be re-used* elsewhere anyway (exception: if used for providing default arguments, then especially interesting when [overloading](https://stackoverflow.com/a/25026358/1312382) involved – and maybe for aliasing one, if there's a good argument for). Too many helper functions lead to the reader hopping around in code all the time. – Aconcagua Oct 04 '22 at 07:27
  • Admitted, finding the good limit in between better splitting up or rather keep code together is not always easy – and additionally subject to personal opinion/taste as well. So don't consider my comments harsh critics, rather careful hints ;) – Aconcagua Oct 04 '22 at 07:29
0

Too long for comment – just an addition to Dúthomhas's answer:

You can even allow an unlimited number of students - well, actually limited by the number of memory your system can provide for – if you implement dynamic memory allocation; you need to additionally store how much capacity there's yet left:

Student* students;
size_t count = 0;
size_t capacity = 0;

int main(void)
{
    capacity = 128;
    students = malloc(sizeof(*students) * capacity);
    if(students) // need to test, allocation might have failed
    {
        // run main loop...

        free(students); // clean up properly!
    }
    else
    {
        // appropriate error handling, most likely just
        // printing some user information...
    }
    return 0;
}

Now if you run out of sufficient memory you just duplicate the data storage:

void add_student()
{
    if(count == capacity)
    {
        size_t c = capacity * 2; // assume we won't overflow,
                                 // especially with 64 bit size_t...
                                 // to be totally safe you might want to add a check
        Student* s = realloc(students, sizeof(*students) * c);
        // need a temporary for the case re-allocation fails, we'd lose
        // the sole pointer to original memory to clean up properly
        // (-> memory leak)
        if(s)
        {
            capacity = c;
            students = s;
        }
        else
        {
            // appropriate error handling!
            // you might exit (consider then installing an atexit handler
            // freeing the memory) or whatever else appears meaningful to you
        }
    }
    students[count] = ...;
    ++count;
}

Note that you need to add such a capacity check in your modified add_student function anyway, even if you apply the changes from the original answer only; it could then look like

// note: still an array, not the pointer as in this answer:
if(num_students == sizeof(students)/sizeof(*students))
{
    // error handling!
}
else
{
    students[num_students] = ...;
    ++num_students;
}
Aconcagua
  • 24,880
  • 4
  • 34
  • 59