2012-10-15 3 views
0

첫 번째 scanf()가 사용되고 Y로 대답하면 두 번째 scanf()는 "No option selected, Exiting ..."로 바로 건너 뜁니다. 이 메시지는 keyfile이 sourcefile보다 크고 마지막 scanf가 제대로 작동하면 나타납니다. 그래서 내가 여기서 잃어버린거야, 뭐가 잘못 됐니? (코드는 멋지게 컴파일되므로 자유롭게 시도하십시오.)C - scanf misbehaving

편집 : 적어도 이유를 게시하는 것이 downvoters에게 도움이 될 것입니다. 나는 아주 좋은 프로그래머가 아니며 여기서 배우려고하고있다.

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/stat.h> 

int main(int argc, char **argv) 
{ 
struct stat statbuf; 
struct stat keybuf; 

int key; 
int data; 
int output; 
int count; 
char ans; 
FILE * keyfile; 
FILE * sourcefile; 
FILE * destfile; 

if(argc<4) 
{ 
printf("OTP-Bunny 1.0\n"); 
printf("USAGE: OTP <source file> <output file> <keyfile>\n"); 
return (0); 
} 

/* Check number of arguments. */ 
if(argc>4) 
{ 
printf("Too many arguments.\n"); 
printf("USAGE: OTP <source file> <output file> <keyfile>\n"); 
return(1); 
} 

/* Check if sourcefile can be opened. */ 
if((sourcefile = fopen(argv[1], "rb"))== NULL) 
{ 
printf("Can't open source file.\n"); 
printf("Please enter a valid filename.\n"); 
printf("USAGE: OTP <source file> <output file> <keyfile>\n"); 
perror("Error"); 
return (1); 
} 

/* Get size of sourcefile */ 
fstat(fileno(sourcefile), &statbuf); 

/* Check if keyfile can be opened. */ 
if((keyfile = fopen(argv[3], "rb"))== NULL) 
{ 
printf("Can't open keyfile.\n"); 
printf("Please enter a valid filename.\n"); 
printf("USAGE: OTP <source file> <output file> <keyfile>\n"); 
perror("Error"); 
return(1); 
}        

/* Get size of keyfile */ 
fstat(fileno(keyfile), &keybuf); 

/* Check if keyfile is the same size as, or bigger than the sourcefile */ 
if((keybuf.st_size) < (statbuf.st_size)) 
{ 
printf("Source file is larger than keyfile.\n"); 
printf("This significantly reduces cryptographic strength.\n"); 
printf("Do you wish to continue? (Y/N)\n"); 
scanf("%c", &ans); 
if(ans == 'n' || ans == 'N') 
{ 
return (1); 
} 
if(ans == 'y' || ans == 'Y') 
{ 
    printf("Proceeding with Encryption/Decryption.\n"); 
    } 
else 
{ 
printf("No option selected. Exiting...\n"); 
return (1); 
} 
} 

/* Check if destfile can be opened. */ 
if((keyfile = fopen(argv[2], "wb"))== NULL) 
{ 
printf("Can't open output file.\n"); 
perror("Error"); 
return(1);     
}  

/* Open destfile. */ 
destfile=fopen(argv[2], "wb"); 

/* Encrypt/Decrypt and write to output file. */ 
while(count < (statbuf.st_size)) 
{ 
key=fgetc(keyfile); 
data=fgetc(sourcefile); 

output=(key^data); 

fputc(output,destfile); 
count++; 
} 

/* Close files. */ 
fclose(keyfile); 
fclose(sourcefile); 
fclose(destfile); 

printf("Encryption/Decryption Complete.\n"); 

/* Delete keyfile option. */ 
printf("Do you wish to delete the keyfile? (Y/N)\n"); 
scanf("%c", &ans); 
if(ans == 'y' || ans == 'Y') 
{ 
if (remove(argv[3]) == 0) 
    { 
    printf("File deleted successfully.\n"); 
    } 
else 
    { 
    printf("Unable to delete the file.\n"); 
    perror("Error"); 
    return(1); 
    } 
} 

if(ans == 'n' || ans == 'N') 
{ 
return(0); 
} 
else 
{ 
printf("No option selected. Exiting...\n"); 
} 
return(0); 
} 
+0

오류 메시지에는 열 수없는 파일 이름이 포함되어야합니다 (예 : 사용자에게 호의). 에러 메시지는'stderr'에 쓰여지는 것이 아니라'stdout'에 쓰여 져야합니다. 오류보고 기능을 생각해보십시오. –

답변

6

실제로는 scanf()이 올바르게 작동하지만 올바르게 사용하는 것은 매우 까다로운 기능이며 문서화 된 동작과 기대치가 다를 수 있습니다.

첫 번째 scanf() 호출은 개행 문자를 그대로두고 한 문자를 읽습니다.

두 번째 scanf() 호출은 줄 바꿈을 읽습니다. 그 다음은 문제가됩니다.

" %c"을 사용하여 코드를 수정할 수 있습니다. 선행 공백은 공백을 건너 뜁니다 (선택 사항).

일반적으로 더 좋은 해결 방법은 fgets() 또는 동급 (POSIX 2008의 경우 readline() 일 것임) 및 sscanf()의 조합을 사용하는 것입니다. fgets()으로 메모리의 데이터 라인을 읽습니다. sscanf()으로 분석하십시오. 그렇게하면 오류를 더 잘보고 할 수 있습니다. 사용자가 입력 한 모든 정보를 오류보고에 사용할 수 있습니다.

+1

사용자가 하나의 입력 후에 개행을 입력하지 않으면이 작업이 수행됩니다. 표준 c에서 fgets 또는 유사한 함수를 사용하는 것이 항상 더 좋습니다. – fayyazkl

-1

이는 공백이나 개행 발생한 경우에만 입력을 받아, 다음 명령문에 대한 입력으로서 취해진 다 입력 버퍼에서의 \ N 잎는 scanf 즉 표준 동작이다.

각 호출 후에 cin.ignore()를 사용하면 C++가 아닌 strictc를 사용하지 않는 한 피할 수 있습니다. 이 경우 fgets 일 수도 있습니다.

+2

C에서'cin.ignore()'를 사용할 수 없습니다 - C++에서도 잘 작동 할 것입니다. –

+0

확실히 C++에서 작동하며 일반적으로 사용자가 지정하지 않으면 엄격한 c가 아니기 때문에 좋은 조언입니다. C는 보통 사람을 플러시 할 수있는 좋은 방법이 없습니다. \ n 또는 새로운 줄을 만나지 않을 때까지 반복하십시오. 그러므로 나는 위에 제안했다. 그래도 C++ 표시를 추가했습니다. – fayyazkl