ANSI-C, лучше скопировать элементы массива в другой массив? - PullRequest
1 голос
/ 24 сентября 2010

есть ли в любом случае делать то, что я делаю в строках 2 и 3, с чем-то, похожим на строку 1?

Если я просто поставлю строку 1, тогда и «a», и «one.index1» будутуказывая на подобное местоположение, которое я не хочу.То, что я действительно хочу, сделано в строках 2 и 3. Итак, это единственный путь, или кто-то может дать лучший путь?

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
 int *index1;
} data;

void doo(int *);

int main(int argc, char *argv[])
{
 int *a = (int *) malloc(10*sizeof(int));
 int i;

 for(i=0; i<10; i++)
 {
  a[i] = 2*i;
 }

 doo(a);

 data one;
 //one.index1 = a;                           // Line 1
 /*******************/
 one.index1 = (int *) malloc(5*sizeof(int)); // Line 2
 for(i=0; i<5; i++) one.index1[i] = a[i];    // Line 3
 /*******************/

 printf("%d\n", one.index1[4]);

 free(a);

 printf("%d\n", one.index1[4]);

 free(one.index1);
 return 0;
}

void doo(int *b)
{
 b = (int *) realloc(b, 5*sizeof(int));
 return;
}

Заранее спасибо!

Ответы [ 5 ]

2 голосов
/ 24 сентября 2010

ду не будет работать как есть.Это должно быть:

void doo(int **b) 
{ 
 *b = (int *) realloc(*b, 5*sizeof(int)); 
 return; 
} 

и вызываться по

 doo(&a);

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

Теперь, чтобы ответить на ваш актуальный вопрос, поскольку мы имеем дело с простыми элементами данных (т. Е. Целыми числами), вы можете использовать memmove() или memcpy() для их копирования:(memmove безопасен, если блоки памяти перекрываются; memcpy нет, но здесь это не проблема)

  one.index1 = (int *) malloc(5*sizeof(int)); // Line 2 
  memcpy(one.index1, a, sizeof(int) * 5); 

Что касается эффективности memmove / memcpy, это в значительной степени неизвестная область.memmove делает немного большую проверку диапазона, чем memcpy, так что это будет намного медленнее memcpy.Насколько memcpy против цикла, сказать сложно.У memcpy немного больше накладных расходов, но он называется много , поэтому у поставщиков компиляторов есть парень, который тратит много времени, чтобы быть уверенным, что это максимально быстро.

Обратите внимание, однако, учитывая небольшое фиксированное количество элементов для копирования, самый быстрый способ - просто скопировать их напрямую:

  one.index1 = (int *) malloc(5*sizeof(int)); // Line 2 
  one.index1[0] = a[0];
  one.index1[1] = a[1];
  one.index1[2] = a[2];
  one.index1[3] = a[3];
  one.index1[4] = a[4];
1 голос
/ 24 сентября 2010

Некоторые придирки.

Жизнь становится проще, если вы определяете функции до их вызова (если они находятся в одном и том же исходном файле); Таким образом, вам не нужно беспокоиться о синхронизации объявлений / определений.

Не разыгрывайте результат malloc(). Начиная с C89 вам это не нужно, и это может подавить полезную диагностику, если вы забудете #include stdlib.h или у вас нет прототипа для malloc() в области видимости (хотя новые компиляторы ловят эту ошибку даже с актерами, так как это часто бывает так кроваво).

Используйте оператор sizeof для того, что вы выделяете, а не для типа; опять же, это упрощает жизнь, так как вам не нужно хранить объявление и malloc() синхронизировать вызовы.

Если вы хотите, чтобы функция изменила аргумент указателя, вы должны передать указатель на этот указатель:

void doo(int **p)
{
  *p = realloc(*p, 5 * sizeof **p); 
}

В противном случае изменение формального параметра p не отражается в фактическом параметре.

Жизнь также становится проще, если вы абстрагируете свои функции управления памятью; Вы можете заменить строки 2 и 3 одним вызовом функции:

int *copy(int * const source, size_t len)
{
  int *dest = malloc(len * sizeof *dest);
  if (dest)
    memcpy(dest, source, len * sizeof *source);
  return dest;
}

который вы называете

one.index1 = copy(a, len);
0 голосов
/ 24 сентября 2010

Это зависит от того, что конкретно вы хотите избежать в строках 2 и 3. Если вы хотите избежать цикла, используйте memcpy, хотя большинство компиляторов должны заменять ваш цикл кодом, эквивалентным вызову memcpy.Если вы хотите однострочную операцию, вы можете написать статическую функцию, которая принимает в качестве аргументов адрес one.index1, размер массива a и a.

int * f (int **int_pp, size_t len, int const *a) {
    *int_pp = (int *) malloc (len * sizeof (int));
    if ( *int_pp != NULL ) {
       memcpy (*int_pp, a, len);
    }
    return *int_pp;
}

Не забудьте проверить, возвращает ли malloc значение NULL!

Если вы хотите избежать вызова malloc, я думаю, что единственный вариант - установить часть памятикроме того, что вы управляете вручную.Однако почти никогда не стоит пытаться самостоятельно управлять памятью.

0 голосов
/ 24 сентября 2010

Вы можете использовать функцию memmove / memcpy, которая, вероятно, будет сильно оптимизирована:

const size_t size = 5*sizeof(int);
one.index = (int *) malloc(size);
memcpy(one.index, a, size);

Конечно, вы можете заключить это в функцию:

int *getCopy(const int *source, size_t count)
{
  int *result = (int *)malloc(count * sizeof(int));
  if (!result)
    return NULL;
  memcpy(result, source, count * sizeof(int));
  return result;
}

// Usage
one.index = getCopy(a, 5);
0 голосов
/ 24 сентября 2010

Вы можете использовать memmove. Обязательно #include <string.h> при запуске.

Заменить строки 2 и 3 на

one.index1 = malloc( 5*sizeof(int) );
memmove(one.index1,a, 5*sizeof(int) );

Например, рассмотрим a & c здесь:

int *a= (int *) malloc(10*sizeof(int));
for(i=0; i<10; i++)
{
    a[i] = 2*i;
}   
int *c= (int *) malloc(10*sizeof(int));
memmove(c,a,10*sizeof(int));

Теперь оба a & c являются отдельными указателями, указывающими на "одинаковые данные" и могут быть освобождены отдельно.

a[0]=0 c[0]=0
a[1]=2 c[1]=2
a[2]=4 c[2]=4
a[3]=6 c[3]=6
a[4]=8 c[4]=8
a[5]=10 c[5]=10
a[6]=12 c[6]=12
a[7]=14 c[7]=14
a[8]=16 c[8]=16
a[9]=18 c[9]=18

Является ли этот новый метод более эффективным? Практически это так. Сравните время, необходимое для запуска программы: (я использовал long long type вместо int, чтобы получить заметную разницу во времени)

Старый метод:

$ time ./a.out

real    0m0.249s
user    0m0.178s
sys     0m0.070s

Новый метод:

$ time ./a.out

real    0m0.164s
user    0m0.095s
sys     0m0.068s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...