이 코드에서 scanf()가 무한 루프를 일으키는 이유는 무엇입니까?
각 루프 사이클마다 하나씩 stdin의 숫자를 읽어내는 작은 C-프로그램이 있습니다.사용자가 일부 NaN을 입력하면 콘솔에 오류가 출력되고 입력 프롬프트가 다시 표시됩니다."0"을 입력하면 루프가 종료되고 지정된 양의/음의 값의 수가 콘솔에 인쇄되어야 합니다.프로그램은 다음과 같습니다.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
문제는 ("a"와 같이) 번호가 아닌 것을 입력하면 무한 루프 쓰기 "-> Err..."가 반복된다는 것입니다.이것은 scanf()의 문제라고 생각합니다만, 이 함수는 보다 안전한 함수로 대체될 수 있다는 것을 알고 있습니다만, 이 예는 printf/scanf, if-else, loops에 대해서만 알고 있는 초보자를 위한 것입니다.
질문의scanf() 답은 이미 C의 다른 모든 루프를 건너뛰고 다른 질문들을 훑어보았지만, 이 문제에 대한 해답은 아무것도 없습니다.
scanf는 형식 문자열과 일치하는 입력만 소비하고 사용된 문자 수를 반환합니다.형식 문자열과 일치하지 않는 문자가 있으면 검색이 중지되고 잘못된 문자가 여전히 버퍼에 남아 있습니다.다른 사람이 말했듯이 계속 진행하기 전에 잘못된 문자를 버퍼에서 삭제해야 합니다.이것은 꽤 지저분한 수정이지만, 문제가 되는 문자를 출력에서 삭제합니다.
char c = '0';
if (scanf("%d", &number) == 0) {
printf("Err. . .\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
//consume non-numeric chars from buffer
}
edit: 코드를 수정하여 모든 비메모리 문자를 한 번에 삭제합니다.숫자가 아닌 각 문자에 대해 더 이상 여러 개의 "오류"를 인쇄하지 않습니다.
여기 scanf의 개요가 있습니다.
루프를 계속하기 전에 버퍼를 플러시하면 될 것 같아요.이런 방법으로 작업을 수행할 수 있지만, 여기서는 내용을 테스트할 수 없습니다.
int c;
while((c = getchar()) != '\n' && c != EOF);
「 」의 문제로 인해scanf다른 답변에 의해 지적된 다른 접근방식을 사용하는 것을 고려해야 합니다.는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★.scanf심각한 입력 판독 및 처리를 하기에는 너무 제한적입니다. 한 줄 좋을 것 같아요.fgets '하다, 하다, 하다, 하다' 등의 을 합니다.strtok ★★★★★★★★★★★★★★★★★」strtol(BTW는 정수를 올바르게 해석하여 비활성 문자의 정확한 시작 위치를 알려줍니다).
「」를 사용하는 에, 「」를 합니다.scanf()하지 않은.fgets() ★★★★★★★★★★★★★★★★★」sscanf().
/* ... */
printf("0 to quit -> ");
fflush(stdout);
while (fgets(buf, sizeof buf, stdin)) {
if (sscanf(buf, "%d", &number) != 1) {
fprintf(stderr, "Err...\n");
} else {
work(number);
}
printf("0 to quit -> ");
fflush(stdout);
}
/* ... */
scanf() 남기다a"는 다음 번을 위해 입력 버퍼에 남아 있습니다.도 아마 '어느 정도'를 할 것 같아요.getline() strtol()또는 유사합니다.
.getline()는 POSIX가 GNU의 것입니다.linux라는가 붙어 있습니다"gcc" 또는 "linux"를 사용합니다. getline()모든 것을 수작업으로 하는 경우를 제외하고, 텍스트의 행을 읽는 것은, 이 방법 밖에 없습니다).
안녕, 나는 이것이 오래된 실이라는 것을 알지만 나는 방금 학교 과제를 끝냈는데, 거기서 나는 이 같은 문제에 부딪혔다.해결방법은 gets()를 사용하여 scanf()가 남긴 것을 픽업하는 것입니다.
여기 OP 코드가 약간 다시 작성되어 있습니다.아마 그는 쓸모가 없을 것입니다만, 다른 사람에게 도움이 될 것입니다.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
char unwantedCharacters[40]; //created array to catch unwanted input
unwantedCharacters[0] = 0; //initialzed first byte of array to zero
while (1)
{
printf("-> ");
scanf("%d", &number);
gets(unwantedCharacters); //collect what scanf() wouldn't from the input stream
if (unwantedCharacters[0] == 0) //if unwantedCharacters array is empty (the user's input is valid)
{
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
else
printf("Err...\n");
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
좋은 저녁입니다.저도 최근에 같은 문제를 겪었는데 많은 남자들에게 도움이 될 만한 해결책을 찾았어요.음, 실제로 "scanf" 함수는 메모리에 버퍼를 남깁니다. 그래서 무한 루프가 발생합니다.따라서 초기 스캔에 "null" 값이 포함된 경우 이 버퍼를 다른 변수에 "저장"해야 합니다.제 말은 이렇습니다.
#include <stdio.h>
int n;
char c[5];
main() {
while (1) {
printf("Input Number: ");
if (scanf("%d", &n)==0) { //if you type char scanf gets null value
scanf("%s", &c); //the abovementioned char stored in 'c'
printf("That wasn't a number: %s\n", c);
}
else printf("The number is: %d\n", n);
}
}
// all you need is to clear the buffer!
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
char clearBuf[256]; //JG:
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fgets(stdin, 256, clearBuf); //JG:
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
솔루션:를 추가해야 합니다.fflush(stdin); 때0scanf.
이유:오류가 발생했을 때 입력 문자를 버퍼에 남기는 것처럼 보이므로 매번scanf무효 문자를 계속 처리하려고 할 뿐 버퍼에서 삭제하지 않습니다.했을 때fflush 」 。
수정한 프로그램:아래는 필요한 변경 사항을 적용하여 수정한 프로그램입니다.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
및 에서는 "Windows" Linux" 를 사용할 수 .서는fflush(stdin);:
#include <stdio.h>
int main(void)
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
fflush(stdin);
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
저도 비슷한 문제가 있었어요.scanf만 사용해서 해결했어요.
Input "abc123<Enter>"어떻게 동작하는지 확인하세요.
#include <stdio.h>
int n, num_ok;
char c;
main() {
while (1) {
printf("Input Number: ");
num_ok = scanf("%d", &n);
if (num_ok != 1) {
scanf("%c", &c);
printf("That wasn't a number: %c\n", c);
} else {
printf("The number is: %d\n", n);
}
}
}
다음을 사용해 보십시오.
if (scanf("%d", &number) == 0) {
printf("Err...\n");
break;
}
이건 나한테 잘 먹혔어...이거 먹어봐..continue 문은 Error로 적절하지 않습니다.한 번만 실행할 수 있습니다. 그러니 제가 테스트한 것을 깨보세요.이게 너한테는 잘 먹혔어테스트...
비숫자를 입력하면 오류가 발생하며 비숫자는 계속 입력 버퍼에 저장됩니다.건너 뛰어야 해요. 이 ' 조합'입니다.1a처음에는 1번으로 읽히겠지만 그런 입력도 건너뛰는 게 좋을 것 같아요.
프로그램은 다음과 같이 표시될 수 있습니다.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int p = 0, n = 0;
while (1)
{
char c;
int number;
int success;
printf("-> ");
success = scanf("%d%c", &number, &c);
if ( success != EOF )
{
success = success == 2 && isspace( ( unsigned char )c );
}
if ( ( success == EOF ) || ( success && number == 0 ) ) break;
if ( !success )
{
scanf("%*[^ \t\n]");
clearerr(stdin);
}
else if ( number > 0 )
{
++p;
}
else if ( number < n )
{
++n;
}
}
printf( "\nRead %d positive and %d negative numbers\n", p, n );
return 0;
}
프로그램 출력은 다음과 같습니다.
-> 1
-> -1
-> 2
-> -2
-> 0a
-> -0a
-> a0
-> -a0
-> 3
-> -3
-> 0
Read 3 positive and 3 negative numbers
저도 같은 문제를 겪었는데, 어느 정도 진부한 해결책을 찾았어요.사용하고 있다fgets()sscanf()무한 루프 문제에 대한 수정은 나쁘지 않습니다.단순한 for 루프에서는 C에게 숫자가 아닌 문자를 검색하도록 지시합니다.되지 않습니다.123abc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char line[10];
int loop, arrayLength, number, nan;
arrayLength = sizeof(line) / sizeof(char);
do {
nan = 0;
printf("Please enter a number:\n");
fgets(line, arrayLength, stdin);
for(loop = 0; loop < arrayLength; loop++) { // search for any none numeric charcter inisde the line array
if(line[loop] == '\n') { // stop the search if there is a carrage return
break;
}
if((line[0] == '-' || line[0] == '+') && loop == 0) { // Exculude the sign charcters infront of numbers so the program can accept both negative and positive numbers
continue;
}
if(!isdigit(line[loop])) { // if there is a none numeric character then add one to nan and break the loop
nan++;
break;
}
}
} while(nan || strlen(line) == 1); // check if there is any NaN or the user has just hit enter
sscanf(line, "%d", &number);
printf("You enterd number %d\n", number);
return 0;
}
문제를 해결하기 위해 스캔프 뒤에 다음 행을 추가합니다.
fgetc(stdin); /* to delete '\n' character */
아래 행이 표시된 코드:
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fgetc(stdin); /* to delete '\n' character */
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
그러나 여러 문자를 입력하면 프로그램은 "\n"까지 한 글자씩 계속됩니다.
그래서 저는 여기서 해결책을 찾았습니다.scanf를 사용하여 입력 길이를 제한하는 방법
다음 행을 사용할 수 있습니다.
int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
스캔하기 전에 입력 버퍼를 플러시합니다.
while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
...
가 제안하려고 fflush(stdin)단, 그 결과 정의되지 않은 동작이 발생한다고 합니다.
코멘트에 응답하여 프롬프트를 표시하려면 출력 버퍼를 플러시해야 합니다.기본적으로는 새 줄을 인쇄할 때만 발생합니다.예를 들어 다음과 같습니다.
while (1) {
printf("-> ");
fflush(stdout);
while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
...
언급URL : https://stackoverflow.com/questions/1716013/why-is-scanf-causing-infinite-loop-in-this-code
'source' 카테고리의 다른 글
| 파이어베이스를 만들려고 시도하고 있습니다.auth().current 사용자 약속 (0) | 2022.08.24 |
|---|---|
| Android/Java에서의 JSON 어레이 반복 (0) | 2022.08.24 |
| Java에서 문자열을 InputStream으로 변환하려면 어떻게 해야 하나요? (0) | 2022.08.24 |
| 페이지피드 통찰력이 "blob" 압축 및 캐시를 수정하도록 요구하는 이유는 무엇입니까? (0) | 2022.08.24 |
| java.util 복사 방법다른 java.util에 나열합니다.목록. (0) | 2022.08.24 |