无法找出为什么我的程序没有执行它应该执行的操作
Can't find out why my program isn't doing what it's supposed to do
作为我目前正在参加的 CS50 哈佛编程课程的一部分,我正在做一个名为 "Vigenere" 的练习。
除了我收到以 b
开头的输入时,我的程序一切正常(它逐行执行并且符合预期的行为)。
一旦它到达输入字符串的末尾,它就不会循环回到数组中的第一个字符,但如果输入不是以 b 开头,它会正常工作。
一直在谷歌搜索、调试,但就是想不通。也尝试过很多其他不同的方式,但我就是无法让它工作。
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Error.\n");
return (1);
}
string input = argv[1];
for (int i = 0; input[i] != '[=10=]'; i++)
{
if (!isalpha(input[i]))
{
printf("Error.\n");
return (1);
}
}
string plaintext = get_string("plaintext: ");
string cipher = argv[1];
printf("ciphertext: ");
int i = 0;
int j = 0;
int code = 0;
while (plaintext[i] != '[=10=]')
{
if (cipher[j] >= 97)
{
cipher[j] = cipher[j] - 97;
}
if (isupper(cipher[j]))
{
cipher[j] = cipher[j] - 65;
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
i++;
}
printf("\n");
return (0);
}
如上所述,只要我的命令行输入以 b 开头,程序就无法按预期运行。当输入不是 b 时不会发生。
因为您将 cipher[j]
中的字符从 ASCII 代码更改为 "ABC...XYZ" 的索引,所以以下比较无法检测键码的结尾:
if (cipher[j] == '[=10=]' ...
一个'A'或'a'将变成值0,与'\0'相同。因此,导致该行为的不是前导 'b',而是后面的 'a'。
将它放在循环中的重要位置,您会立即看到它:
printf("%d %d %02X %02X\n", i, j, cipher[j], plaintext[i]);
您在代码中进行的 cipher 操作会导致 j 始终为零并导致重复打印第一个字符。
这是由于 ascii -> 非 ascii -> ascii 的行为引起的,这是来自加密过程
为了解决这个问题,您只需要使用 cipher 的值,而不是在条件中对其进行操作。
我所做的是将值复制到不同的 pointer 并保持条件以引用原始 char 的原始 cipher 使用 malloc 和 memset.
代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *input = argv[1];
for (int i = 0; input[i] != '[=10=]'; i++)
{
if (!isalpha(input[i]))
{
printf("Error.\n");
return (1);
}
}
char *plaintext = "aaaaaaa";
char *cipher = argv[1];
//<============================
char *moving_cipher;
moving_cipher = (char *) malloc(3);
memcpy(moving_cipher, cipher, 3);
//<============================
printf("ciphertext: ");
int i = 0;
int j = 0;
int code = 0;
while (plaintext[i] != '[=10=]')
{
if (cipher[j] >= 97)
{
moving_cipher[j] = cipher[j] - 97;
}
if (isupper(cipher[j]))
{
moving_cipher[j] = cipher[j] - 65;
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + moving_cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + moving_cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
i++;
}
printf("\n");
return (0);
}
注意事项:
正如您在评论中所写,我检查了有问题的输入,这就是为什么您需要以聪明的方式找到所需的大小而不是硬编码的原因。
输入:"baz"
修复前的输出:"bazbbbb"
修复后输出:"bazbazb"
建议代码如下:
- 不使用不可移植的库
cs50
- 正确输出错误信息到
stderr
- 执行所需的功能
- 干净地编译
现在,建议的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf( stderr, "USAGE: %s cypherKey\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, user entered correct number of parameters
char * cipher = argv[1];
for (int i = 0; cipher[i] != '[=10=]'; i++)
{
if (!isalpha( cipher[i]))
{
fprintf( stderr, "key must be all alphabetic characters\n");
exit( EXIT_FAILURE );
}
}
// implied else, key all alphabetic characters
char plaintext[1024];
puts( "Please enter the plain text" );
if( !fgets( plaintext, sizeof(plaintext), stdin ) )
{
perror( "fgets to input plain text failed" );
exit( EXIT_FAILURE );
}
//implied else, fgets successful
// remove possible trailing newline
plaintext[ strcspn( plaintext, "\n" ) ] = '[=10=]';
printf("ciphertext: ");
for( int j = 0, i = 0; plaintext[i]; i++ )
{
if (cipher[j] >= 97)
{
cipher[j] = (char)(cipher[j] - 97);
}
if (isupper(cipher[j]))
{
cipher[j] = (char)(cipher[j] - 65);
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
}
printf("\n");
return (0);
}
以下是程序的几个典型运行
./untitled 是可执行文件
./untitled
USAGE: ./untitled cypherKey
./untitled abcd
Please enter the plain text
This is a plain text message
ciphertext: Tikv it c slbkq tfzw mfuvahg
./untitled bcda
Please enter the plain text
This is a plain text message
ciphertext: Ujls ju d qndjp wfzw ngvtcjf
作为我目前正在参加的 CS50 哈佛编程课程的一部分,我正在做一个名为 "Vigenere" 的练习。
除了我收到以 b
开头的输入时,我的程序一切正常(它逐行执行并且符合预期的行为)。
一旦它到达输入字符串的末尾,它就不会循环回到数组中的第一个字符,但如果输入不是以 b 开头,它会正常工作。
一直在谷歌搜索、调试,但就是想不通。也尝试过很多其他不同的方式,但我就是无法让它工作。
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Error.\n");
return (1);
}
string input = argv[1];
for (int i = 0; input[i] != '[=10=]'; i++)
{
if (!isalpha(input[i]))
{
printf("Error.\n");
return (1);
}
}
string plaintext = get_string("plaintext: ");
string cipher = argv[1];
printf("ciphertext: ");
int i = 0;
int j = 0;
int code = 0;
while (plaintext[i] != '[=10=]')
{
if (cipher[j] >= 97)
{
cipher[j] = cipher[j] - 97;
}
if (isupper(cipher[j]))
{
cipher[j] = cipher[j] - 65;
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
i++;
}
printf("\n");
return (0);
}
如上所述,只要我的命令行输入以 b 开头,程序就无法按预期运行。当输入不是 b 时不会发生。
因为您将 cipher[j]
中的字符从 ASCII 代码更改为 "ABC...XYZ" 的索引,所以以下比较无法检测键码的结尾:
if (cipher[j] == '[=10=]' ...
一个'A'或'a'将变成值0,与'\0'相同。因此,导致该行为的不是前导 'b',而是后面的 'a'。
将它放在循环中的重要位置,您会立即看到它:
printf("%d %d %02X %02X\n", i, j, cipher[j], plaintext[i]);
您在代码中进行的 cipher 操作会导致 j 始终为零并导致重复打印第一个字符。
这是由于 ascii -> 非 ascii -> ascii 的行为引起的,这是来自加密过程
为了解决这个问题,您只需要使用 cipher 的值,而不是在条件中对其进行操作。 我所做的是将值复制到不同的 pointer 并保持条件以引用原始 char 的原始 cipher 使用 malloc 和 memset.
代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *input = argv[1];
for (int i = 0; input[i] != '[=10=]'; i++)
{
if (!isalpha(input[i]))
{
printf("Error.\n");
return (1);
}
}
char *plaintext = "aaaaaaa";
char *cipher = argv[1];
//<============================
char *moving_cipher;
moving_cipher = (char *) malloc(3);
memcpy(moving_cipher, cipher, 3);
//<============================
printf("ciphertext: ");
int i = 0;
int j = 0;
int code = 0;
while (plaintext[i] != '[=10=]')
{
if (cipher[j] >= 97)
{
moving_cipher[j] = cipher[j] - 97;
}
if (isupper(cipher[j]))
{
moving_cipher[j] = cipher[j] - 65;
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + moving_cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + moving_cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
i++;
}
printf("\n");
return (0);
}
注意事项: 正如您在评论中所写,我检查了有问题的输入,这就是为什么您需要以聪明的方式找到所需的大小而不是硬编码的原因。
输入:"baz"
修复前的输出:"bazbbbb"
修复后输出:"bazbazb"
建议代码如下:
- 不使用不可移植的库
cs50
- 正确输出错误信息到
stderr
- 执行所需的功能
- 干净地编译
现在,建议的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf( stderr, "USAGE: %s cypherKey\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, user entered correct number of parameters
char * cipher = argv[1];
for (int i = 0; cipher[i] != '[=10=]'; i++)
{
if (!isalpha( cipher[i]))
{
fprintf( stderr, "key must be all alphabetic characters\n");
exit( EXIT_FAILURE );
}
}
// implied else, key all alphabetic characters
char plaintext[1024];
puts( "Please enter the plain text" );
if( !fgets( plaintext, sizeof(plaintext), stdin ) )
{
perror( "fgets to input plain text failed" );
exit( EXIT_FAILURE );
}
//implied else, fgets successful
// remove possible trailing newline
plaintext[ strcspn( plaintext, "\n" ) ] = '[=10=]';
printf("ciphertext: ");
for( int j = 0, i = 0; plaintext[i]; i++ )
{
if (cipher[j] >= 97)
{
cipher[j] = (char)(cipher[j] - 97);
}
if (isupper(cipher[j]))
{
cipher[j] = (char)(cipher[j] - 65);
}
if (islower(plaintext[i]))
{
printf("%c", 'a' + (plaintext[i] - 'a' + cipher[j]) % 26);
j++;
}
if (isupper(plaintext[i]))
{
printf("%c", 'A' + (plaintext[i] - 'A' + cipher[j]) % 26);
j++;
}
if (plaintext[i] == ' ')
{
printf("%c", plaintext[i]);
}
if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
{
printf("%c", plaintext[i]);
}
if (cipher[j] == '[=10=]' && plaintext[i] != ' ')
{
j = 0;
}
}
printf("\n");
return (0);
}
以下是程序的几个典型运行
./untitled 是可执行文件
./untitled
USAGE: ./untitled cypherKey
./untitled abcd
Please enter the plain text
This is a plain text message
ciphertext: Tikv it c slbkq tfzw mfuvahg
./untitled bcda
Please enter the plain text
This is a plain text message
ciphertext: Ujls ju d qndjp wfzw ngvtcjf