Bạn nên không bao giờ sử dụng gets
(hoặc scanf
với kích thước chuỗi không bị chặn) vì thao tác này sẽ mở bạn đến tràn bộ đệm. Sử dụng các fgets
với một xử lý stdin
vì nó cho phép bạn giới hạn dữ liệu sẽ được đặt trong bộ đệm của bạn.
Dưới đây là một đoạn nhỏ tôi sử dụng cho đầu vào dòng từ người sử dụng:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
này cho phép tôi để đặt kích thước tối đa, sẽ phát hiện nếu quá nhiều dữ liệu được nhập trên dòng, và sẽ tuôn phần còn lại của dòng cũng vì vậy nó không ảnh hưởng đến hoạt động đầu vào tiếp theo.
Bạn có thể thử nghiệm nó với một cái gì đó như:
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
không phải thư viện hệ thống thực hiện quét ngăn chặn tràn lệnh (Tôi hiểu rằng trong chương trình nếu nhà phát triển không kiểm tra đầu vào có thể là tràn, nhưng thư viện hệ thống an toàn không?). – Marm0t
Không, nếu bạn 'scanf ("% s ")' vào bộ đệm 20 byte và người dùng nhập một dòng 40 byte, bạn sẽ được đặt. Toàn bộ điểm của 'scanf' được quét định dạng và có ít hơn _unformatted_ hơn đầu vào của người dùng :-) – paxdiablo
@ Marm0t - Hãy suy nghĩ theo cách này bằng cách xem xét câu hỏi sau: làm thế nào có thể thực hiện ngăn chặn tràn nếu tất cả nó được một con trỏ tới một lát bộ nhớ (được định kiểu là char *) 'mà không có tham số nào cho biết việc thực thi về kích thước của bộ đệm đích'? –