Я хочу скопировать международный массив в другой международный массив. Они используют то же, определяют для длины, таким образом, они будут всегда иметь ту же длину.
Каковы профессионалы/недостатки следующих двух альтернатив для параметра размера к memcpy ()?
memcpy(dst, src, ARRAY_LENGTH*sizeof(int));
или
memcpy(dst, src, sizeof(dst));
Вторая опция будет всегда работать? Независимо от содержания?
Одна вещь, которая способствует последнему, состоит в том, что, если массив должен был измениться, это будет некоторое обслуживание для обновления memcpy ().
Спасибо
Пока 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*)
Если и когда у вас есть массив (настоящий), вы можете использовать трюк 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 Вам нужно исправить расчет размера.
Это зависит от обстоятельств. И 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);
}
Если 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
Как насчет?
memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]);
Это должно работать, даже если размер отдельных элементов меньше, чем размер каждого элемента в реальном массиве.
sizeof (dst)
правильно, только если dst
- это массив, размер которого известен во время компиляции: например, int arr [ARRAY_LENGTH]
или массив переменной длины C99; в противном случае он возвращает размер указателя, а не длину целевого массива.
Чтобы избежать ошибок в будущем, будьте последовательны и отдайте предпочтение первой форме: размер типа * длина.
Предполагая, что dst имеет тип int *, sizeof (dst) вернет размер самого указателя (т.е. 4 в 32-битной системе, 8 в 64-битная система), поэтому ваш второй пример будет копировать только это количество байтов, а первый будет правильно использовать фактический размер содержимого.
Всегда ли будет работать второй вариант? Независимо от содержания?
Он будет работать, только если выполнены оба условия:
dst
- это обычный массив, а не указатель src
и dst
имеют одинаковый размер Всегда ли будет работать второй вариант? Независимо от содержания?
Второй вариант работает только в том случае, если вы добавили отсутствующие )
и dst
- статический массив (т.е. типа int
).
Если dst
имеет неизвестный размер (например, int []
), то sizeof dst
возвращает только размер указателя, поскольку dst
разложился до указателя. В этом случае вам нужно использовать sizeof (* dst) * ARRAY_LENGTH
.
Если вы выделили с помощью 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));