2010-04-21 54 views
13

Tôi muốn sao chép một mảng int vào một mảng int khác. Chúng sử dụng cùng một định nghĩa cho độ dài để chúng luôn có cùng chiều dài.memcpy(), giá trị của thông số kích thước là bao nhiêu?

Ưu điểm/nhược điểm của hai lựa chọn thay thế sau đây của tham số kích thước là memcpy() là gì?

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

hoặc

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

sẽ lựa chọn thứ hai luôn luôn làm việc? Bất kể nội dung?

Một điều mà ưu tiên cuối cùng là nếu mảng được thay đổi, nó sẽ là một số nhà giữ để cập nhật memcpy() của.

Cảm ơn

+0

Nó phụ thuộc hoàn toàn vào cách bạn đã khai báo 'dst' (và đến một mức độ, có hoặc không' src' bằng hoặc lớn hơn 'dst'). – dreamlax

Trả lời

22

Chừng nào dst được khai báo là một mảng với kích thước, sizeof sẽ trở lại kích thước của mảng theo byte:

int dst[ARRAY_LENGTH]; 

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

Nếu dst chỉ xảy ra được một con trỏ đến phần tử đầu tiên của như vậy mảng (đó là loại giống như các mảng chính nó), nó sẽ không làm việc:

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

memcpy(dst, src, sizeof(dst)); // Bad, sizeof(dst) returns sizeof(int*) 
5

sizeof(dst) chỉ đúng nếu dst là một mảng mà kích thước được biết đến tại thời gian biên dịch: như int arr[ARRAY_LENGTH] hoặc C99 chiều dài biến mảng; nếu không nó sẽ trả về kích thước của một con trỏ, không phải độ dài của mảng đích.

Để tránh lỗi trong tương lai, hãy nhất quán và thích biểu mẫu đầu tiên: kích thước loại * độ dài.

+0

Thật sao? Tôi đã tham gia vào [10]; cout << sizeof (arr) << endl; để có được 40 mà tôi nghi ngờ không phải là giá trị con trỏ. – Tomas

+0

Không nếu 'dst' là một mảng. – dreamlax

+1

Nó phụ thuộc vào dst là con trỏ hay mảng "thực". –

1

Giả sử dst có kiểu int *, sizeof (dst) sẽ trả về kích thước của con trỏ (tức là 4 trên hệ thống 32 bit, 8 trên hệ thống 64 bit), vì vậy ví dụ thứ hai của bạn sẽ chỉ sao chép nhiều byte, trong khi đầu tiên sẽ sử dụng đúng kích thước thực của nội dung.

2

Nếu bạn đã phân bổ sử dụng malloc bạn phải nêu rõ kích thước của mảng

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

Nếu bạn đã phân bổ với một mảng tĩnh bạn chỉ có thể sử dụng sizeof

int dst2[ARRAY_LENGTH]; 
memcpy(dst2,src,sizeof(dst2)); 
3

Will thứ hai tùy chọn luôn hoạt động? Bất kể nội dung?

Các tùy chọn thứ 2 chỉ hoạt động nếu bạn thêm vào lưng thiếu )dst là một mảng tĩnh (ví dụ: các loại int[123]).

Nếu dst có kích thước không xác định (ví dụ: int[]), thì sizeof dst chỉ trả về kích thước con trỏ, vì dst đã bị phân rã thành con trỏ. Trong trường hợp này, bạn cần sử dụng sizeof(*dst)*ARRAY_LENGTH.

+0

+1, nhưng tôi không nghĩ "tĩnh" là thuật ngữ chính xác cho một biến loại mảng.Nó có thể là một tự động, và "tĩnh" đã có rất nhiều ý nghĩa trong C và đặc biệt là C + +. "Tức là" của bạn giống như nó. –

1

sẽ lựa chọn thứ hai luôn luôn làm việc? Bất kể nội dung?

Nó sẽ chỉ làm việc nếu cả hai điều kiện được thỏa mãn:

  • dst là mảng thường xuyên, không phải con trỏ
  • srcdst đều giống nhau kích thước
+0

Hoặc 'src' lớn hơn' dst'. – dreamlax

0

Nó phụ thuộc. Cả arr và pointer đều là mảng, nhưng sizeof() chỉ trả về kích thước đúng cho arr, được khai báo tại thời gian biên dịch.

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

Đừng quên về C99 độ dài biến mảng. Độ dài của chúng được xác định trong thời gian chạy nhưng 'sizeof' sẽ vẫn hoạt động. – dreamlax

0

Nếu dst được cấp phát từ heap (sử dụng malloc chẳng hạn), giải pháp thứ hai sẽ không hoạt động. sizeof (dst) sẽ chỉ hoạt động khi nó được biết đến trình biên dịch. Ví dụ, ví dụ sau sẽ thất bại như sizeof (dst) sẽ bằng sizeof một con trỏ (4-8 byte.)

#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 

đoạn mã này sẽ làm việc mỗi thời gian:

#define ARRAY_LENGTH 10 
int *dst; 

dst = malloc(ARRAY_LENGTH*sizeof(int)); 
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes 
5

Nếu và khi bạn có một mảng (thực tế), bạn có thể sử dụng thủ thuật sizeof(array), nhưng lưu ý rằng nếu bạn refactor mã và đẩy nó vào đâu đó mảng đã bị phân rã thành một con trỏ (hoặc nếu bộ nhớ ban đầu được cấp phát trong một con trỏ (malloc/new), bạn cần phải vượt qua một kích thước đã biết.

Bỏ qua các kích thước tương đối của nguồn và đích, giả sử rằng chúng giống nhau cho phần còn lại của cuộc thảo luận, nếu bạn đang sử dụng C++, tôi sẽ đề xuất một thủ thuật lập trình meta để cung cấp cho bạn một số lượng kích thước an toàn cho mảng và sẽ thất bại để biên dịch nếu bạn cố gắng sử dụng nó với con trỏ:

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

bằng cách đó:

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 
} 

Nếu lúc nào đó bạn cấu trúc lại và mã di chuyển đến một nơi mà mảng đã bị hư hỏng (hoặc bạn thay thế một mảng tĩnh cho một phân bổ động) trình biên dịch sẽ cho bạn biết rằng bạn cần phải sửa tính toán kích thước.

+0

Tôi thậm chí không nhận thấy câu hỏi đã được gắn thẻ 'C++', +1! – dreamlax

+1

rất đẹp, nhưng chỉ là 'return sizeof a;' là đủ. –

+0

@BenVoigt: Đúng (và sửa) –

-1

Làm thế nào?

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

Điều này sẽ hoạt động ngay cả khi kích thước của từng phần tử nhỏ hơn kích thước của từng mục trong mảng thực tế.

+1

Tôi không rõ ràng về hoàn cảnh nào bạn nghĩ rằng điều này sẽ hiệu quả nhưng hình thức ban đầu thì không. –

+0

@ Dennis: Bạn nói đúng, tôi có thể nghĩ đến việc giải nén 'struct', trong đó các phần tử kế tiếp có thể không theo sát nhau ... Trong mảng C, bạn có thể giả định rằng '& a [n + 1] = = & a [n] + sizeof (a [0]) ', hoặc' & a [n] == a + n * sizeof (a [0]) ', do đó, biểu mẫu ban đầu sẽ hoạt động tốt. Xin lỗi vì sự nhầm lẫn. – squelart

+0

Thao tác này sẽ không hoạt động nếu không có 'sizeof' hoặc một diễn viên' char * '. –

1

sizeof (X) luôn mang đến cho bạn số byte của "X" nếu X là một mảng uint16_t 10, sau đó sizeof (X) sẽ trả lại 20

uint16_t X[10]={0}; 
cout<<"sizeof x: "<<sizeof(X); 

$> sizeof x: 20 

nếu bạn muốn số lượng yếu tố mà bạn phải làm một chút byte số học:
8bit = 1byte
16bit = 2bytes
32bit = 4 byte
64bit = 8 byte

như vậy để có được số lượng yếu tố mà bạn có thể làm:

numb_of_elements = (sizeof(X)/sizeof(X[0])); 

kết quả là:

uint32_t source[100]={0}; 
memcpy((void*) dest, (void*) source, (sizeof(source)/sizeof(source[0]))); 

tất nhiên bạn có lẽ sẽ muốn thực hiện (sizeof (X)/sizeof (X [0])) là một hằng số/biến để bạn không tính toán mỗi lần .. (Tôi không biết liệu các trình biên dịch sẽ luôn tối ưu hóa điều này)

0

memcpy(), giá trị của thông số kích thước là bao nhiêu?

Nó phải là kích thước tối thiểu giữa kích thước của bộ đệm nguồn và kích thước của bộ đệm đích.

Theo truyền thống, kích thước của bộ đệm nguồn đã được sử dụng. Điều đó tràn bộ đệm đích vào dịp ... Vì vậy, tốt hơn nên sử dụng phiên bản "an toàn hơn" của hàm: một hàm xác định cả kích thước bộ đệm nguồn và đích.

Bạn có các chức năng "an toàn hơn" có sẵn qua ISO/IEC TR24731. Có rất nhiều thứ khác, như các giá trị trả về nhất quán và hành vi xử lý chuỗi nhất quán.

Các chức năng "an toàn hơn" là một phần của tiêu chuẩn C ngay bây giờ, vì vậy chức năng của nó phải khả dụng ở mọi nơi. Vì vậy, bạn nên sử dụng memcpy_s.

Bạn không thể sử dụng nó trên Linux, bởi vì nó không cung cấp các chức năng (không tin vào quảng cáo tiếp thị về tuân thủ các tiêu chuẩn)). Trên Linux, bạn nên "cuộn của riêng bạn" wrapper.

Không phải ai cũng là người hâm mộ các chức năng an toàn hơn. Xem, ví dụ: Do you use the TR 24731 'safe' functions?. Về tất cả những gì tôi có thể nói về điều đó là: Multiple libunp buffer overflows. Hàng triệu bộ định tuyến và cổng có thể bị nhiều lỗ hổng và nhiều cổng vẫn chưa được vá. Và chúng là do các lỗi có thể bị dừng lại bởi các chức năng an toàn hơn. +1 cho tất cả những người đang nói "không sử dụng Microsoft crap này".

Các vấn đề liên quan