-2
#include <conio.h>
#include <windows.h>
#include <stdio.h>

int main ()
{
char input[255];
int i = 0;
for(;;i++) /* Infinite loop, exited when RETURN is pressed */
{
    char temp;
    temp = getch (); /* Get the current character of the password */
    if (GetAsyncKeyState (VK_RETURN)) /* If the user has pressed return */
    {
        input[i]='\0';
        break;
    }
    input[i] = temp;
    printf("*"); /* Print a star */
}
//printf("%s",input);
if(strcmp(input,"kamal")==0)
{
                     printf("ACCEPTED");
                     }
                     else
                     printf("not");
_getch();
return EXIT_SUCCESS; /* Program was executed successfully */
}

这是我的代码。我怎样才能防止缓冲区溢出,如果我输入密码更多,那么我的程序就会崩溃。无论如何我可以克服这个问题吗?

4

5 回答 5

2

局部变量 char input[255] 存储在堆栈中。C 中没有对数组进行边界检查。问题是当我们添加超过 255 个字符时,存储在堆栈中的另一个变量的值可能会改变。这可能会导致崩溃。

一种解决方案是读取字符并仅在范围 (i) 小于 255 时分配给输入数组。

#include <conio.h>
#include <windows.h>
#include <stdio.h>

int main ()
{
    char input[255];
    int i = 0;
    int flag = 0;
   for(;;i++) /* Infinite loop, exited when RETURN is pressed */
   {
       char temp;
       temp = getch (); /* Get the current character of the password */
       if (GetAsyncKeyState (VK_RETURN)) /* If the user has pressed return */
       {
           input[i]='\0';
           break;
       }
       if ( i< 255)
       {
            input[i] = temp;
       }
       else     
       {
           flag = 1;
       }

       printf("*"); /* Print a star */
 }
//printf("%s",input);
if(strcmp(input,"kamal")==0 && flag == 0)
{
      printf("ACCEPTED");
 }
 else
       printf("not");
 getch();
 return EXIT_SUCCESS; /* Program was executed successfully */
}

另一种解决方案是动态分配输入数组的 (realloc()) 大小。

于 2013-02-25T13:04:09.690 回答
1

始终检查边界。始终根据缓冲区的长度检查 i 的值。

于 2013-02-25T12:46:09.027 回答
1

在某些情况下,扩展缓冲区是可以接受的。这很少是理想的,因为无限扩展会导致其他问题。

在其他情况下,截断输入是可以接受的。这可能是这里的一个选项,但它也不理想。

在这种情况下,当您与不变的字符串进行比较时,您可以跳过“将输入存储在数组中”阶段,并将接收到的输入逐字节与密码进行比较。这样的代码应该看起来像这样,但要小心,因为这是未经测试的:

char password[] = "kamal";
size_t position = 0;
char c = getch();
while (password[position] != '\0' || strchr("\r\n", (unsigned char) c) == NULL) {
    if (c != password[position++] || position == sizeof password) {
        // Password mismatch. Discard the rest of the password, then tell the user...
        while (strchr("\r\n", (unsigned char) c) == NULL) {
            c = getch();
        }
        position = 0;
        puts("Invalid password. Please retry.");
    }
    c = getch();
}

...如果没有缓冲区溢出,那你还担心什么?

于 2013-02-25T13:16:31.623 回答
0

尝试包装类似的东西:

if(i<255) {
    ...
}

...围绕您的角色收集过程。

- 编辑 -

#include <conio.h>
#include <windows.h>
#include <stdio.h>

int main ()
{
char input[255];
int i = 0;
for(;;i++) /* Infinite loop, exited when RETURN is pressed */
{
    if(i < 255) 
    {
        char temp;
        temp = getch (); /* Get the current character of the password */
        if (GetAsyncKeyState (VK_RETURN)) /* If the user has pressed return */
        {
            input[i]='\0';
            break;
        }
        input[i] = temp;
        printf("*"); /* Print a star */
    }
}
//printf("%s",input);
if(strcmp(input,"kamal")==0)
{
                     printf("ACCEPTED");
                     }
                     else
                     printf("not");
_getch();
return EXIT_SUCCESS; /* Program was executed successfully */
}
于 2013-02-25T12:46:20.113 回答
0

正如您所指出的,如果用户提供超过 255 个字符,您将程序崩溃。

所以,你应该检查已经提供的字符数量,如果它达到最大值(你的缓冲区),你应该停止获取更多的键(因为密码已经错了,这并不重要......):

#define BUFFER_MAX 255

// +1 so we can always add the 0-terminator
char input[BUFFER_MAX + 1];
do {
    char temp;
    temp = getch (); /* Get the current character of the password */
    // Check if char does fit in the buffer
    if(i < BUFFER_MAX) {
        // add to buffer
        input[i] = temp;
        i++;
    }
    printf("*"); /* Print a star */
    // Check if the user pressed return
} while(GetAsyncKeyState (VK_RETURN) == false);
input[i]='\0';

注意:我还重新安排了你的循环,因为使用无限循环并打破它们是“丑陋的”(不好的做法,在这种情况下是不必要的)......

于 2013-02-25T13:08:58.047 回答