Массив с двойным указателем в куче кодируется как одиночный указатель для записи в файл.

У меня есть массив, который уже находится в куче (динамической) памяти. Это не очень сложно понять, но записать его в файл с помощью функции fwrite() может быть немного сложно понять, если это также двойной указатель, как я вижу в Интернете, что я не понимаю с точки зрения логики, что это то, что я пытаюсь прояснить здесь.

int ** A;
A = new int* [randomSize];
A[0] = new int [randomSize];

Например, одиночный указатель на fwrite() будет выглядеть так:

fwrite(&A[0], sizeof(teststruct), 54, dogfile);

Итак, если массив с одним указателем выглядит так в функции fwrite(), я думаю, что логика массива с двойным указателем должна выглядеть примерно так:

fwrite(&A[0][0], sizeof(teststruct), 54, dogfile);

Вот как я это понимаю, исходя из логики работы функции fwrite().

Однако я видел в Интернете двойной указатель, используемый с fwrite() для печати в файл с одним массивом блоков (A[0]), а не с массивом двойных блоков (A[0][0]). Это выглядело как:

fwrite(A[0], sizeof(teststruct), 54, dogfile);

Может ли кто-нибудь, кто разбирается в этом, объяснить мне логику этого, пожалуйста?

В данном случае A[0] — это указатель, потому что у вас есть массив указателей.

Retired Ninja 14.02.2023 20:40
&A[0] — это то же самое, что и A в большинстве контекстов. Следовательно, &A[0][0] совпадает с A[0].
n. m. 14.02.2023 20:46
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы
HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!
Современный фронтенд похож на старую добрую веб-разработку, но с одной загвоздкой: страница в браузере так же сложна, как и бэкенд.
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
HTML предоставляет множество тегов для структурирования и организации содержимого веб-страницы. Одним из наиболее часто используемых тегов для...
0
2
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Fwrite() хочет указатель на (адрес) записываемых данных.

В этом коде:

int A[size];

A — это массив значений int:

     [0] [1] [2] [...]
    +---+---+---+-----+
A = | x | x | x | ... |
    +---+---+---+-----+

Итак, этот код будет работать:

fwrite(&A[0], sizeof(int), size, dogfile);

Как и этот код:

fwrite(A, sizeof(int), size, dogfile);

Потому что ссылка на фиксированный массив только по его имени даст (т.е. он распадается на) указатель на его 1-й элемент в различных контекстах, например, в параметре функции или присваивании переменной.

       [0] [1] [2] [...]
      +---+---+---+-----+
  A = | x | x | x | ... |
      +---+---+---+-----+
        ^
        |
fwrite(buffer, ...)

Теперь в вашем коде:

int ** A;
A = new int* [randomSize];
A[0] = new int [randomSize];

Это создает массив указателей int*, где каждый int* указывает на свой собственный массив значений int:

     [0] [1] [2] [...]
    +---+---+---+-----+
A = | x | x | x | ... |
    +---+---+---+-----+
      |   |   |           [0] [1] [2] [...]
      |   |   |          +---+---+---+-----+
      +---|---|--------> | x | x | x | ... |
          |   |          +---+---+---+-----+
          |   |
          |   |           [0] [1] [2] [...] 
          |   |          +---+---+---+-----+
          +---|--------> | x | x | x | ... |
              |          +---+---+---+-----+
              |
              |           [0] [1] [2] [...]
              |          +---+---+---+-----+
              +--------> | x | x | x | ... |
                         +---+---+---+-----+

Где:

  • A[0] — это 1-й int* в этом массиве, а &A[0] — указатель на этот int*
  • A[0][0] — это 1-й int, на который указывает 1-й int* в A, а &A[0][0] — указатель на этот int
  • И так далее...

fwrite(&A[0], sizeof(int), randomSize, dogfile);

Вы будете писать мусор в файл, потому что A — это массив int* указателей, и вы записываете значения самих этих указателей, а не значения int, на которые они указывают.

     [0] [1] [2] [...]
    +---+---+---+-----+
A = | x | x | x | ... |
    +---+---+---+-----+
     ^ |                  [0] [1] [2] [...]
     | |                 +---+---+---+-----+
     | +---------------> | x | x | x | ... |
     |                   +---+---+---+-----+
     +---+
         |
fwrite(buffer, ...)

Однако этот код работает:

fwrite(A[0], sizeof(int), randomSize, dogfile);

Потому что A[0] — это указатель на 1-й int в другом массиве.

     [0] [1] [2] [...]
    +---+---+---+-----+
A = | x | x | x | ... |
    +---+---+---+-----+
       |                  [0] [1] [2] [...]
       |                 +---+---+---+-----+
       +---------------> | x | x | x | ... |
                         +---+---+---+-----+
                           ^
                           |
         +-----------------+
         |
fwrite(buffer, ...)


1: то есть взять начальный адрес Array, увеличить его на Index количество элементов (то есть на Index умножить на sizeof(element type) количество байтов), а затем разыменовать его для доступа к элементу по этому адресу.

2: означает взять начальный адрес Array, увеличить его на Index количество элементов, разыменовать его для доступа к элементу, а затем взять адрес этого элемента.

Другие вопросы по теме