由于某种原因,我无法获得fgets()
和strcat()
的两个实例。
这是我的代码:
#include <stdio.h>
#include <string.h>
int main()
{
char str[150];
char userName[8]; char password[8];
printf("Enter username: ");fgets(userName, 9, stdin);
printf("Enter password: ");scanf("%s", password);
strcpy(str, "INSERT INTO USERS (ID,USERNAME,PASSWORD,IP) " \
"VALUES (1, '");
strcat(str, userName);
strcat(str, "', '");
strcat(str, password);
strcat(str, "', '120.132.12.1');");
puts(str);
return 0;
}
获取&#34;密码&#34;的字符串时,我无法使用fgets()
或者它会抛出错误&#34;中止陷阱:6&#34;。具体来说我正在使用:
fgets(password, 9, stdin);
9个元素因为我读过你需要在你的总数中考虑空终止字符。
我不明白这一点,因为char数组中的元素与userName一样多,我认为获取字符串的代码实际上应该与char数组名称相同。
此外,strcat()
似乎在尝试追加&#34; str&#34;时似乎无效。使用userName。我的输出看起来像这样:
Enter username: beckah12
Enter password: beckah12
INSERT INTO USERS (ID,USERNAME,PASSWORD,IP) VALUES (1, '', 'beckah12', '120.132.12.1')
为什么跳过"strcpy(str, userName)"
?
当我声明这两个字符串时,存在一些内存重叠。当我在两个字符串之间声明一个随机整数时,它保留了两者的输入。如何使用更永久的解决方案修复此内存重叠?
答案 0 :(得分:3)
对于您正确声明的fgets()
:
9个元素因为我读过你需要在你的总数中考虑空终止字符。
但是在你的变量声明中你忘了它:
char userName[8]; char password[8];
让他们char ....[9]
,你的程序不应该再中止。
但,正如@chux所说:
如果您阅读完整的文本行,您还必须处理新行字符,这会使您的代码类似:
char userName[10]; char password[10];
...
fgets( userName, sizeof userName, stdin );
if( userName[strlen(userName)-1] == '\n' ) {
//truncate new line character
userName[strlen(userName)-1] = '\0';
}
...如果有人输入超过8个字符的名称或密码,您仍会遇到问题。所以我建议:
#define L_USER 8
char userName[256]; char password[256];
...
fgets( userName, sizeof userName, stdin );
if( strlen(userName) > L_USER ) {
//truncate name if too long
userName[L_USER] = '\0';
}
if( userName[strlen(userName)-1] == '\n' ) {
//truncate new line character
userName[strlen(userName)-1] = '\0';
}
答案 1 :(得分:3)
这是彻底改写,但也很有效。这更符合我的用途:
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int prompt_for_data(const char *prompt, const char *what, char *buffer, size_t buflen)
{
char line[256];
assert(prompt != 0 && *prompt != '\0');
assert(what != 0 && *what != '\0');
assert(buffer != 0);
assert(buflen > 1 && buflen < sizeof(line));
printf("%s", prompt);
if (fgets(line, sizeof(line), stdin) == 0)
{
fprintf(stderr, "EOF\n");
return EOF;
}
size_t len = strlen(line);
if (len == 0)
{
fprintf(stderr, "Zero length string? You can't use Control-@ in a %s\n",
what);
return EOF;
}
if (line[len - 1] != '\n')
{
fprintf(stderr, "Line far too long (%zu bytes)\n", len);
return EOF;
}
line[--len] = '\0';
/* Optionally chop leading and trailing white space - omitted */
if (len > buflen - 1)
{
fprintf(stderr, "Maximum length of %s is %zu (you entered %zu characters)\n",
what, buflen - 1, len);
return EOF;
}
if (len == 0)
{
fprintf(stderr, "You're supposed to enter a value for the %s\n", what);
return EOF;
}
strcpy(buffer, line);
return 0;
}
int main(void)
{
char userName[9];
char password[9];
if (prompt_for_data("Enter username: ", "username", userName, sizeof(userName)) == 0 &&
prompt_for_data("Enter password: ", "password", password, sizeof(password)) == 0)
{
char str[150];
snprintf(str, sizeof(str),
"INSERT INTO USERS (ID, USERNAME, PASSWORD, IP) VALUES"
"(%d, '%s', '%s', '%s');",
1, userName, password, "120.132.12.1");
puts(str);
}
return 0;
}
“提示输入值,读取一行,检查其长度,将其复制到所需变量”的序列封装在prompt_for_data()
函数中。它然后被使用了两次(但我可能将它写为函数,即使它只被调用一次)来获取用户名和密码。然后,我使用strcat()
来创建输出字符串,而不是使用snprintf()
。
您还应该注意,如果您想要从古怪的8个字符更改用户名和密码的大小加上将null终止为32,那么唯一更改的代码行是userName
和password
的声明sizeof(userName)
。这是因为我需要在描述大小时仔细使用sizeof(password)
或fgets()
。与其他变量类似;例如,如果我更改line
变量的大小,O'Reilly
行不会更改。通常,最好在更改变量大小时尽量减少必要更改的数量。
请注意,您仍然遇到SQL注入问题。如果我输入“$ ./up
Enter username: beckah12
Enter password: beckah12
INSERT INTO USERS (ID, USERNAME, PASSWORD, IP) VALUES(1, 'beckah12', 'beckah12', '120.132.12.1');
$ ./up
Enter username: absolom12
Maximum length of username is 8 (you entered 9 characters)
$ ./up
Enter username: beckah12
Enter password: absolom12
Maximum length of password is 8 (you entered 9 characters)
$ ./up
Enter username:
You're supposed to enter a value for the username
$ ./up
Enter username: beckah12
Enter password:
You're supposed to enter a value for the password
$ ./up
Enter username: EOF
$ ./up
Enter username: beckah12
Enter password: EOF
$ ./up
Enter username: nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
Line far too long (255 bytes)
$
”作为用户名,则SQL无效。记住Little Bobby Tables!关于短用户名的一件好事;它使SQL注入更难。
{{1}}
答案 2 :(得分:0)
更改行
char userName[8] to char userName[9]
char password[8] to char password[9]
因为这是您在fgets(userName, 9, stdin);
等中指定的内容。 al ..