2011-08-08 17 views
6

Tôi nên sử dụng thông tin gì khi muốn sao chép src_str đến dst_arr và tại sao?strncpy hoặc strlcpy trong trường hợp của tôi

char dst_arr[10]; 
char *src_str = "hello"; 

PS: đầu tôi đang quay nhanh hơn đĩa của máy tính của tôi sau khi đọc rất nhiều thứ về cách tốt hoặc xấustrncpystrlcpy.

Lưu ý: Tôi biết strlcpy không khả dụng ở mọi nơi. Đó không phải là mối quan tâm ở đây.

Trả lời

20

strncpybao giờ câu trả lời đúng khi chuỗi điểm đến của bạn là zero-chấm dứt. strncpy là chức năng được sử dụng với các chuỗi không cố định có chiều rộng cố định. Chính xác hơn, mục đích của nó là để chuyển đổi một chuỗi không chấm dứt thành một chuỗi có độ rộng cố định không bị chấm dứt (bằng cách sao chép). Nói cách khác, strncpy không được áp dụng có ý nghĩa ở đây.

Lựa chọn thực sự bạn có ở đây là giữa strlcpy và đồng bằng strcpy.

Khi bạn muốn thực hiện sao chép "an toàn" (tức là cắt ngắn có khả năng) thành dst_arr, chức năng thích hợp để sử dụng là strlcpy.

Đối với dst_ptr ... Không có nội dung nào như "sao chép vào dst_ptr". Bạn có thể sao chép vào bộ nhớ chỉ bằng dst_ptr, nhưng trước tiên bạn phải đảm bảo rằng nó trỏ đến đâu đó và phân bổ bộ nhớ đó. Có rất nhiều cách khác nhau để làm điều đó.

Ví dụ: bạn chỉ có thể thực hiện dst_ptr để trỏ đến dst_arr, trong trường hợp này, câu trả lời giống như trong trường hợp trước - strlcpy.

Hoặc bạn có thể cấp phát bộ nhớ bằng cách sử dụng malloc. Nếu lượng bộ nhớ bạn phân bổ được đảm bảo đủ cho chuỗi (tức là ít nhất strlen(src_str) + 1 byte được phân bổ), thì bạn có thể sử dụng số strcpy hoặc thậm chí memcpy để sao chép chuỗi. Không có nhu cầu và không có lý do để sử dụng strlcpy trong trường hợp này, mặc dù một số người có thể thích sử dụng nó, vì nó bằng cách nào đó mang lại cho họ cảm giác an toàn hơn.

Nếu bạn cố ý phân bổ ít bộ nhớ hơn (nghĩa là bạn muốn chuỗi của mình bị cắt bớt), thì strlcpy sẽ trở thành chức năng phù hợp để sử dụng.

+1

Cảm ơn. Khi bạn nói "strncpy không bao giờ là câu trả lời đúng khi bạn đang làm việc với các chuỗi zero-terminated", bạn có nghĩa là chuỗi nguồn hoặc dest? – hari

+2

@hari: Chuỗi đích. 'strncpy' là một hàm * conversion *, chuyển đổi chuỗi nguồn không bị chấm dứt thành một chuỗi đích cố định chiều rộng cố định. – AnT

+0

Vì vậy, nếu chuỗi đích của tôi là 'char dst_arr [10];' mà không phải là null-chấm dứt. Sau đó, tôi nên sử dụng 'strlcpy' đúng? – hari

4

strlcpy() an toàn hơn strncpy() để bạn cũng có thể sử dụng nó.
Các hệ thống không có nó thường có s_strncpy() thực hiện tương tự.

Lưu ý bạn không thể sao chép bất cứ điều gì để dst_ptr cho đến khi nó chỉ vào một cái gì đó

+1

Nó an toàn hơn một chút, nhưng cũng không an toàn. Ví dụ. strlcpy cắt ngắn chuỗi nguồn để phù hợp với đích, đó là một nguy cơ bảo mật. – rurban

2

Tôi không biết về strlcpy. Tôi chỉ tìm thấy here rằng:

Các strlcpy() và strlcat() chức năng sao chép và nối chuỗi tương ứng. Chúng được thiết kế để an toàn hơn, nhất quán hơn và ít bị lỗi hơn thay thế cho strncpy (3) và strncat (3).

Vì vậy, đường nối strlcpy an toàn hơn.

Chỉnh sửa: Cuộc thảo luận đầy đủ có sẵn here.

Edit2:

Tôi nhận ra rằng những gì tôi viết trên đây không trả lời "trong trường hợp của bạn" một phần của câu hỏi của bạn. Nếu bạn hiểu những hạn chế của strncpy, tôi đoán bạn có thể sử dụng nó và viết mã tốt xung quanh nó để tránh những cạm bẫy của nó; nhưng nếu bạn không chắc chắn về sự hiểu biết của bạn về giới hạn của nó, sử dụng strlcpy.

Sự hiểu biết của tôi về những hạn chế của strncpy và strlcpy là bạn có thể làm điều gì đó rất xấu với strncpy (tràn bộ đệm), và điều tồi tệ nhất bạn có thể làm với strlcpy là mất một char trong tiến trình.

+0

Cảm ơn bạn đã giải thích. Làm thế nào tôi có thể mất một char trong 'strlcpy'? bạn có thể giải thích dùm không? – hari

+0

Nếu bạn sử dụng strncpy để sao chép một chuỗi lớn hơn bộ đệm của bạn, nó sẽ không đặt một ''\ 0'' ở cuối bộ đệm. Nếu bạn sử dụng strlcpy, ''\ 0'' sẽ ở đó, nhưng một char ít hơn sẽ nằm trong bộ đệm của bạn. Vì vậy, nếu ai đó sử dụng strncpy khi anh ta nên sử dụng memcpy, sử dụng strlcpy thay vì strncpy sẽ mất anh ta một char. – jfg956

+0

Cảm ơn. Vì vậy, khi sử dụng 'strlcpy' điều duy nhất bạn cần phải chăm sóc là, bạn nên cung cấp điểm đến với (src_length + 1 cho null). Chính xác? – hari

-1

Trước hết, dst_ptr của bạn không có không gian được cấp phát và bạn chưa đặt nó ở điểm khác, do đó, chỉ định bất kỳ thứ gì có thể gây ra lỗi phân đoạn.

strncpy nên làm việc hoàn toàn tốt đẹp - chỉ cần làm:

strncpy(dst_arr, src_str, sizeof(dst_arr)); 

và bạn biết bạn wont tràn dst_arr. Nếu bạn sử dụng một src_str lớn hơn, bạn có thể phải đặt null-terminator của riêng bạn vào cuối dst_arr, nhưng trong trường hợp này nguồn của bạn là < dest của bạn, do đó, nó sẽ được đệm với nulls anyway.

Điều này hoạt động ở mọi nơi và an toàn của nó, vì vậy tôi sẽ không xem xét bất kỳ điều gì khác trừ khi sự tò mò trí tuệ của nó.

Cũng lưu ý rằng nó sẽ là tốt để sử dụng một số phi ma thuật cho 10 vì vậy bạn biết kích thước của phù hợp với kích thước của strncpy :)

+0

'strncpy' gần như không bao giờ là điều đúng, vì nó không điền nhưng không kết thúc bằng 0. OP muốn 'strlcpy', mà không kết thúc và không làm đầy. Ngoài ra, nó là một sai lầm để nói về "trong trường hợp này", bởi vì câu hỏi tất nhiên chỉ là một minh hoạ ... mã thực sẽ không được sao chép một chuỗi cố định như "hello" vào một bộ đệm có kích thước cố định được gọi là lớn hơn . –

-1

bạn không nên sử dụng strncpy và không strlcpy cho điều này . Tốt hơn bạn sử dụng

*dst_arr=0; strncat(dst_arr,src_arr,(sizeof dst_arr)-1); 

hoặc không có một khởi

sprintf(dst_arr,"%.*s",(sizeof dst_arr)-1,src_arr); 

dst_arr đây phải là một mảng KHÔNG phải là một con trỏ.

+2

'strlcpy' có thể được sử dụng cho các nhu cầu của OP. –

1

Bạn phải luôn là hàm chuẩn, trong trường hợp này là hàm C11 strcpy_s(). Không phải strncpy(), vì điều này là không an toàn không đảm bảo không có chấm dứt. Và không chỉ OpenBSD chỉ strlcpy(), vì nó cũng không an toàn, và OpenBSD luôn luôn đi kèm với phát minh của riêng nó, mà thường không làm cho nó thành bất kỳ tiêu chuẩn.

Xem http://en.cppreference.com/w/c/string/byte/strcpy

Chức năng strcpy_s cũng tương tự như chức năng BSD strlcpy, ngoại trừ việc strlcpy truncates chuỗi nguồn để phù hợp với đích (đó là một nguy cơ bảo mật)

  • strlcpy làm không thực hiện tất cả các kiểm tra thời gian chạy mà strcpy_s thực hiện
  • strlcpy không thực hiện lỗi rõ ràng bằng cách đặt đích đến chuỗi rỗng hoặc gọi trình xử lý nếu cuộc gọi không thành công.
  • Mặc dù strcpy_s cấm cắt ngắn do rủi ro bảo mật tiềm ẩn, nhưng có thể cắt ngắn chuỗi bằng cách sử dụng strncpy_s được kiểm tra giới hạn.

Nếu thư viện C của bạn không có strcpy_s, hãy sử dụng safec lib. https://rurban.github.io/safeclib/doc/safec-3.1/df/d8e/strcpy__s_8c.html

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