C中的strcat()和fgets()不起作用

时间:2014-05-12 14:33:10

标签: c string fgets strcat

由于某种原因,我无法获得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)"

更新

当我声明这两个字符串时,存在一些内存重叠。当我在两个字符串之间声明一个随机整数时,它保留了两者的输入。如何使用更永久的解决方案修复此内存重叠?

3 个答案:

答案 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,那么唯一更改的代码行是userNamepassword的声明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 ..