Почему двоичное сохранение массива в файл работает? [C ++] - PullRequest
1 голос
/ 04 февраля 2011

C ++ новичок здесь.

Я пытаюсь выяснить следующую строку, которая записывает буфер в файл:

fOut.write((char *)&_data, sizeof(_data));

_data = массив целых чисел ...

У меня есть пара вопросов:

  1. Является ли &_data адресом первого элемента массива?
  2. Какой бы это ни был адрес, означает ли это, что мы сохраняем только адрес массива? тогда почему я все еще могу получить доступ к массиву после его освобождения?
  3. Разве я не должен пройти sizeof(_data)*arrLength? что означает передача размера int (в данном случае), а не размера всего массива?
  4. Что означает приведение к char* при работе с адресами?

Буду очень признателен за разъяснения.

Ответы [ 6 ]

6 голосов
/ 04 февраля 2011

Вопреки вашему комментарию, для работы sizeof массив должен иметь автоматическую или статическую продолжительность хранения.

  1. Это должно быть просто (char*)_data. Имя массива неявно преобразуется в указатель на первый элемент.

  2. Нет, write ожидает указатель и сохраняет содержимое, найденное в этом месте, а не адрес местоположения.

  3. Нет. Поскольку _data является массивом, sizeof (_data) является совокупным размером всех элементов в массиве. Если бы _data был указателем (например, когда массив динамически размещается в куче), вы бы хотели numElems * sizeof(_data[0]). Умножение размера указателя на количество элементов не помогает.

  4. Это означает, что содержимое по этому адресу будет обрабатываться как последовательность отдельных байтов, теряя любое числовое значение, которое оно могло иметь. Это часто делается для эффективного массового копирования данных в файл и из файла или с помощью memcpy / memmove. Тип данных должен быть POD (обычные старые данные), иначе вы получите неожиданные результаты.

Если _data - это указатель на массив, выделенный из кучи, как подсказывает ваш комментарий, то код сильно нарушен. В этом случае вы сохраняете только адрес, и он может работать, если вы загрузите файл обратно в тот же экземпляр вашей программы, но это только потому, что он находит данные, все еще находящиеся в памяти по тому же адресу. На самом деле данные не будут в файле, и если вы перезапустите программу перед загрузкой файла, вы обнаружите, что данные пропали. Внесите изменения, о которых я упоминал в (1) и (3), чтобы сохранить весь массив независимо от того, выделен он автоматически, статически или динамически.

1 голос
/ 04 февраля 2011

Что означает приведение в char * при работе с адресами?

Вообразите этот простой пример

int x = 12;
char * z = (char *)&x;

И предположим, что архитектура int имеет длину 4 байта. Из стандарта C ++ sizeof(char)==1.

По выражению char * z части char * можно сказать, что оно используется для арифметики указателей

Во второй строке примера, который я привел, получается, что z теперь указывает на первое (из 4 байтов), которое имеет x. Выполнение ++z; сделает z указателем на второй байт (в моем примере) 4 байта int

Можно сказать, что левая часть объявления используется для арифметики указателей, чтобы упростить вещи. ++(char *) переместит вас на один байт, а ++(int *) переместит вас на соответствующее количество байтов int занимает в памяти.

0 голосов
/ 04 февраля 2011

прочитайте это: http://www.cplusplus.com/reference/iostream/ostream/write/

  1. должно быть.
  2. если вы вызываете "fstream.write (a, b)", тогда он записывает b байтов, начиная с местоположения a вфайл (то есть, на что указывает адрес);
  3. это должен быть размер в байтах или символах.
  4. не очень, похоже на приведение материала к byte [] в более цивилизованных языках.

Кстати, он будет работать только с простыми массивами с простыми значениями внутри них ...

Предлагаю заглянуть в операторы >> <<. </strong>

0 голосов
/ 04 февраля 2011

1) Да, & _data - это адрес первого элемента вашего массива.
2) Нет, write () записывает число байтов, указанное вами в sizeof (_data), начиная с адреса & _data
3)Вы бы передали sizeof (int) * arrLength, если _data является указателем на массив, но, поскольку он равен , sizeof () возвращает правильный размер.
4) donне знаю;)

0 голосов
/ 04 февраля 2011

является & _data адресом первого элемента массива?

Да, это так. Это обычный способ передачи «ссылки» на массив в C и C ++.Если вы передадите сам массив в качестве параметра, будет скопировано все содержимое массива, что обычно является расточительным и ненужным. Исправление: Вы можете передать либо &_data, либо просто _data.В любом случае массив не нужно копировать в стек.

независимо от того, какой это адрес, означает ли это, что мы сохраняем только адрес массива?тогда почему я все еще могу получить доступ к массиву после удаления его из памяти?

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

Разве я не должен передавать sizeof (_data) * arrLength?Я имею в виду ... какова логика передачи размера int (в данном случае), а не размера всего массива?

Нет, sizeof(_data) - это размер массива,не одного члена.Нет необходимости умножать на длину.

Что означает приведение к char * при работе с адресами?

Приведение к char * означает, что массив доступен как списокбайтов;это необходимо для доступа и записи необработанных значений.

0 голосов
/ 04 февраля 2011
  1. Да
  2. Нет, запись использует этот адрес в качестве первого местоположения и считывает sizeof (_data), записывая весь массив
  3. sizeof (_data) возвращает размервесь массив не совпадает с sizeof (int)
  4. Означает, что данные будут считываться побайтово, это указатель, необходимый для записи при записи в двоичном формате (побайтно)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...