Calculate the average score of groups and each student, C I have a file containing information about the session of students. The structure of this file is: group number, student name, exams, and tests.


debt() function find and print the names of underachieving students.
student_score() calculate the average score of groups
group_score() calculate the average score of each student.


So, this is my program and maybe I can make something better?

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;wchar.h&gt;
#include &lt;locale.h&gt;

#define N 50

void debt();
void student_score();
void group_score();

struct STUDENTS {
  int group;
  char name[100];
  char test[15];
  int exam;
};

struct STUDENTS student_list[N];

int main() {
  FILE *file;
  int choice;
  char buffer[200];
  int i = 0;

  file = fopen("students.txt", "r");

  if (file == NULL) {
    puts("students.txt не найден");
    return 1;
  }

  while (fgets(buffer, sizeof buffer, file) != NULL) {
    sscanf(strdup(buffer), "%d %[^0-9] %d %s", &amp;student_list[i].group, student_list[i].name, &amp;student_list[i].exam, student_list[i].test);
    i++;
  }
  fclose(file);
  int student_list_size = i;

  do {
    puts("\nВыберите номер пункта меню:");
    puts("1 - Cтуденты, имеющие задолженности");
    puts("2 – Средний балл каждого студента");
    puts("3 – Средний балл всей группы");
    puts("4 - Выход\n");

    scanf("%d", &amp;choice);

    switch (choice) {
      case 1:
        debt(student_list_size);
        break;
      case 2:
        student_score(student_list_size);
        break;
      case 3:
        group_score(student_list_size);
        break;
      case 4:
        break;
      default:
        puts("\nНужно вводить номер пункта от 1 до 4");
        break;
    }
  } while (choice != 4);

  return 0;
}

void debt(int student_list_size) {
  int counter_debt;
  wchar_t test_wchar[15];
  wchar_t * pch;

  setlocale(LC_ALL, "");

  for (int i = 0; i &lt; student_list_size; i++) {
    counter_debt = 0;
    mbstowcs(test_wchar, student_list[i].test, 15);

    pch = wcschr(test_wchar, L'н');
    while (pch != NULL) {
      counter_debt++;
      pch = wcschr(pch + 1, L'н');
    }

    if (counter_debt &gt; 0) {
      printf("%d %s: %d\n", student_list[i].group, student_list[i].name, counter_debt);
    }
  }
}

void student_score(int student_list_size) {
  int exam;
  int average;
  int digit;
  int counter_digits;

  for (int i = 0; i &lt; student_list_size; i++) {
    average = 0;
    digit = 0;
    counter_digits = 0;
    exam = student_list[i].exam;

    while (exam) {
      digit = exam % 10;
      average += digit;
      counter_digits++;
      exam = exam / 10;
    }

    printf("%d %s: %.1f\n", student_list[i].group, student_list[i].name, (double)average / counter_digits);
  }
}

void group_score(int student_list_size) {
  int exam;

  struct GROUP_SCORE {
    int group_score;
    int students_counter;
  };
  struct GROUP_SCORE group_list[5000] = {0};

  for (int i = 0; i &lt; student_list_size; i++) {
    group_list[ student_list[i].group ].students_counter += 1;
    exam = student_list[i].exam;
    while (exam) {
      group_list[ student_list[i].group ].group_score += exam % 10;
      exam = exam / 10;
    }
  }

  for (int j = 0; j &lt; 5000; j++) {
    if (group_list[j].group_score &gt; 0) {
      printf("%i: %.1f\n", j, (double)group_list[j].group_score / group_list[j].students_counter);
    }
  }
}


students.txt:

4272 Галкин Г. А. 5445 ззззз
4273 Константинопольский А. А. 4333 знзнз
4273 Курочкин А. А. 3433 знзнн
4272 Козлов И. И. 4443 ззззн
Completely prototype functions: debt() student_score() group_score();

// void debt();
void debt(int student_list_size);

Avoid naked magic numbers.  Use #define or a constant to self document various numbers.

#define TEST_N (15)
struct STUDENTS {
  ...
  char test[TEST_N];
};

void debt(int student_list_size) {
  // wchar_t test_wchar[15];
  wchar_t test_wchar[TEST_N];
  ...
  // mbstowcs(test_wchar, student_list[i].test, 15);
  mbstowcs(test_wchar, student_list[i].test, TEST_N);

Use size_t for array index types and the result of sizeof.  int may not be the right size to use as an index.  (Also i in main())

 // void student_score(int student_list_size) {
 void student_score(size_t student_list_size) {
   ...        
   // for (int i = 0; i &lt; student_list_size; i++) {
   for (size_t i = 0; i &lt; student_list_size; i++) {

Localize variables.  This approaches a style issue, but declaring variables close to their use has value.

void student_score(int student_list_size) {
  // int exam;
  // int average;
  // int digit;
  // int counter_digits;

  for (int i = 0; i &lt; student_list_size; i++) {
    int exam;
    int average;
    int digit;
    int counter_digits;

The strdup() serves no purpose.  Eliminate it.

// sscanf(strdup(buffer), "%d ...
sscanf(buffer, "%d ...

The return value of sscanf() should be checked and string widths limited.  Note: student_list[i].name will have a ' ' at the end.

// sscanf(buffer, "%d %[^0-9] %d %s", &amp;student_list[i].group, ...
if (4 != sscanf(buffer, "%d %99[^0-9] %d %14s", &amp;student_list[i].group, ...) {
   Handle_Format_Error();

Use valid main() signature.

int main() {
int main(void) {

Conversions char to/from wchar_t may need different sizes.
The extra '\n' in puts("4 - Выход\n"); looks wrong.  Guess I am not a fan of puts().  Why not use 1 function call?

fputs("\nВыберите номер пункта меню:\n"
      "1 - Cтуденты, имеющие задолженности\n"
      "2 – Средний балл каждого студента\n"
      "3 – Средний балл всей группы\n"
      "4 - Выход\n"
      "\n", stdout);