При использовании calloc в C, что хранится по адресу указателя? - PullRequest
1 голос
/ 08 декабря 2011

Мне трудно понять эту программу для иллюстрации указателей (с http://theocacao.com/document.page/234):

Ниже я не понимаю, почему:

int * currentSlot = memoryBlock

не использует &memoryBlock. Я прочитал комментарий, но не получил его. Что вставляет туда блок памяти, чего не было бы с блоком памяти? Не вернут ли оба указатель на набор целых, созданных с помощью calloc (если я понимаю, что это было сделано)? Что на самом деле в * memoryBlock после calloc?

Тогда вот, *currentSlot = rand();, как здесь работает разыменование? Я думал, что разыменование остановит * currentSlot от присвоения значения адреса памяти (ссылки) фактическому значению (больше не ссылка, а значение).

#include <stdio.h>
#include <stdlib.h> // for calloc and free
#include <time.h>   // for random seeding

main ()
{
  const int count = 10; 
  int * memoryBlock = calloc ( count, sizeof(int) );

  if ( memoryBlock == NULL )
  {
    // we can't assume the memoryBlock pointer is valid.
    // if it's NULL, something's wrong and we just exit
    return 1;
  }

  // currentSlot will hold the current "slot" in the,
  // array allowing us to move forward without losing
  // track of the beginning. Yes, C arrays are primitive
  //
  // Note we don't have to do '&memoryBlock' because
  // we don't want a pointer to a pointer. All we
  // want is a _copy_ of the same memory address

  int * currentSlot = memoryBlock;


  // seed random number so we can generate values
  srand(time(NULL));

  int i;    
  for ( i = 0; i < count; i++ )
  {
    // use the star to set the value at the slot,
    // then advance the pointer to the next slot    
    *currentSlot = rand();
    currentSlot++; 
  }

  // reset the pointer back to the beginning of the
  // memory block (slot 0)
  currentSlot = memoryBlock;

  for ( i = 0; i < count; i++ )
  {
    // use the star to get the value at this slot,
    // then advance the pointer
    printf("Value at slot %i: %i\n", i, *currentSlot);
    currentSlot++;
  }

  // we're all done with this memory block so we
  // can free it  
  free( memoryBlock );
}

Спасибо за любую помощь.

Ответы [ 6 ]

3 голосов
/ 08 декабря 2011

Ниже я не понимаю, почему:

int * currentSlot = memoryBlock

не использует &memoryBlock.

Потому что и memoryBlock, и currentSlot являются указателями на int. &memoryBlock будет адресом указателя на int, то есть int **.

Что такое "in" memoryBlock - указатель на блок памяти.

Тогда вот, *currentSlot = rand();, как здесь работает разыменование?

Это правило C: когда выражение разыменования, подобное этому, происходит в левой части выражения, значение правой стороны сохраняется в ячейке памяти, на которую указывает разыменованный указатель.

1 голос
/ 08 декабря 2011
int * memoryBlock;

memoryBlock - это переменная, которая может содержать адрес блока памяти целых чисел.Размер переменной memoryBlock - это размер адреса.Обычно 4 или 8 байтов (размер (int *)).Его типом является «указатель на int».

memoryBlock = calloc ( 5, sizeof(int) );

Переменной памяти назначается адрес начала блока памяти, который может содержать 5 целых чисел.Размер блока памяти составляет 5 * sizeof (int) байтов.

memoryBlock + 1 - адрес второго целого числа в блоке.memoryBlock + 5 - это один переданный адрес последнего целого числа в блоке.

* memoryBlock - это содержимое адреса (первое целое число).тип целое число.

*(memmoryBlock + 0) = 0;
*(memmoryBlock + 1) = 1;
*(memmoryBlock + 2) = 2;
*(memmoryBlock + 3) = 3;
*(memmoryBlock + 4) = 4;
//    *(memmoryBlock + 5) = 5; illegal

Назначает целые числа блоку памяти.Форма подписки такая же, как и выше.

memmoryBlock[0] = 0;
memmoryBlock[1] = 1;
memmoryBlock[2] = 2;
memmoryBlock[3] = 3;
memmoryBlock[4] = 4;
//    memmoryBlock[5] = 5; illegal

& memoryBlock - это адрес переменной memoryBlock.Это не адрес выделенного пространства.Это тип int ** «указатель на указатель на целое число», а не int *.

int ** pmemoryBlock;

pmemoryBlock - это переменная, которая содержит адрес адреса блока памяти целых чисел.Размер pmemoryBlock - это размер адреса.Обычно 4 или 8 байтов (sizeof (int **)).

pmemoryBlock = &memoryBlock;

pmemoryBlock назначается адрес переменной, которая содержит адрес начала блока памяти, способного содержать 5 целых чисел.

* pmemoryBlock - это адрес блока памяти.** pmemoryBlock - первое целое число в блоке памяти * ((* pmemoryBlock) + 0) - первое целое число в блоке памяти * ((* * pmemoryBlock) + 1) - целое число секунд в блоке памяти

...

1 голос
/ 08 декабря 2011

memoryBlock - массив целых чисел (int*). (технически это указатель на int, но так как для него было выделено достаточно места для 10 целых чисел, вы можете рассматривать его как начало массива)

*memoryBlock - целое число, на которое указывает memoryBlock (первое целое в массиве). Хотя обозначение выглядит так же, как и для объявления, оно фактически разыменовывает значение. ИМХО плохо написано как должно быть объявлено

int* currentSlot = memoryBlock;

, чтобы было более понятно, что это указатель на целое число, но это выбор стиля.

&memoryBlock - адрес указателя .

int * currentSlot = memoryBlock;

сохраняет указатель на первый слот в currentSlot. Затем программа генерирует случайные числа и помещает их в каждое из 10 сгустков, увеличивая currentSlot (который внутренне увеличивает указатель на длину целого числа.

Надеюсь, это поможет.

0 голосов
/ 08 декабря 2011

int * - указатель, который может быть разыменован. int ** - указатель на указатель, который может быть разыменован дважды. Так что это значит? Ну, указатель - не более чем целое число. Адреса памяти начинаются с нуля до максимального диапазона. Для 32-разрядных систем диапазон адресуемой памяти составляет от 0 до 2 ^ 32-1 (или 4294967295). Каждый из этих адресов имеет байтовое значение. Если у вас есть int *, то он будет обращаться к адресу 4 байта за раз. Также, для простоты, давайте предположим, что это виртуальный адрес, вы не можете просто получить доступ ко всей этой памяти, некоторые будут защищены (системные), некоторые недействительны (не зафиксированы). Чтобы получить больше памяти, вы можете попросить систему выделить больше из этого диапазона. sbrk в Linux, VirtualAlloc в Windows, но вы будете обращаться к ним, как правило, через malloc или calloc на C.

Допустим, у вас есть начиная с 0x100: 0x100: «h», «e», «l», «l», «o», «\ 0»

Таким образом, эта строка занимает память от 0x100 до 0x105 (включая нулевой терминатор). Если у вас есть указатель:

char * p = 0x100;

Тогда у вас есть:

p      // 0x100
*p     // 'h'
p+1    // 0x101
*(p+1) // 'e'
p += 2 // 0x102
*p     // 'l'
p = 0x200;
p      // now points to 0x200 in memory
*p     // contains whatever value is in 0x200

Если у вас есть указатели на int, то вы обращаетесь к памяти по 4 байта за раз (или как бы велико ни было int в вашей системе).

Таким образом, со всем этим фоном, когда вы запускаете calloc, он возвращает адрес запрашиваемого блока.

int *memoryBlock = calloc(count, sizeof(int));
// memoryBlock is an array of int, assuming sizeof(int) == 4, then
// you have 40 bytes of memory starting from the address of what is
// returned by calloc.

memoryBlock++;     // now memoryBlock is at base address + 4
*memoryBlock = 10; // now that address contains the value 10
(*memoryBlock)++;  // now that address contains the value 11
memoryBlock++;     // now memoryBlock is 4 bytes further
0 голосов
/ 08 декабря 2011

Это не предполагается для использования & memoryBlock, который является (int ** (хех!)) Адресом указателя в очищаемую память.Другими словами, memoryBLock (если он не равен NULL) указывает (то есть содержит адрес) первого int в памяти calloc ().Чтобы сослаться на эту очищенную до 0 память, вы используете * memoryBlock.

Если вы когда-либо пытались использовать & memoryBlock, не надо: это никогда не будет правильным в фрагменте кода, который вы разместили.1005 *

HTH.Если это не не поможет, вернитесь в K & R и еще раз изучите указатели.Может быть, намного больше.

0 голосов
/ 08 декабря 2011

В коде memoryBlock - это указатель на некоторую память, в которой хранятся целые числа.То есть фактическое значение переменной memoryBlock - это только что выделенный адрес.Если вы используете &memoryBlock, вы получите адрес, где хранится переменная , а не то, на что она указывает.

Давайте рассмотрим пример:

int foo = 5;
/* the variable "foo" is stored in memory,
   and that memory contains the number 5 */

int bar = 7;
/* the variable "foo" is stored in memory,
   and that memory contains the number 7 */

int *foo_pointer = &foo;
/* the variable "foo_pointer" is stored in memory,
   and that memory contains the address of the variable "foo" */

foo_pointer = &bar;
/* the contents of the variable "foo_pointer" is no longer the address
   of where the variable "foo" is in memory, instead it is the address
   of where the variable "bar" */

Iнадеюсь, в этом есть какой-то смысл, и это немного помогает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...