我在调试Vigenere的密码C中的实现时遇到了问题。使用文件输入(-f标志)时文件包含少于6个字符(+ 1 EOF)时出现错误,它吐出一些随机字符的数量以及预期的输入,我不知道为什么这是,虽然我怀疑它与我的问题的第二部分有关,即使用fread()时,我注意到这是Vigenere cipher in C
if(fread(fcontents, fsize, sizeof(char), file) != 1) {...}
将没有问题跑,而这
if(fread(fcontents, sizeof(char), fsize, file) != 1) {...}
不工作(即导致fread()返回1,并触发它下面的错误处理代码),根据here的回答,我希望是另一种方式,但我可能会误解某些内容。
我的完整代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define ENC 0 //Encrypt mode
#define DEC 1 //Decrypt mode
#define INP 0 //Commandline input mode
#define FLE 1 //File input mode
typedef struct {
char *password;
char *file_name;
char *input;
int edmode;
int ifmode;
} options;
void string_clean(char *source)
{
char *i = source;
char *j = source;
while(*j != 0) {
*i = *j++;
if(*i != ' ' && (isupper(*i) || islower(*i)))
i++;
}
*i = 0;
}
char *ftostr(char *file_name) //Takes a file name as input and returns a char* to the files contents, returns NULL pointer on faliure. Allocated string must be freed after use by parent function to prevent memory leaks.
{
FILE *file;
long int fsize;
char *fcontents;
if(!(file = fopen(file_name, "r"))) {
fprintf(stderr, "Error opening file \"%s\"!\n", file_name);
return NULL;
}
fseek(file, 0L, SEEK_END);
fsize = ftell(file);
rewind(file);
if(!(fcontents = malloc((fsize + 1) * sizeof(char)))) {
fclose(file);
fprintf(stderr, "Error allocating memory!");
return NULL;
}
if(fread(fcontents, fsize, sizeof(char), file) != 1) { //suspected buggy line
fclose(file);
free(fcontents);
fprintf(stderr, "Error copying file to memory!\n");
return NULL;
}
fclose(file);
return fcontents;
}
options parse_opts(int argc, char *argv[])
{
int c;
options args;
args.edmode = ENC; //enable encrypt mode by default
args.ifmode = INP; //enable commandline input mode by default
args.file_name = NULL;
args.password = NULL;
args.input = NULL;
opterr = 0;
while((c = getopt(argc, argv, "dep:i:f:")) != -1) {
switch(c) {
case 'e':
args.edmode = ENC;
break;
case 'd':
args.edmode = DEC;
break;
case 'p':
args.password = optarg;
break;
case 'i':
args.input = optarg;
args.ifmode = INP;
break;
case 'f':
args.file_name = optarg;
args.ifmode = FLE;
break;
case '?':
if(optopt == 'f' || optopt == 'p' || optopt == 'i')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if(isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
fprintf(stderr, "Usage: %s (-f file_name || -i input) -p password [options]\n"
"Optional: -e -d\n", argv[0]);
exit(-1);
}
}
return args;
}
char *vigenere_dec(char cipher_text[], char cipher[])
{
char *plain_text;
string_clean(cipher_text);
string_clean(cipher);
int plain_text_len = strlen(cipher_text);
int cipher_len = strlen(cipher);
if(!(plain_text = malloc((plain_text_len + 1) * sizeof(char))))
return 0;
for(int i = 0; i < cipher_len; i++) {
if(isupper(cipher[i]))
cipher[i] -= 'A';
else if(islower(cipher[i]))
cipher[i] -= 'a';
}
for(int i = 0, j = 0; i < plain_text_len; i++, j++) {
if(j == cipher_len)
j = 0;
if(isupper(cipher_text[i]))
cipher_text[i] -= 'A';
else if(islower(cipher_text[i]))
cipher_text[i] -= 'a';
plain_text[i] = ((cipher_text[i] - cipher[j]) % 26);
if(plain_text[i] < 0)
plain_text[i] += 26;
plain_text[i] += 'A';
}
return plain_text;
}
char *vigenere_enc(char plain[], char cipher[])
{
char *cipher_text;
string_clean(plain);
string_clean(cipher);
int plain_len = strlen(plain);
int cipher_len = strlen(cipher);
if(plain_len == 0 || cipher_len == 0)
return NULL;
if(!(cipher_text = malloc((plain_len + 1) * sizeof(char))))
return NULL;
for(int i = 0; i < cipher_len; i++) {
if(isupper(cipher[i]))
cipher[i] -= 'A';
else if(islower(cipher[i]))
cipher[i] -= 'a';
}
for(int i = 0, j = 0; i < plain_len; i++, j++) {
if(j == cipher_len)
j = 0;
if(isupper(plain[i]))
plain[i] -= 'A';
else if(islower(plain[i]))
plain[i] -= 'a';
cipher_text[i] = ((plain[i] + cipher[j]) % 26) + 'A';
}
return cipher_text;
}
int main(int argc, char *argv[])
{
options args;
char *output_text = NULL;
args = parse_opts(argc, argv);
if(args.password == NULL) {
fprintf(stderr, "Password uninitialised!\n");
exit(-1);
}
if(args.input == NULL && args.file_name == NULL) {
fprintf(stderr, "Input stream uninitialised!\n");
exit(-1);
}
if(args.ifmode == INP) {
if(args.edmode == ENC)
output_text = vigenere_enc(args.input, args.password);
else if(args.edmode == DEC)
output_text = vigenere_dec(args.input, args.password);
} else if(args.ifmode == FLE) {
if(!(args.input = ftostr(args.file_name)))
return -1;
if(args.edmode == ENC)
output_text = vigenere_enc(args.input, args.password);
else if(args.edmode == DEC)
output_text = vigenere_dec(args.input, args.password);
free(args.input);
}
puts(output_text);
free(output_text);
return 0;
}
'EOF'不是'char'。请提供[mcve](注意**最小**!)和“不起作用”是没有错误的描述。 – Olaf
“启用文件模式”是什么意思?除了要求的MCVE外,还请提供样品输入,预期产量和实际产量。 – kaylum
您引用了另一个问题,但未能看到'fread()'返回读取**项**的数量。所以如果你交换'size'和'count'参数,期望得到不同的结果(除非'fsize == 1')。 –