2014-10-27 33 views
6

Tôi muốn mã chạy cho đến khi người dùng nhập giá trị số nguyên.Làm thế nào để quét chỉ số nguyên?

Mã hoạt động cho mảng char và char.

Tôi đã làm như sau:


#include<stdio.h> 
int main() 
{ 
    int n; 
    printf("Please enter an integer: "); 
    while(scanf("%d",&n) != 1) 
    { 
     printf("Please enter an integer: "); 
     while(getchar() != '\n'); 
    } 
    printf("You entered: %d\n",n); 
    return 0; 
} 

Vấn đề là nếu người dùng nhập vào một giá trị float scanf sẽ chấp nhận nó.

Please enter an integer: abcd 
Please enter an integer: a 
Please enter an integer: 5.9 
You entered: 5 

Làm cách nào có thể tránh được?

+0

Điều này có giống không? http://stackoverflow.com/questions/23610457/how-can-i-distinguish-between-integer-and-character-when-using-scanf –

+2

Nó không phải là 'quét một phao' mà là dừng ở số không đầu tiên . Nó cũng sẽ làm điều này với đầu vào "5xyzNotAFloatNumber". – usr2564301

+0

Vì vậy, nó không thể được thực hiện với 'scanf'? Vì vậy, người ta phải luôn luôn sử dụng 'fgets'? – user1336087

Trả lời

18
  1. Bạn lấy scanf().
  2. Bạn ném nó vào thùng rác.
  3. Bạn sử dụng fgets() để nhận toàn bộ dòng.
  4. Bạn sử dụng strtol() để phân tích dòng dưới dạng số nguyên, kiểm tra xem nó có sử dụng toàn bộ dòng hay không.
char *end; 
char buf[LINE_MAX]; 

do { 
    if (!fgets(buf, sizeof buf, stdin)) 
     break; 

    // remove \n 
    buf[strlen(buf) - 1] = 0; 

    int n = strtol(buf, &end, 10); 
} while (end != buf + strlen(buf)); 
+0

Hmmm Có vẻ như vòng lặp sẽ thoát nếu người dùng chỉ nhập ''\ n''. Không biết nếu điều đó là quan trọng để OP. – chux

+0

@chux xử lý lỗi thô sơ có chủ ý. –

4

Hãy thử sử dụng các mô hình sau đây trong scanf, nó sẽ đọc cho đến khi kết thúc dòng:

scanf("%d\n",&n) 

Bạn sẽ không cần getchar() bên trong vòng lặp từ scanf sẽ đọc toàn bộ dòng. Các phao sẽ không khớp với mẫu scanf và dấu nhắc sẽ hỏi lại một số nguyên.

+0

'scanf ("% d \ n ", & n)' chỉ đọc toàn bộ dòng (và sau đó một số) nếu một 'int' được nhập vào. Nếu không có 'int' được nhập vào, đầu vào vẫn còn trong' stdin'. Sử dụng '" \ n "' không chỉ tiêu thụ ''\ n'', mà nó còn quét bất kỳ số không gian trắng nào cho đến khi một khoảng trắng không được nhập vào. 'Char' đó được đưa trở lại vào' stdin'. Vì vậy, 'scanf()' sẽ không ngay lập tức trở lại khi ''\ n'' được nhập vào. – chux

4

Sử dụng fgetsstrtol,

Một con trỏ tới ký tự đầu tiên sau khi đại diện số nguyên trong s được lưu trữ trong các đối tượng được trỏ bởi p, nếu *p là khác nhau để \n sau đó bạn có một đầu vào xấu.

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    char *p, s[100]; 
    int n; 

    while (fgets(s, sizeof(s), stdin)) { 
     n = strtol(s, &p, 10); 
     if (p == s || *p != '\n') { 
      printf("Please enter an integer: "); 
     } else break; 
    } 
    printf("You entered: %d\n", n); 
    return 0; 
} 
+0

Nó có thể hữu ích để giải thích lý do tại sao bạn thay đổi những gì bạn đã làm. Tại thời điểm này có vẻ như bạn chỉ đơn giản là đã làm nó theo phong cách của bạn – raam86

+0

@ raam86 ... về cơ bản sao chép câu trả lời của tôi. –

+5

@ TheParamagneticCroissant, tôi đã không đọc câu trả lời của bạn, bạn có nghĩ rằng bạn là người duy nhất sử dụng 'fgets' và' strtol'? ;) –

3

tôi biết làm thế nào điều này có thể được thực hiện bằng fgetsstrtol, tôi muốn biết làm thế nào điều này có thể được thực hiện bằng scanf() (nếu có thể).

Như câu trả lời khác nói, scanf là không thực sự phù hợp cho điều này, fgetsstrtol là một thay thế (mặc dù fgets có nhược điểm mà thật khó để phát hiện một 0-byte trong đầu vào và không thể nói gì đã được nhập sau một byte 0, nếu có).

Đối với lợi ích của đầy đủ (và giả định đầu vào hợp lệ là một số nguyên tiếp theo là một dòng mới):

while(scanf("%d%1[\n]", &n, (char [2]){ 0 }) < 2) 

Ngoài ra, sử dụng %n trước và sau khi %*1[\n] với nhiệm vụ đàn áp.Tuy nhiên, hãy lưu ý (từ số Debian manpage):

Đây không phải là chuyển đổi, mặc dù nó có thể bị chặn bằng ký tự bỏ gán nhiệm vụ *. Tiêu chuẩn C cho biết: "Việc thực thi chỉ thị %n không tăng số lượng nhiệm vụ được trả lại khi hoàn thành việc thực thi" nhưng Corrigendum có vẻ mâu thuẫn với điều này. Có thể khôn ngoan không đưa ra bất kỳ giả định nào về ảnh hưởng của các chuyển đổi %n trên giá trị trả lại.

2

Nếu bạn đang thiết lập về việc sử dụng scanf, bạn có thể làm điều gì đó như sau:

int val; 
char follow; 
int read = scanf("%d%c", &val, &follow); 

if (read == 2) 
{ 
    if (isspace(follow)) 
    { 
    // input is an integer followed by whitespace, accept 
    } 
    else 
    { 
    // input is an integer followed by non-whitespace, reject 
    } 
} 
else if (read == 1) 
{ 
    // input is an integer followed by EOF, accept 
} 
else 
{ 
    // input is not an integer, reject 
} 
2

Sử dụng fgets() là tốt hơn.

Để chỉ giải quyết bằng cách sử dụng scanf() để nhập, hãy quét intchar sau đây.

int ReadUntilEOL(void) { 
    char ch; 
    int count; 
    while ((count = scanf("%c", &ch)) == 1 && ch != '\n') 
    ; // Consume char until \n or EOF or IO error 
    return count; 
} 

#include<stdio.h> 
int main(void) { 
    int n; 

    for (;;) { 
    printf("Please enter an integer: "); 
    char NextChar = '\n'; 
    int count = scanf("%d%c", &n, &NextChar); 
    if (count >= 1 && NextChar == '\n') 
     break; 
    if (ReadUntilEOL() == EOF) 
     return 1; // No valid input ever found 
    } 
    printf("You entered: %d\n", n); 
    return 0; 
} 

Cách tiếp cận này không tái nhắc nếu người dùng chỉ nhập màu trắng-không gian như chỉ Nhập.

+0

trong mỗi lần truyền qua vòng lặp, đặt NextChar = '\ 0'; Tuy nhiên, '\ n', trong một số hệ điều hành nhất định, là một mục đa char, do đó hãy xác định là 'int NextChar = 0 Sau đó, nó sẽ nhắc lại khi không có ký tự nào được nhập – user3629249

+0

@ user3629249 Cảm ơn ý tưởng - đừng nghĩ rằng nó sẽ hoạt động . Khi không có 'char' được nhập vào (ví dụ: chỉ' '\ n''), 'scanf()' sẽ không trả về cho đến khi một số khoảng trắng không được nhập vào. ''% D "' gây 'scanf()' để tiêu thụ khoảng trắng cho đến khi EOF hoặc không-trắng-không gian. Vì vậy, thiết lập 'NextChar' này hoặc điều đó sẽ không tạo sự khác biệt. – chux

+0

@chux Bạn sẽ sửa đổi điều này như thế nào nếu nó chỉ chấp nhận các số nguyên dương? Việc sửa đổi đầu tiên nếu 'if (count> = 1 && n> 0 && NextChar == '\ n')' doesnt dường như không hoạt động. Stdout không phản ứng nếu chúng ta đưa ra ví dụ '-125' nhưng chúng ta phải nhập lại một lần nữa để hiển thị một thông điệp. – BugShotGG

2

Một giải pháp khả thi là để suy nghĩ về nó ngược: Chấp nhận một phao như là đầu vào và từ chối đầu vào nếu phao không phải là một số nguyên:

int n; 
float f; 
printf("Please enter an integer: "); 
while(scanf("%f",&f)!=1 || (int)f != f) 
{ 
    ... 
} 
n = f; 

Mặc dù điều này cho phép người dùng nhập vào một cái gì đó giống như 12.0, hoặc 12e0, v.v.

+1

Lưu ý: Khi đầu vào là" abcd ", mã vẫn còn trong' stdin'. Ngoài ra, hãy thử điều này với đầu vào "2147483647" hoặc "0,9999999999". – chux

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