Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.06.2022, 22:39   #1
xelio
Новичок
Джуниор
 
Регистрация: 16.06.2022
Сообщений: 4
По умолчанию Очистка памяти и контроль входных данных(язык Си)

Добрый вечер уважаемые форумчане! Может кто помочь с задачкой. В коде есть очистка памяти Free. Но мне говорят,что её нет,и нет контроля входных данных,как правильно очищать память при выполнении и реализовать контроль входных данных?
Условие задачи Используя процедуры и описания модуля типа данных, разработать программу, обеспечивающую ввод исходных данных из первого файла данных в память и хранение их в памяти в виде связного списка, сортировку списка по алфавитному и по числовому параметру.
По поводу ввода данных я так понимаю, нужно предусмотреть проверку данных, чтобы пользователь не ввёл например в числовое поле текстовое значение.
А очистку делать через fflush,но не знаю как это реализовать.Буду благодарен за помощь.
Код:
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#include <conio.h>
#include <stdio.h >
#include <stdlib.h>
#include <math.h>
#include <locale.h>
#include <string.h>
 
#define collective_farm struct _cf
 
#pragma
 
int f_print();
int f_input();
int f_add();
int f_delete();
int f_change();
int f_sort();
int f_save();
int f_restore();
 
collective_farm{
   char title[30]; /* Название */
   char fullname[25]; /* Имя работника */
   int squad; /* Бригада */
   char job_type[15]; /* Вид работ */
   float salary; /* Заработок */
   collective_farm* next; /* Указатель на следующий элемент */
};
collective_farm* collective_farm_fp = NULL; /* Начало списка */
char fname[] = "collective_farm.DAT"; /* Файл для хранения списка */
 
int main( void ) {
  char eoj; /* Флаг окончания работы */
  setlocale(LC_ALL, "");
  f_restore();
  int key = 1;
 
  while (key != 0) {
    printf("1. Вывод\n");
    printf("2. Ввод\n");
    printf("3. Добавить\n");
    printf("4. Удалить\n");
    printf("5. Изменить\n");
    printf("6. Сортировать\n");
    printf("7. Числовая сортировка \n");
    printf("8. Сохранить\n");
    printf("9. Восстановить\n");
    printf("0. Выйти\n");
    printf("Выберите пункт меню:");
    scanf("%d%", &key);
    switch (key)
    {
    case 1: {
      f_print();
      break;
    }
    case 2: {
      f_input();
      break;
    }
    case 3: {
      f_add();
      break;
    }
    case 4: {
      f_delete();
      break;
    }
    case 5: {
      f_change();
      break;
    }
    case 6: {
      f_sort();
      break;
    }
    case 7: {
      f_sort();
      break;
    }
    case 8: {
      f_save();
      break;
    }
    case 9: {
      f_restore();
      break;
    }
    default:
      break;
    }
  }
}
 
int f_print() {
  collective_farm* a;
  int i, j;
 
  if (collective_farm_fp == NULL) printf("Список пуст\n");
  else {
    for (a = collective_farm_fp, i = 1, j = 1; a != NULL; a = a->next, j++, i++) {
      printf("#%-2d %-5s  %-3s  %-2d  %-2s  %.2f \n",
        i, a->title, a->fullname, a->squad, a->job_type, a->salary);
      if (j == 20) {
        printf("Нажмите любую кнопку чтобы продолжить...\n");
        _getch();
        j = 1;
      }
    }
    printf("Конец списка\n");
  }
  return 0;
}
 
int f_input() {
  int cc;
  printf("Введите название колхоза=  * - чтобы закончить ввод\n");
  /* Конец ввода - при вводе '*' вместо имени */
  while (!(cc = f_add())); /* Вызов функции добавления */
  return cc;
}
 
 
int f_add() {
  collective_farm* a = NULL, *b = NULL;
  char ss[40];
  int i = 1;
  /* Если список существует,осуществляем вставку элемента */
  if (collective_farm_fp != NULL)
    for (i++, a = collective_farm_fp; a->next != NULL; a = a->next, i++);
  /* Приглашение к вводу */
  printf("Строка #%d. Ввод: Название колхоза, ФИО, Бригада, Вид Работ, Зарплата(220,2)\n", i);
  scanf("%s", ss);
  if (ss[0] == '*') return 2;
  /* Выделение памяти под новый элемент */
  b = (collective_farm*)malloc(sizeof(collective_farm));
  strcpy(b->title, ss);
  scanf("%s %d %s %f", &(b->fullname), &(b->squad), &(b->job_type), &(b->salary));
  b->next = NULL;
 
  if (collective_farm_fp == NULL) collective_farm_fp = b;
  else a->next = b;
  return 0;
}
 
int f_save() {
  FILE* dat;
  collective_farm* a;
  dat = fopen(fname, "w"); /* Открытие файла на запись */
  /* Запись в файл осуществляется  полями */
  for (a = collective_farm_fp; a != NULL; a = a->next)
    fprintf(dat, "%s %s %d %s %f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
  /* В конце файла - спецкод '***' */
  fprintf(dat, "***\n");
  fclose(dat);        /* Закрытие файла */
  return 0;
}
 
int f_restore() {
  FILE* dat;
  char ss[40];
  collective_farm* a = NULL, *b = NULL;
  /* Открытие файла для чтения,если файл не найден-вывод
     соответствующего сообщения */
  if ((dat = fopen(fname, "r")) == NULL) {
    printf("Файл не найден: %s\n", fname);
    return 1;
  }
  else {
    collective_farm_fp = NULL;
    do {
      /* Чтение из файла по полям пока не дошли до
         спецкода '* '*/
      fscanf(dat, "%s", ss);
      if (ss[0] != '*') {
        /* Выделение памяти под новый элемент */
        b = (collective_farm*)malloc(sizeof(collective_farm));
        if (collective_farm_fp == NULL) collective_farm_fp = b;
        else a->next = b;
        strcpy(b->title, ss);
        fscanf(dat, "%s %d %s %f\n", &(b->fullname), &(b->squad), &(b->job_type), &(b->salary));
        b->next = NULL;
        a = b;
      }
    } while (ss[0] != '*');
    fclose(dat);  /* Закрытие файла */
  }
  return 0;
}
 
int f_sort() {
  int n;
  collective_farm* a = NULL, *b = NULL, *c = NULL;
  /* Если список пустой или в нем один элемент,
     то выход из функции */
  if ((collective_farm_fp == NULL) || (collective_farm_fp->next == NULL)) return 0;
  /* Сортировка списка методом "пузырька" */
  for (n = 1; n; ) {
    n = 0;
    for (a = collective_farm_fp, b = collective_farm_fp->next; b != NULL; )
      if (strcmp(a->fullname, b->fullname) > 0) {
        a->next = b->next; b->next = a;
        if (a == collective_farm_fp) collective_farm_fp = b;
        else c->next = b;
        c = b; b = a->next;
        n = 1;
      }
      else {
        c = a; a = b; b = b->next;
      }
  }
  return 0;
}
 
int f_sort_int() {
  int n;
  collective_farm* a = NULL, *b = NULL, *c = NULL;
  /* Если список пустой или в нем один элемент,
     то выход из функции */
  if ((collective_farm_fp == NULL) || (collective_farm_fp->next == NULL)) return 0;
  /* Сортировка списка методом "пузырька" */
  for (n = 1; n; ) {
    n = 0;
    for (a = collective_farm_fp, b = collective_farm_fp->next; b != NULL; )
      if (a->salary > b->salary) {
        a->next = b->next; b->next = a;
        if (a == collective_farm_fp) collective_farm_fp = b;
        else c->next = b;
        c = b; b = a->next;
        n = 1;
      }
      else {
        c = a; a = b; b = b->next;
      }
  }
  return 0;
}
 
int get_ln() {
  int ln;
  printf("Введите номер строки: ");
  do {
 
    scanf("%d", &ln);
    if (ln < 1) {
      printf("Неверный номер строки, попробуйте ещё раз:");
      ln = 0;
    }
  } while (!ln);
  return ln;
}
 
int f_delete() {
  int ln;
  collective_farm* a, *b;
  /* Если списка нет в памяти,то вывод соотвтствуюшего
   сообщения */
  if (collective_farm_fp == NULL) printf("List empty\n");
  /* Иначе-ввод номера элемента с помощью функции GET_LN */
  else {
    ln = get_ln() - 1;
    if (!ln) {
      /*  Если номер корректен - переприсваивание указателей
          и освобождение памяти */
      a = collective_farm_fp; collective_farm_fp = a->next; free(a);
    }
    else {
      for (ln--, a = collective_farm_fp; ln && (a != NULL); a = a->next, ln--);
      if (a != NULL)
        if ((b = a->next) != NULL) {
          a->next = b->next; free(b);
        }
    }
  }
  return 0;
}
 

 
}
xelio вне форума Ответить с цитированием
Старый 17.06.2022, 00:43   #2
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

1 Функция main(), строки
Код:
    case 6: {
      f_sort();
      break;
    }
    case 7: {
      f_sort();
      break;
    }
Зачем вам 2 пункта меню, если вы не различаете вызов одной и той же функции. Хотя функция f_sort_int() вообще не вызывается.
2) функция f_restore(), строка
Код:
collective_farm_fp = NULL;
Она конечно вызывается 1 раз на входе, но разве стоит так делать не освободив уже выделенную память.
3) Функция f_add(), строка
Код:
collective_farm* a = NULL, *b = NULL;
Если инициализируете переменную a, тогда зачем присваивать NULL, чтобы дополнительно проверять. Просто присвойте ей значение collective_farm_fp
Код:
collective_farm* a = collective_farm_fp, *b = NULL;
/* ... */
if (a != NULL)
 for (i = 1; /* ... */
/* ... */
  if (collective_farm_fp == NULL) collective_farm_fp = b; /* а это уже не трогаем */
  else a->next = b;
4) Функция f_save(), строки
Код:
  for (a = collective_farm_fp; a != NULL; a = a->next)
    fprintf(dat, "%s %s %d %s %f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
При вводе в строке title, filename или job_type пробела пользователем у вас будет нарушена структура файла.
4.1) Функция f_restore(), строки
Код:
      fscanf(dat, "%s", ss);
      if (ss[0] != '*') {
        fscanf(dat, "%s %d %s %f\n", &(b->fullname), &(b->squad), &(b->job_type), &(b->salary));
После сохранения в файл через
Код:
fprintf(dat, "%s %s %d %s %f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
вы получите строку вида
Цитата:
Светлый путь Петров Иван Игоревич 1 высадка картошки 220.25
и прочитаете ее так
Код:
title = "Светлый"
fullname = "путь"
squad = ? /* Ошибка перевода строки в число */
job_type = ?
salary = ?
Хотя и при вводе данных возникнут проблемы.
Мораль. Нужен контроль вводимых пользователем значений и использование других функций сохранения и загрузки значений в файл хранения базы данных
На сегодня все. Пока надоело разбираться в коде.

Последний раз редактировалось macomics; 17.06.2022 в 00:56.
macomics вне форума Ответить с цитированием
Старый 17.06.2022, 12:23   #3
xelio
Новичок
Джуниор
 
Регистрация: 16.06.2022
Сообщений: 4
По умолчанию

Цитата:
Сообщение от macomics Посмотреть сообщение
1 Функция main(), строки
Код:
    case 6: {
      f_sort();
      break;
    }
    case 7: {
      f_sort();
      break;
    }
Зачем вам 2 пункта меню, если вы не различаете вызов одной и той же функции. Хотя функция f_sort_int() вообще не вызывается.
2) функция f_restore(), строка
Код:
collective_farm_fp = NULL;
Она конечно вызывается 1 раз на входе, но разве стоит так делать не освободив уже выделенную память.
3) Функция f_add(), строка
Код:
collective_farm* a = NULL, *b = NULL;
Если инициализируете переменную a, тогда зачем присваивать NULL, чтобы дополнительно проверять. Просто присвойте ей значение collective_farm_fp
Код:
collective_farm* a = collective_farm_fp, *b = NULL;
/* ... */
if (a != NULL)
 for (i = 1; /* ... */
/* ... */
  if (collective_farm_fp == NULL) collective_farm_fp = b; /* а это уже не трогаем */
  else a->next = b;
4) Функция f_save(), строки
Код:
  for (a = collective_farm_fp; a != NULL; a = a->next)
    fprintf(dat, "%s %s %d %s %f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
При вводе в строке title, filename или job_type пробела пользователем у вас будет нарушена структура файла.
4.1) Функция f_restore(), строки
Код:
      fscanf(dat, "%s", ss);
      if (ss[0] != '*') {
        fscanf(dat, "%s %d %s %f\n", &(b->fullname), &(b->squad), &(b->job_type), &(b->salary));
После сохранения в файл через
Код:
fprintf(dat, "%s %s %d %s %f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
вы получите строку видаи прочитаете ее так
Код:
title = "Светлый"
fullname = "путь"
squad = ? /* Ошибка перевода строки в число */
job_type = ?
salary = ?
Хотя и при вводе данных возникнут проблемы.
Мораль. Нужен контроль вводимых пользователем значений и использование других функций сохранения и загрузки значений в файл хранения базы данных
На сегодня все. Пока надоело разбираться в коде.
По поводу функции да,незаметил ошибку что нужно f_sort_int. Спасибо вам. Про контроль вводимых значений верно подметили,можете помочь как его реализовать? Через go to? Буду вам очень благодарен за помощь
xelio вне форума Ответить с цитированием
Старый 17.06.2022, 20:38   #4
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Для улучшения работы лучше разделить поле fullname[25] на 3: fname[16], sname[16], tname[16]. Это несколько упростит задачу ввода полного имени (через scaf).

По хорошему вам надо считывать файл построчно и выполнять разбор структуры вручную.
Для этого стоит использовать функции gets(char *, int, FILE *), которая считывает заданное число символов из файла или до конца строки. Для этого надо прикинуть приблизительный размер одной записи в файле
Код:
/*
  title=30;
  fullname=25;
  squad=не более 11 символов со знаком;
  job_type=15;
  salary=количество цифр в целой части + 3 или 5 (точка и 2 или 4 цифры после нее);
  символы конца строки и завершающий NULL = 3;
  итого получаем 30 + 1 + 25 + 1 + 11 + 1 + 15 + 11 + 5 + 3 = 103 (126 для записи с fname, sname, tname)

Для загрузки из файла стоит читать строку целиком. Дальше можно действовать по разному
  Вариант 1. Дополнить каждую подстроку до ее максимальной длины перед записью в файл. Тогда нахождение значения подстроки будет привязано к индексам в считанной строке
*/
  int i;
  char buffer[103], temp[20];
  fgets(buffer, 103, input_file);
  if buffer[0] != "*" { /* Для примера разбираю вручную строку считанную из файла */
    for (i = 0; i < 30 && buffer[i] != '#'; i++) a->title[i] = buffer[i];
    for (i = 0; i < 25 && buffer[31 + i] != '#'; i++) a->fullname[i] = buffer[31 + i];
    for (i = 0; i < 11 && buffer[57 + i] != '#'; i++) temp[i] = buffer[57 + i];
    temp[i] = 0;
    a->squad = atoi(temp); /* Функция преобразует строку в целое число */
    for (i = 0; i < 15 && buffer[69 + i] != '#'; i++) a->job_type[i] = buffer[69 + i];
    for (i = 0; i < 16 && buffer[85 + i] != '#'; i++) temp[i] = buffer[85 + i];
    temp[i] = 0;
    a->salary = atof(temp); /* Функция преобразует строку в вещественное число */
  }

/*Для сохранения данных необходимо можно и дальше использовать fprintf, но тогда надо изменить шаблоны*/

  int i, l;
  char temp0[31], temp1[26], temp2[12], temp3[16];
  l = strlen(a->title);
  for (i = 0; i < 30; i++) if (i < l) { temp0[i] = a->title[i]; } else { temp0[i] = '#' }
  temp[i] = 0;
  l = strlen(a->fullname);
  for (i = 0; i < 30; i++) if (i < l) { temp1[i] = a->fullname[i]; } else { temp1[i] = '#' }
  temp1[i] = 0;
  itoa(a->squad, temp2);
  for (i = strlen(temp2); i < 11; i++) temp2[i] = '#'
  temp2[i] = 0;
  l = strlen(a->job_type);
  for (i = 0; i < 15; i++) if (i < l) { temp3[i] = a->job_type[i]; } else { temp3[i] = '#' }
  temp3[i] = 0;
  fprintf(output_file, "%s#%s#%s#%s#%.4f", temp0, temp1, temp2, temp3, a->salary);

/* Вариант 2. Использовать для хранения значений в файле более сложную структуру. Например: Для каждого поля структуры использовать свою собственную строку

Тогда для чтения надо: */
  char temp[30];
  fgets(temp, 30, input_file);
  if (temp[0] != '*') {
    strcpy(a->title, temp);
    fgets(a->fullname, 25, input_file);
    fgets(temp, 11, input_file);
    a->squad = atoi(temp);
    fgets(a->job_type, 15, input_file);
    fgets(temp, 30, input_file);
    a->salary = atof(temp);
  }

/* Для ввода данных так же можно использовать gets, но тогда вводить придется построчно с выводом запроса на каждую вводимую переменную */

  printf("Введите имя колхоза: ");
  gets(a->title);
  printf("Введите ФИО руководителя: ");
  gets(a->fullname);
  printf("Введите номер отряда: ");
  scanf("%d", a->squad);
  printf("Введите тип работы: ");
  gets(a->job_type);
  printf("Введите оплату: ");
  gets("%f", a->salary);

/* А для записи можно вообще обойтись одной единственной fprintf */

  fprintf(output_file, "%s\n%s\n%d\n%s\n%.4f\n", a->title, a->fullname, a->squad, a->job_type, a->salary);
Как-то так. Набирал в браузере - могут быть очепятки и неточности (не проверял).
macomics вне форума Ответить с цитированием
Старый 18.06.2022, 00:21   #5
xelio
Новичок
Джуниор
 
Регистрация: 16.06.2022
Сообщений: 4
По умолчанию

macomics, Благодарю вас за ответ,ваш вариант конечно лучше! У меня накручено всё. Не знаю как сделать проверку на вводимые данные,поможете с этим вопросом?
xelio вне форума Ответить с цитированием
Старый 18.06.2022, 01:34   #6
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Если вы хотите контролировать количество вводимых символов для строк, то можно сделать так
Код:
  int i;
  char c;
  fgets(a->title, 30, stdin);
/* После ввода с помощью этой функции надо будет еще убрать в конце введенного перевод строки */
  for (i = 0; i < 30 && a->title[i] != '\n'; i++);
  if (i < 30)
  {
    a->title[i] = 0;
  } else {
/* Вывод сообщения об ошибке ввода и завершение */
  }
/* Так вы не выйдете за конец строки в случае ввода слишком длинного текста */
  fgets(a->fullname, 25, stdin);
  for (i = 0; i < 25 && a->fullname[i] != '\n'; i++);
  if (i < 25)
  {
    a->fullname[i] = 0;
  } else {
/* Вывод сообщения об ошибке ввода и завершение */
  }
/* Контроль ввода чисел придется делать вводя значения по символам
Так пользователь просто не сможет ввести символы отличные от ведущего знака - и цифр */
  c = _getch();
  if (c == '-')
  {
    putchar(c);
    a->squad = -1;
  } else {
    a->squad = 1;
  }
  unsigned int v = 0;
  do
  {
    if (c >= '0' && c <= '9')
    {
      v = v * 10 + c - '0';
      putchar(c);
    }
    c = _getch();
  } while (c != '\n' || c != '\r' || v < 0x7FFFFFFF);
/* введенное число должно помещаться в переменной */
  if (v < 0x7FFFFFFF)
  {
    a->squad *= v;
  } else {
/* Вывод сообщения об ошибке ввода и завершение */
  }
/* и так далее */

Последний раз редактировалось macomics; 18.06.2022 в 01:37.
macomics вне форума Ответить с цитированием
Старый 19.06.2022, 23:37   #7
xelio
Новичок
Джуниор
 
Регистрация: 16.06.2022
Сообщений: 4
По умолчанию

macomics,
Вы ггений! Спасибо вам за помощь,заметил,что у меня с сортировкой беда,одна есть f_sort,а вторая f_sort_int явно не числовая,поможете набросать простенький вариант числовой сортировки для данной задачки? Спасибо!
xelio вне форума Ответить с цитированием
Старый 20.06.2022, 00:13   #8
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Для сортировки данных в виде списков лучше использовать двусвязные списки. Иначе ничего кроме простых сортировок типа сортировки перестановкой или выбором не реализовать (без кучи дополнительных манипуляций, которые сведут весь профит от этих сортировок на нет).
Код:
// Сортировка перестановкой (пузырьком, самая базовая)
if (collective_farm_fp != NULL && collective_farm_fp->next != NULL) // Сортируем, если больше 2-х элементов
  for (a = 1, b = collective_farm_fp; a != 0 && b->next != NULL; b = b->next) // Внешний цикл до последнего элемента
    a = 0;
    for (c = &collective_farm_fp, d = collective_farm_fp; d->next->next != NULL; c = d, d = d->next) // Внутренний цикл (от начального элемента, до предпоследнего)
      if (d->salary > d->next->salary) { // Проверка условия перестановки (по возрастанию)
// Перестановка элементов
        a = NULL != (c->next = d->next);
        d->next = d->next->next;
        c->next->next = d;
      }

Последний раз редактировалось macomics; 20.06.2022 в 09:01.
macomics вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
очистка памяти Kukurudza Общие вопросы C/C++ 1 30.07.2012 11:34
Контроль памяти FW-TOT Помощь студентам 2 15.11.2008 14:04
Очистка памяти Senator Общие вопросы Delphi 1 28.06.2008 19:39
Очистка памяти в C# darkstarx Общие вопросы .NET 1 14.04.2008 14:48