You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言函数输入处理引发栈溢出(stack smashing)问题求助

问题排查:输入长字符串后触发栈溢出错误

我编写了一段处理命令输入的C语言代码,测试异常处理逻辑时发现:当先输入单个无效字符(如"p")再输入有效字符"b",程序能正常输出the capital is: B;但先输入长度大于1的字符串(如"awd"),再输入有效字符"b"时,程序会触发**栈溢出(stack smashing)**错误,无法定位问题原因,请求帮忙排查解决。

原代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

char main_choice();

int main() 
{
  //case_b();
  // check_if_num1();
  char mainchoice [300];

  printf("the capital is: %c\n", main_choice(mainchoice));
  return 0;
}


char main_choice()
{
  int flag1=0;
  int flag2=0;
  char choice;
  printf("Select one of the following commands: \n");
  printf("B) - Binary Mathematical Operations, such as addition and subtraction.\n");
  printf("U) - Unary Mathematical operations, such as square root, and log.\n");
  printf("A) - Advances Mathematical Operations, using variables, arrays.\n");
  printf("V) - Define variables and assign them values.\n");
  printf("E) - Exit\n");
  scanf(" %[^\n]%*c",&choice); 

  
while (1)
  {
    if (strlen(&choice) == 1)
    {
      do
        {
          if (choice == 'b')
          {
            choice = 'B';
            return choice;
            flag1 = 1;
            //flag2 = 1;
            break;
          }
          else if (choice == 'u')
          {
            choice = 'U';
            return choice;
            flag1 = 1;
            //flag2 = 1;
            break;
          }
          else if (choice == 'a')
          {
            choice = 'A';
            return choice;
            flag1 = 1;
            //flag2 = 1;
            break;
          }
          else if (choice == 'v')
          {
            choice = 'V';
            return choice;
            flag1 = 1;
            //flag2 = 1;
            break;
          }
          else if (choice == 'e')
          {
            choice = 'E';
            return choice;
            flag1 = 1;
            //flag2 = 1;
            break;
          }
            
            // if (strlen(&choice) == 1 && choice != 'b' && choice != 'u' && choice != 'a' && choice != 'v' && choice != 'e')
          else
            {
              //flag2 =0;
              printf("Invalid entry\n");
              printf("----------------------------------------------------------\n\n");
              printf("Select one of the following commands: \n");
              printf("B) - Binary Mathematical Operations, such as addition and subtraction.\n");
              printf("U) - Unary Mathematical operations, such as square root, and log.\n");
              printf("A) - Advances Mathematical Operations, using variables, arrays.\n");
              printf("V) - Define variables and assign them values.\n");
              printf("E) - Exit\n");
              scanf(" %[^\n]%*c",&choice);
            }
        }while(flag1);
      //break;
    }
    else
    {
      printf("Invalid entry\n");
      printf("----------------------------------------------------------\n\n");
      printf("Select one of the following commands: \n");
      printf("B) - Binary Mathematical Operations, such as addition and subtraction.\n");
      printf("U) - Unary Mathematical operations, such as square root, and log.\n");
      printf("A) - Advances Mathematical Operations, using variables, arrays.\n");
      printf("V) - Define variables and assign them values.\n");
      printf("E) - Exit\n");
      scanf(" %[^\n]%*c",&choice); 
      
    }
    //break;
  }
  //return choice;
}

核心问题原因

  1. 缓冲区溢出直接破坏栈结构:
    • main_choice函数中定义的char choice是单个字符变量,但使用scanf(" %[^\n]%*c", &choice)读取输入。%[^\n]会读取所有非换行符的字符,当输入长度大于1的字符串时,超出单个字符的内容会直接写入choice内存地址之外的栈空间,破坏栈帧数据,触发栈溢出。
    • strlen(&choice)用法错误:strlen要求传入以\0结尾的字符串首地址,但choice是单个字符,没有终止符,函数会越界读取内存直到找到\0,结果不可预测,进一步加剧内存访问异常。
  2. 函数声明与定义不匹配:
    • 声明的char main_choice()无参数,但main中调用时传入了mainchoice,函数定义却未接收参数,属于未定义行为,干扰栈的正常布局。

修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

// 修正函数声明,明确接收缓冲区参数
char main_choice(char *input_buf);

int main() 
{
    char mainchoice[300];
    printf("the capital is: %c\n", main_choice(mainchoice));
    return 0;
}

// 使用缓冲区存储输入,避免单个字符溢出问题
char main_choice(char *input_buf)
{
    while (1)
    {
        // 打印命令提示
        printf("Select one of the following commands: \n");
        printf("B) - Binary Mathematical Operations, such as addition and subtraction.\n");
        printf("U) - Unary Mathematical operations, such as square root, and log.\n");
        printf("A) - Advances Mathematical Operations, using variables, arrays.\n");
        printf("V) - Define variables and assign them values.\n");
        printf("E) - Exit\n");
        
        // 限制读取长度为299,避免缓冲区溢出;%*c吃掉换行符
        if (scanf(" %299[^\n]%*c", input_buf) != 1) {
            // 处理输入错误,清空输入缓冲区
            while (getchar() != '\n');
            printf("Invalid entry\n");
            printf("----------------------------------------------------------\n\n");
            continue;
        }

        // 检查输入长度是否为1
        if (strlen(input_buf) != 1) {
            printf("Invalid entry\n");
            printf("----------------------------------------------------------\n\n");
            continue;
        }

        // 统一转为大写,简化判断逻辑
        char choice = toupper(input_buf[0]);
        if (choice == 'B' || choice == 'U' || choice == 'A' || choice == 'V' || choice == 'E') {
            return choice;
        } else {
            printf("Invalid entry\n");
            printf("----------------------------------------------------------\n\n");
        }
    }
}

关键修复点

  • 使用缓冲区存储输入:利用main中定义的mainchoice[300]作为输入缓冲区,scanf通过%299[^\n]限制读取长度,彻底避免溢出。
  • 修正内存访问逻辑:传入合法的以\0结尾的字符串给strlen,确保长度判断准确。
  • 简化命令判断:用toupper统一转换输入大小写,减少冗余代码。
  • 修复函数匹配问题:让函数接收缓冲区参数,消除未定义行为。
  • 增加错误处理:当scanf失败时清空输入缓冲区,避免死循环。

内容的提问来源于stack exchange,提问作者Ghostrocket 017

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:40:24