memcpy (), что должно значение параметра размера быть?

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

Каковы профессионалы/недостатки следующих двух альтернатив для параметра размера к memcpy ()?

memcpy(dst, src, ARRAY_LENGTH*sizeof(int));

или

memcpy(dst, src, sizeof(dst));

Вторая опция будет всегда работать? Независимо от содержания?

Одна вещь, которая способствует последнему, состоит в том, что, если массив должен был измениться, это будет некоторое обслуживание для обновления memcpy ().

Спасибо

18
задан jww 20 November 2014 в 00:48
поделиться

10 ответов

Пока dst объявлен как массив с размером, sizeof вернет размер этого массива в байтах:

int dst[ARRAY_LENGTH];

memcpy( dst, src, sizeof(dst) ); // Good, sizeof(dst) returns sizeof(int) * ARRAY_LENGTH

Если dst просто указатель на первый элемент такого массива (который имеет тот же тип, что и сам массив), он не будет работать:

int buffer[ARRAY_LENGTH];
int* dst = &buffer[0];

memcpy( dst, src, sizeof(dst) ); // Bad, sizeof(dst) returns sizeof(int*)
28
ответ дан 30 November 2019 в 06:42
поделиться

Если и когда у вас есть массив (настоящий), вы можете использовать трюк sizeof (array) , но обратите внимание, что если вы реорганизуете код и отправите его куда-нибудь, где массив распался на указатель ( или если память изначально была выделена в указателе (malloc / new), вам нужно будет передать известный размер.

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

template <typename T, int N>
inline int array_memory_size( T (&a)[N] ) { return sizeof a; }

Таким образом:

int main() {
   int array[10];
   int *ptr = array;
   int orig[10] = { 0 };
   memcpy( array, orig, array_memory_size(array) ); // ok
   //memcpy( ptr, orig, array_memory_size(ptr) ); // compilation error
}

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

5
ответ дан 30 November 2019 в 06:42
поделиться

Это зависит от обстоятельств. И arr, и указатель являются массивами, но sizeof () возвращает только правильный размер для arr, который объявляется во время компиляции.

int main() {
        int arr[10];
        int * pointer;
        pointer = (int *) malloc(10 * sizeof(int));
        printf("%d\n", sizeof(arr)); // 40
        printf("%d\n", sizeof(pointer)); // 4 or 8
        free(pointer);
}
0
ответ дан 30 November 2019 в 06:42
поделиться

Если dst был выделен из кучи (например, с помощью malloc), второе решение не сработает. sizeof (dst) будет работать, только если это известно компилятору. Например, следующий пример завершится ошибкой, поскольку sizeof (dst) будет равен размеру указателя (4-8 байтов).

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, sizeof(dst)); // sizeof dst in this case would be 4 bytes on 32 bit system

Этот сегмент кода будет работать каждый раз:

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes
0
ответ дан 30 November 2019 в 06:42
поделиться

Как насчет?

memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]);

Это должно работать, даже если размер отдельных элементов меньше, чем размер каждого элемента в реальном массиве.

-1
ответ дан 30 November 2019 в 06:42
поделиться

sizeof (dst) правильно, только если dst - это массив, размер которого известен во время компиляции: например, int arr [ARRAY_LENGTH] или массив переменной длины C99; в противном случае он возвращает размер указателя, а не длину целевого массива.

Чтобы избежать ошибок в будущем, будьте последовательны и отдайте предпочтение первой форме: размер типа * длина.

5
ответ дан 30 November 2019 в 06:42
поделиться

Предполагая, что dst имеет тип int *, sizeof (dst) вернет размер самого указателя (т.е. 4 в 32-битной системе, 8 в 64-битная система), поэтому ваш второй пример будет копировать только это количество байтов, а первый будет правильно использовать фактический размер содержимого.

1
ответ дан 30 November 2019 в 06:42
поделиться

Всегда ли будет работать второй вариант? Независимо от содержания?

Он будет работать, только если выполнены оба условия:

  • dst - это обычный массив, а не указатель
  • src и dst имеют одинаковый размер
1
ответ дан 30 November 2019 в 06:42
поделиться

Всегда ли будет работать второй вариант? Независимо от содержания?

Второй вариант работает только в том случае, если вы добавили отсутствующие ) и dst - статический массив (т.е. типа int ).

Если dst имеет неизвестный размер (например, int [] ), то sizeof dst возвращает только размер указателя, поскольку dst разложился до указателя. В этом случае вам нужно использовать sizeof (* dst) * ARRAY_LENGTH .

3
ответ дан 30 November 2019 в 06:42
поделиться

Если вы выделили с помощью malloc, вы должны указать размер массива

int * src = malloc(ARRAY_LENGTH*sizeof(*src));
int * dst1 = malloc(ARRAY_LENGTH*sizeof(*dst));
memcpy(dst1,src,ARRAY_LENGTH*sizeof(*dst));

Если вы выделили статический массив, вы можете просто использовать sizeof

int dst2[ARRAY_LENGTH];
memcpy(dst2,src,sizeof(dst2));
3
ответ дан 30 November 2019 в 06:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: