void * как параметр функции - PullRequest
0 голосов
/ 18 января 2019

У меня проблема с использованием void *. Как я должен сделать, чтобы использовать эту функцию clean_buffer для массивов int и float.

void clean_buffer( void *ptr, int n)
{
    for( int i = 0; i < n; i++)
        ptr[i]=0;
}
int main(void)
{
   float  *pf;
   int    *pi;

   pf = (float *) malloc(10*sizeof(float));
   pi = (int *)malloc(10*sizeof(int));


   clean_buffer( (float *)pf, 10);
   clean_buffer( (int *)pi, 10);

    return 0;
}

Ответы [ 6 ]

0 голосов
/ 18 января 2019

У меня проблема с использованием void *. Как мне сделать, чтобы использовать эту функцию clean_buffer для массивов int и float (?)

Другие упомянули полезные вещи, такие как необходимость sizeof найти размер, приведение не требуется и альтернативы использованию calloc() для нулевого инициализированного выделения памяти.


Добавить:

sizeof * object_pointer

Используйте sizeof *object_pointer, чтобы найти размер. Он менее подвержен ошибкам, его легче просматривать и поддерживать, чем кодировать в типе.

// clean_buffer( (float *)pf, 10);
// clean_buffer( (int *)pi, 10);

// cast not needed
clean_buffer(pf, sizeof *pf * 10);  // No need to mention type!
clean_buffer(pi, sizeof *pi * 10);

летучий

Очистка памяти после ее окончательного использования склонна к оптимизации, а затем веская причина для , а не , использовать memset(), когда важна безопасность памяти. Вместо этого используйте volatile, чтобы предотвратить оптимизацию clean_buffer().

void clean_buffer(void *ptr, size_t n) {
  volatile unsigned char *vuc = ptr;
  for(size_t i = 0; i < n; i++)
    vuc[i]=0;
  }
}
0 голосов
/ 18 января 2019

malloc сам по себе возвращает пустой указатель, поскольку он не знает, для какого типа вы выделяете память. Таким образом, вам нужно использовать тот же размер, который вы передаете malloc для очистки буфера.

Вы можете использовать memset и передать размер всего буфера, чтобы очистить его, не беспокоясь о его типе.

void clean_buffer( void *ptr, size_t n)
{
    memset(ptr, 0, n)
}
int main(void)
{
   float  *pf;
   int    *pi;

   pf = (float *) malloc(10*sizeof(float));
   pi = (int *)malloc(10*sizeof(int));


   clean_buffer(pf, 10*sizeof(float));
   clean_buffer(pi, 10*sizeof(int));

    return 0;
}

Кроме того, как предлагали другие, вы можете использовать calloc, если вам это подходит.

0 голосов
/ 18 января 2019

void clean_buffer (void * ptr, int n)

Эта функция требует void * в качестве параметра.

clean_buffer ((float *) pf, 10);

Здесь вы приводите указатель с плавающей точкой. Так что это другой тип, как требуется

Также void не имеет размера, поэтому вы не можете использовать [] на ptr

0 голосов
/ 18 января 2019

Тип void не имеет размера. Поэтому вы не можете использовать void * для очистки массива. Вы не можете разыменовать этот тип по той же причине.

Вы должны привести к указателю с определенным типом:

void clean_buffer(void *ptr, size_t n)
{
    unsigned char *my_ptr = ptr;
    for (int i = 0; i < n; i++)
        my_ptr[i]=0;
}

Вам нужно позаботиться о том, чтобы размер, передаваемый вашей функции, не мог быть числом или массивами, потому что компилятор не может выполнять арифметику указателей с void* указателями. А для размеров следует использовать size_t

Вместо этого вы должны передать размер массива в байтах:

int main(void)
{
   float  *pf;
   int    *pi;

   pf = malloc(10*sizeof(float));
   pi = malloc(10*sizeof(int));

   clean_buffer( pf, 10*sizeof(float));
   clean_buffer( pi, 10*sizeof(int));

   return 0;
}

Или вам нужно передать любую другую информацию, которая может использоваться для определения типа и / или размера данных.

Также: Приведение возвращаемого значения malloc не требуется в C. Преобразование параметров clean_buffer в тип, который уже есть в переменной, бесполезно. В любом случае тип указателя преобразуется в void *, поскольку это то, что ожидает функция.

Примечание: В других ответах и ​​комментариях упоминается, что вы можете просто передать указатель на memset или использовать calloc и т. Д. Это может быть верно для этого очень специфического случая, но если вы хотите сделать что-то еще, кроме простого обнуления памяти, применяются те же аспекты в отношении указателей void *, как я показал здесь. И в этих случаях memset или calloc не помогают.

0 голосов
/ 18 января 2019

void - это не значение, которое нельзя использовать *((void*) x) = v;, а использование cast для использования указателя на другой тип опасно , поскольку размер может не совпадать

Но в вашем случае вы устанавливаете 0, так что вы можете использовать memset или заменить malloc my calloc и бесполезно иметь clean_buffer:

int main(void)
{
   float  *pf;
   int    *pi;

   pf = calloc(10, sizeof(float));
   pi = calloc(10, sizeof(int));

   return 0;
}
0 голосов
/ 18 января 2019

Вы приводите ptr к соответствующему типу, чтобы его можно было разыменовать, чтобы очистить то, на что он указывает; что-то, что вы знаете, указывает на тип, который вы хотите очистить i пунктов.

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