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

C语言词法分析器运行输出随机字符问题求助

C语言词法分析器出现随机垃圾字符问题

问题背景

我正在用C语言编写一个词法分析器,预期功能如下:
输入:2 + 3
输出:

Token text (Operand): 2
Token text: +
Token lexical Category: ADD 
Token text (Operand): 3

对应的代码如下:

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

void token(char c);

int main(int argc, char *argv[]){
    
    if(argc == 1){
        printf("[*] Usage ./%s <TextToAnalyze>\n", argv[0]); //用户输入的参数将被分析
    } else{
        char arguments[argc];
        
        for(int i = 1; i < argc; i++){
            strcat(arguments, argv[i]);//参数将被复制并分隔到变量"arguments"
            strcat(arguments, " ");
        }
        
        for( int i = 0; i < strlen(arguments); ++i){
        token(arguments[i]); //遍历输入元素,用token函数分析
        }
    }
    
    return 0;
}

void token(char c){
    if(isdigit(c)){
        printf("Token text (OPERAND): %c\n", c);
        
    } else if(isalpha(c)){
        printf("Token text: %c\n", c);
        printf("Token lexical category: CHARACTER\n");
    } else if(isspace(c)){
asm ("nop");
    } else {
        
        switch(c){
            case '+':
                printf("Token text: %c\n", c);
                printf("Token lexical category: ADD\n");
                break;
            case '-':
                printf("Token text: %c\n", c);
                printf("Token lexical category: SUBTRACT\n");
                break;
            case '*':
                printf("Token text: %c\n", c);
                printf("Token lexical category: MULTIPLY\n");
                break;
            case '/':
                printf("Token text: %c\n", c);
                printf("Token lexical category: DIVIDE\n");
                break;
            case '%':
                printf("Token text: %c\n", c);
                printf("Token lexical category: MODULE\n");
                break;
            case '<':
                printf("Token text: %c\n", c);
                printf("Token lexical category: LESS THAN\n");
                break;
            case '>':
                printf("Token text: %c\n", c);
                printf("Token lexical category: GREATER THAN\n");
                break;
            case '=':
                printf("Token text: %c\n", c);
                printf("Token lexical category: EQUAL\n");
                break;
            default:
                printf("Operator not found: %c \n", c);
        }
    }
}

错误现象

运行程序输入- 2时,终端输出随机垃圾字符:

bash-3.2$ ./a.out - 2
Operator not found:  
Token text: Y
Token lexical category: CHARACTER
Operator not found: ? 
Operator not found: ? 
Operator not found: ? 
Operator not found:  
Token text: -
Token lexical category: SUBTRACT
Token text (OPERAND): 2
bash-3.2$ 

问题原因

  1. 未初始化数组引发垃圾数据读取:char arguments[argc];定义的数组未初始化,内存中残留随机垃圾值。而strcat要求目标字符串必须以'\0'结尾,否则会从内存随机位置读取直到找到'\0',导致垃圾字符被当作有效内容处理。
  2. 数组空间不足导致内存越界:argc是命令行参数的个数,并非所有参数的总字符长度。比如输入- 2时argc=3,数组大小仅为3,但实际需要存储"- 2\0"共4个字符,空间不足触发内存越界,引发未定义行为。

修复方案

方案1:静态数组(计算足够空间并初始化)

先计算所有参数的总长度,加上参数间空格的数量,再预留字符串结束符的空间,同时初始化数组为空字符串:

int main(int argc, char *argv[]){
    
    if(argc == 1){
        printf("[*] Usage ./%s <TextToAnalyze>\n", argv[0]);
    } else{
        // 计算总字符长度
        int total_len = 0;
        for(int i = 1; i < argc; i++){
            total_len += strlen(argv[i]);
        }
        // 添加参数间的空格(argc-1个参数对应argc-2个空格)
        total_len += (argc - 2);
        // 定义数组并预留结束符空间
        char arguments[total_len + 1];
        // 初始化为空字符串
        arguments[0] = '\0';
        
        for(int i = 1; i < argc; i++){
            strcat(arguments, argv[i]);
            // 最后一个参数后不加空格
            if(i != argc - 1){
                strcat(arguments, " ");
            }
        }
        
        for( int i = 0; i < strlen(arguments); ++i){
            token(arguments[i]);
        }
    }
    
    return 0;
}

方案2:动态内存分配(适合长参数场景)

如果担心栈空间不足,使用malloc动态分配内存,使用后记得释放:

int main(int argc, char *argv[]){
    
    if(argc == 1){
        printf("[*] Usage ./%s <TextToAnalyze>\n", argv[0]);
    } else{
        int total_len = 0;
        for(int i = 1; i < argc; i++){
            total_len += strlen(argv[i]);
        }
        total_len += (argc - 2);
        
        // 动态分配内存,检查分配是否成功
        char *arguments = malloc(total_len + 1);
        if(arguments == NULL){
            perror("malloc failed");
            return 1;
        }
        arguments[0] = '\0';
        
        for(int i = 1; i < argc; i++){
            strcat(arguments, argv[i]);
            if(i != argc - 1){
                strcat(arguments, " ");
            }
        }
        
        for( int i = 0; i < strlen(arguments); ++i){
            token(arguments[i]);
        }
        
        // 释放动态分配的内存
        free(arguments);
    }
    
    return 0;
}

另外,原代码中asm ("nop");可替换为return;或直接空块,提升代码可读性。


内容的提问来源于stack exchange,提问作者AndresTheGiant-

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:41:01