For循环中每个数组元素[i]都被赋值,为什么数组没有填入值?
Why array does not filled with values while For loop, in which each array element[i] is assign with variable?
代码编译正常。我尝试使用调试器,但无法找出问题所在。
每次迭代“c”都被填充,但似乎我尝试将此变量“c”分配给数组的方式没有任何反应,因此结束打印语句以“ciphertext:EMPTY NOTHING”
非常欢迎任何帮助或想法。我正在上课并尝试解决一组问题。我只是初学者,请不要评判:)
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, string argv[])
{
if(argc < 2 || argc<2 )
{
printf("Usage: ./caesar key \n");
return 1;
}
else if(argc == 2)
{
for (int i = 0; i < strlen(argv[1]); i++)
{
if(!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key \n");
return 1;
}
}
}
int key = atoi(argv[1]);
string initial_text = get_string("plaintext: ");
int cipher[strlen(initial_text)];
int i = 0;
int n = strlen(initial_text);
for (i = 0; i < n; i++)
{
int c = 0;
if (isupper(initial_text[i]))
{
c = (((int)initial_text[i] - 65 + key) % 26) + 65;
cipher[i] += c;
}
else if (islower(initial_text[i]))
{
c = (((int)initial_text[i] - 97 + key) % 26) + 97;
cipher[i] += c;
}
else
{
c=initial_text[i];
cipher[i] += c;
}
}
//////////////////
printf("ciphertext: %c\n", (char)cipher);
}
存在一些问题:
- 当您[可能]想要
char
. 时,将int
用于cipher
- 在
cipher
中没有为尾随的 0x00 [EOS] 字符串终止符定义足够的 space
- 不是设置最后的EOS。
- 在
printf
中使用 %c
而不是 %s
。
if ((argc < 2) || (argc < 2))
是错误的,可以用if (argc != 2)
代替。
- 因为
if
做了 return
,所以不再需要后续的 else if
检查。
- “硬接线”十进制 值(例如
65
代表 'A'
)。
- 在
for
循环的条件表达式中使用 strlen
。这将循环的 运行 时间从 O(n) 增加到 O(n^2)。
- 这可以替换为(例如)将数组元素与 0x00 进行比较。
- 使用
strtol
代替atoi
并检查结束可以在单个操作中进行解码和验证。
- 定义
argv
时不要使用 string
-- 使用 char **argv
.
- 您的
main
末尾缺少 return 0;
。
- 有很多重复的代码可以简化。
这是重构后的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// I don't have cs50 handy, so a quick hack ...
#define string char *
string
get_string(const char *prompt)
{
char buf[1000];
char *cp;
printf("%s",prompt);
fflush(stdout);
do {
cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
// IIRC, [real] get_string does heap allocation (vs. static buffer) but
// for demo purposes here, doesn't really matter
cp = strdup(buf);
} while (0);
return cp;
}
int
main(int argc, char **argv)
{
// check if there is exactly 2 arguments passing, otherwise prompt for a
// valid key(+return 1, to signal mistake)
if (argc != 2) {
printf("Usage: ./caesar key \n");
return 1;
}
// otherwise check if the key is only a digit and prompt for a valid
// key(+return 1, to signal mistake)
// loop through each character in the second argument and validate
char *arg = argv[1];
// convert a string to int variable to be used in transformation of letters
int key = strtol(arg,&arg,10);
if (*arg != 0) {
printf("Usage: ./caesar key \n");
return 1;
}
// prompt for plaintext
string initial_text = get_string("plaintext: ");
// create an array of int to store encrypted letters to then be converted
// in print by (char)
// NOTE: we need one extra to make room for the trailing EOS
char cipher[strlen(initial_text) + 1];
const char *src = initial_text;
char *dst = cipher;
for (int chr = *src++; chr != 0; chr = *src++, ++dst) {
if (isupper((unsigned char) chr)) {
*dst = (((chr - 'A') + key) % 26) + 'A';
continue;
}
if (islower((unsigned char) chr)) {
*dst = (((chr - 'a') + key) % 26) + 'a';
continue;
}
// for all none alphabetic symbols leave them as they are
*dst = chr;
}
// set the trailing EOS
*dst = 0;
// ////////////////
printf("ciphertext: %s\n", cipher);
return 0;
}
你可以这样写
if ( argc < 2 || argc<2 || argc < 2 )
而不是
if ( argc < 2 || argc<2 )
这是正确的,但没有意义。
随便写
if ( argc != 2 )
{
puts( "Usage: ./caesar key" );
return 1;
}
这条else语句
else if(argc == 2)
是多余的。删除它。
而不是这个 for 循环
for (int i = 0; i < strlen(argv[1]); i++)
{
if(!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key \n");
return 1;
}
}
写起来更简单
char *p;
unsigned long ley = strtoul( argv[1], &p, 10 );
if ( *p || key == ULLONG_MAX )
{
puts( "Usage: ./caesar key" );
return 1;
}
无需定义变长数组。您可以更改指针 initial_text
.
指向的原始字符串
引入变量n是多余的
int n = strlen(initial_text);
而不是循环
for (i = 0; i < n; i++)
你可以使用这个循环
for ( size_t i = 0; initial_text[i] != '[=18=]'; i++ )
而不是这些 if 语句
if (isupper(initial_text[i]))
和
else if (islower(initial_text[i]))
写起来会更安全
if ( isupper( ( unsigned char )initial_text[i]))
和
else if ( islower( ( unsigned char )initial_text[i] ) )
同时使用像 65 这样的幻数会使代码变得不可读。例如你可以
写
c = ( initial_text[i] - 'A' + key ) % ( 'Z' - 'A' + 1 ) + 'A';
和
c = ( initial_text[i] - 'a' + key ) % ( 'z' - 'a' + 1) + 'a';
and 而不是复合赋值运算符
cipher[i] += c;
你需要写
initial_text[i] = c;
此外,在 printf 的调用中,您使用了不正确的转换说明符 %c 和转换
printf( "ciphertext: %c\n", (char)cipher);
因为字符串应该就地更新,所以 printf 的调用看起来像
printf( "ciphertext: %s\n", initial_text );
代码编译正常。我尝试使用调试器,但无法找出问题所在。 每次迭代“c”都被填充,但似乎我尝试将此变量“c”分配给数组的方式没有任何反应,因此结束打印语句以“ciphertext:EMPTY NOTHING”
非常欢迎任何帮助或想法。我正在上课并尝试解决一组问题。我只是初学者,请不要评判:)
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, string argv[])
{
if(argc < 2 || argc<2 )
{
printf("Usage: ./caesar key \n");
return 1;
}
else if(argc == 2)
{
for (int i = 0; i < strlen(argv[1]); i++)
{
if(!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key \n");
return 1;
}
}
}
int key = atoi(argv[1]);
string initial_text = get_string("plaintext: ");
int cipher[strlen(initial_text)];
int i = 0;
int n = strlen(initial_text);
for (i = 0; i < n; i++)
{
int c = 0;
if (isupper(initial_text[i]))
{
c = (((int)initial_text[i] - 65 + key) % 26) + 65;
cipher[i] += c;
}
else if (islower(initial_text[i]))
{
c = (((int)initial_text[i] - 97 + key) % 26) + 97;
cipher[i] += c;
}
else
{
c=initial_text[i];
cipher[i] += c;
}
}
//////////////////
printf("ciphertext: %c\n", (char)cipher);
}
存在一些问题:
- 当您[可能]想要
char
. 时,将 - 在
cipher
中没有为尾随的 0x00 [EOS] 字符串终止符定义足够的 space - 不是设置最后的EOS。
- 在
printf
中使用%c
而不是%s
。 if ((argc < 2) || (argc < 2))
是错误的,可以用if (argc != 2)
代替。- 因为
if
做了return
,所以不再需要后续的else if
检查。 - “硬接线”十进制 值(例如
65
代表'A'
)。 - 在
for
循环的条件表达式中使用strlen
。这将循环的 运行 时间从 O(n) 增加到 O(n^2)。 - 这可以替换为(例如)将数组元素与 0x00 进行比较。
- 使用
strtol
代替atoi
并检查结束可以在单个操作中进行解码和验证。 - 定义
argv
时不要使用string
-- 使用char **argv
. - 您的
main
末尾缺少return 0;
。 - 有很多重复的代码可以简化。
int
用于cipher
这是重构后的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// I don't have cs50 handy, so a quick hack ...
#define string char *
string
get_string(const char *prompt)
{
char buf[1000];
char *cp;
printf("%s",prompt);
fflush(stdout);
do {
cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
// IIRC, [real] get_string does heap allocation (vs. static buffer) but
// for demo purposes here, doesn't really matter
cp = strdup(buf);
} while (0);
return cp;
}
int
main(int argc, char **argv)
{
// check if there is exactly 2 arguments passing, otherwise prompt for a
// valid key(+return 1, to signal mistake)
if (argc != 2) {
printf("Usage: ./caesar key \n");
return 1;
}
// otherwise check if the key is only a digit and prompt for a valid
// key(+return 1, to signal mistake)
// loop through each character in the second argument and validate
char *arg = argv[1];
// convert a string to int variable to be used in transformation of letters
int key = strtol(arg,&arg,10);
if (*arg != 0) {
printf("Usage: ./caesar key \n");
return 1;
}
// prompt for plaintext
string initial_text = get_string("plaintext: ");
// create an array of int to store encrypted letters to then be converted
// in print by (char)
// NOTE: we need one extra to make room for the trailing EOS
char cipher[strlen(initial_text) + 1];
const char *src = initial_text;
char *dst = cipher;
for (int chr = *src++; chr != 0; chr = *src++, ++dst) {
if (isupper((unsigned char) chr)) {
*dst = (((chr - 'A') + key) % 26) + 'A';
continue;
}
if (islower((unsigned char) chr)) {
*dst = (((chr - 'a') + key) % 26) + 'a';
continue;
}
// for all none alphabetic symbols leave them as they are
*dst = chr;
}
// set the trailing EOS
*dst = 0;
// ////////////////
printf("ciphertext: %s\n", cipher);
return 0;
}
你可以这样写
if ( argc < 2 || argc<2 || argc < 2 )
而不是
if ( argc < 2 || argc<2 )
这是正确的,但没有意义。
随便写
if ( argc != 2 )
{
puts( "Usage: ./caesar key" );
return 1;
}
这条else语句
else if(argc == 2)
是多余的。删除它。
而不是这个 for 循环
for (int i = 0; i < strlen(argv[1]); i++)
{
if(!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key \n");
return 1;
}
}
写起来更简单
char *p;
unsigned long ley = strtoul( argv[1], &p, 10 );
if ( *p || key == ULLONG_MAX )
{
puts( "Usage: ./caesar key" );
return 1;
}
无需定义变长数组。您可以更改指针 initial_text
.
引入变量n是多余的
int n = strlen(initial_text);
而不是循环
for (i = 0; i < n; i++)
你可以使用这个循环
for ( size_t i = 0; initial_text[i] != '[=18=]'; i++ )
而不是这些 if 语句
if (isupper(initial_text[i]))
和
else if (islower(initial_text[i]))
写起来会更安全
if ( isupper( ( unsigned char )initial_text[i]))
和
else if ( islower( ( unsigned char )initial_text[i] ) )
同时使用像 65 这样的幻数会使代码变得不可读。例如你可以
写
c = ( initial_text[i] - 'A' + key ) % ( 'Z' - 'A' + 1 ) + 'A';
和
c = ( initial_text[i] - 'a' + key ) % ( 'z' - 'a' + 1) + 'a';
and 而不是复合赋值运算符
cipher[i] += c;
你需要写
initial_text[i] = c;
此外,在 printf 的调用中,您使用了不正确的转换说明符 %c 和转换
printf( "ciphertext: %c\n", (char)cipher);
因为字符串应该就地更新,所以 printf 的调用看起来像
printf( "ciphertext: %s\n", initial_text );