Динамическое распределение и структуры - динамическое выделение памяти для строки из структуры - PullRequest
1 голос
/ 10 января 2020

У меня проблема с динамическим размещением и структурами. Задача: у меня есть структура студентов, которая выглядит следующим образом:

typedef struct{
  unsigned id;
  char *lastName;
  float grade;
}students_t;

Мне не разрешено передавать на lastName максимальное количество символов, оно должно оставаться указателем, размер которого я буду увеличивать каждый раз время.

Мой код выглядит следующим образом:

unsigned counter = 0;
students_t* students = NULL;
students_t temp;

char char_current;
unsigned char_counter=0;

while (fscanf(inputFile,"%u",&temp.id) == 1) {

    students = realloc(students,(counter+1) * sizeof(students_t));
    students[counter].id=temp.id;
    printf("%d",students[counter].id);

    students[counter].lastName = NULL;
    while (fscanf(inputFile,"%c",&char_current) != ' ') {
        students[counter].lastName = realloc(students[counter].lastName,(char_counter+1) * sizeof(char));
        students[counter].lastName[char_counter] = char_current;

        char_counter++;
    }

    students[counter].lastName[char_counter] = '\0';

    fscanf(inputFile,"%f",&students[counter].grade);


    counter++;
}

Моя проблема с fscanf из while (потому что программа вводит бесконечный l oop), но Я не знаю, как на самом деле это исправить.

Буду признателен, если кто-нибудь поможет мне разобраться. Спасибо!

1 Ответ

2 голосов
/ 10 января 2020

У вас есть несколько проблем:

  1. Оператор while () l oop не заканчивается (ваш первоначальный вопрос).
  2. fscanf () небезопасен - лучше альтернативы.
  3. Вы используете fscanf () неправильно.
  4. Чтение строки символом за раз неэффективно.
  5. Повторный вызов "reallo c ()" неэффективно - есть лучшие альтернативы.

Вот пример кода.

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

#define MAX_STRING 80

typedef struct {
   unsigned id;
   char *lastName;
   float grade;
} students_t;

students_t* enter_new_student (FILE *inputFile)
{
   char buffer[MAX_STRING];
   unsigned id;
   int iret;

   // Check for end of input
   iret = fscanf(inputFile, "%u", &id);
   if ((iret < 1) || feof(inputFile)) {  // iret should be "1" if successful
      return NULL;
   }

   // Allocate a record and read its data
   students_t *student = (students_t *)malloc(sizeof(students_t));
   iret = fscanf(inputFile, "%s %f", buffer, &student->grade); // iret should be "2" if successful
   student->id = id;
   student->lastName = strdup(buffer);   // strdup() does an implicit "malloc()" and "strcpy()"

   // Return new student
   return student;
}

int main()
{
   students_t *student = NULL;
   int record_counter = 0;
   FILE *fp;

   // Open file
   if (!(fp = fopen("tmp.txt", "r"))) {
      perror("unable to open file");
      return 1;
   }

   // Read student records
   while ((student = enter_new_student(fp))) {
      if (student) {
         ++record_counter;
         printf("new student=%s,id=%u, grade=%f, record_counter=%d\n",
            student->lastName, student->id, student->grade, record_counter);
      }
   }

   // Done
   printf("Done: final record count=%d\n", record_counter);
   return 0;
}

Вот пример файла "tmp.txt":

1 Johnson 4.0
2 Jackson 3.5
3 Jamison 3.85

И соответствующий пример вывода:

new student=Johnson,id=1, grade=4.000000, record_counter=1
new student=Jackson,id=2, grade=3.500000, record_counter=2
new student=Jamison,id=3, grade=3.850000, record_counter=3

В общем, предпочтительнее использовать fgets () over fscanf (): Недостатки scanf

Обратите внимание, что все, что связано с чтением записи ученика, находится внутри отдельной функции: enter_new_student(). Вы также заметите, что «структура управления» - «while l oop» - это OUTSIDE функции.

Есть два (связанных) условия, которые могут вызвать oop для выхода:

  1. Не прочитал "id"
  2. Конец файла

Причина вашего оригинала "пока l oop «Неудачным было то, что fscanf() никогда не вернется ' ' ... так что вы непреднамеренно закодировали« бесконечный l oop ». Вот почему:

https://linux.die.net/man/3/fscanf

Возвращаемое значение

Эти функции успешно возвращают количество элементов ввода сопоставлены и назначены, что может быть меньше предусмотренного или даже равно нулю в случае ошибки раннего сопоставления.

Значение EOF возвращается, если достигнут конец ввода перед первым успешным преобразованием или происходит сбой сопоставления. EOF также возвращается, если происходит ошибка чтения, и в этом случае устанавливается индикатор ошибки для потока (см. Ferror (3)), и устанавливается errno, указывающий ошибку.

...