Представление данных в файле отличается от представления данных в памяти.
Хотя, например, значение int
в памяти состоит из точного фиксированного количества байтов (обычно четыре на современном оборудовании), числа в тексте состоят из переменной серии байтов. Кроме того, значения байтов не совпадают.
885487
в текстовом файле состоит из байтов 0x38 0x38 0x35 0x34 0x38 0x37
, тогда как то же число в памяти (предоставляется 32-битное int) выглядит как 0xEF 0x82 0x0D 0x00
(представление с прямым порядком байтов!).
Размеры других элементов также не совпадают, кроме того, между элементами двоичных данных не будет пробела (0x20).
Для иллюстрации: Данные внутри s
после первого звонка на fread(&s, sizeof(struct student), 1, pointer_to_file)
:
name == "Marcos David 885487 9.4 5.4 8." // you read EXACTLY 30 chars
cod_student == 170 926 133 // "5 0\n" interpreted as 32-bit int (little endian)
test_1 == <some value> // "Vict" interpreted as 32-bit float
test_2 == <some value> // "or C" interpreted as 32-bit float
activity == <some value> // "orle" interpreted as 32-bit float
test_optional == <some value> // "one " interpreted as 32-bit float
Я не прилагал усилий для преобразования символов в фактические значения с плавающей запятой, предположим, что довольно очевидно, что значения не будут теми, которые вы действительно хотели иметь ... Я предполагал, что окончания строки unix - если вы используете windows, то перед \n
будет дополнительный символ \r
, смещающий символы, используемые для заполнения поплавков, на 1, но этого не произойдет. изменить что-либо при чтении ненужных данных.
Теперь у вас есть два варианта:
Либо вы сохраняете учеников уже в двоичном формате (во время записи откройте файл с опцией "wb"
, для чтения используйте "rb"
, чтобы не допустить специальной обработки разрывов строк). Имейте в виду, что файл больше не будет доступен для чтения человеком!
Или вам нужно преобразовать текстовые данные в двоичные.
Для последнего варианта я лично прочитал бы файл построчно (C: fgets ; C ++: std :: getline ) и проанализировал бы эти строки самостоятельно.
Вы оказались в неудачной ситуации, когда вы выбрали символ-разделитель для элементов данных, которые также могут встречаться в одном из полей данных: пробел. Если вы измените разделитель полей на что-то другое (например, |
- также есть специальные символы-разделители, ASCII 0x1 C - 0x1F, идеально подходит для наших целей при чтении, но их сложно ввести в текстовом редакторе ...) , тогда вы значительно упростите себе жизнь: просто выделите строку этим символом-разделителем и преобразуйте подстроки.
На данный момент вы должны искать в строке первое di git (при условии, что цифры не встречается в имени) и скопируйте символы перед (за исключением последнего пробела) в поле имени. Не забудьте завершить строку нулевым символом.
С этого момента вы можете просто токенизировать, начиная с di git, найденного ранее. В C посмотрите на функцию strtok для токенизации и на strtol и strtof для преобразования.
В C ++ (как вы помечен изначально), существует множество различных способов обработки оставшейся строки (возможно, самый простой способ - использовать std::istringstream
).