2012-10-15 20 views
0

當使用第一個scanf()並且你回答Y時,第二個scanf()直接跳到「沒有選擇選項退出......」。當密鑰文件比大的資源文件,最後scanf函數它正確的工作也出現該消息。所以我在這裏虧本,出了什麼問題? (代碼編譯很好,所以隨時嘗試)C-scanf行爲不端

編輯:這將有助於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而不是C++。在這種情況下,使用可能是fgets是好得多

+2

不能在C中使用'cin.ignore()',但它可能在C++中工作。 –

+0

它當然可以在C++中工作,因爲通常用戶不是嚴格的c,除非指定,這是一個很好的建議。 C沒有一個像樣的辦法通常人們直到沒有遇到新行添加\ n或循環沖洗。因此我在上面建議。儘管如此,添加C++指示 – fayyazkl