Trong cuốn sách Thực hành lập trình của họ (rất đáng đọc), Kernighan và Pike thảo luận về vấn đề này, và họ giải quyết nó bằng cách sử dụng snprintf()
để tạo chuỗi với kích thước bộ đệm chính xác để chuyển đến scanf()
họ hàm. Có hiệu lực:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
Lưu ý, điều này vẫn giới hạn đầu vào ở kích thước được cung cấp dưới dạng 'bộ đệm'. Nếu bạn cần thêm dung lượng, thì bạn phải thực hiện cấp phát bộ nhớ hoặc sử dụng một hàm thư viện không chuẩn để cấp phát bộ nhớ cho bạn.
Lưu ý rằng POSIX 2008 (2013) phiên bản của scanf()
gia đình các chức năng hỗ trợ sửa đổi định dạng m
(một nhân vật nhiệm vụ phân bổ) cho đầu vào chuỗi ( %s
, %c
, %[
). Thay vì lấy một char *
đối số, nó lấy một char **
đối số và phân bổ không gian cần thiết cho giá trị mà nó đọc:
char *buffer = 0;
if (sscanf(data, "%ms", &buffer) == 1)
{
printf("String is: <<%s>>\n", buffer);
free(buffer);
}
Nếu sscanf()
hàm không đáp ứng được tất cả các thông số kỹ thuật chuyển đổi, thì tất cả bộ nhớ mà nó phân bổ cho các %ms
chuyển đổi-like sẽ được giải phóng trước khi hàm trả về.
buflen-1
- Cảm ơn bạn. Sau đó, bạn phải lo lắng về dòng dưới không được đánh dấu (gói đến một số lượng khá lớn), do đó,if
thử nghiệm. Tôi rất muốn thay thế nó bằng mộtassert()
hoặc sao lưu nó bằng mộtassert()
trước khiif
nó phát hỏa trong quá trình phát triển nếu bất kỳ ai đó đủ bất cẩn để vượt qua 0 làm kích thước. Tôi đã không xem xét cẩn thận tài liệu để biết%0s
có nghĩa là gìsscanf()
- kiểm tra có thể tốt hơnif (buflen < 2)
.