【问题标题】:Function not reading from stdin properly函数未正确从标准输入读取
【发布时间】:2016-12-13 06:29:35
【问题描述】:

所以我一直在尝试编写一个从标准输入读取数据的虚拟计算机程序。标准输入不断以(%d %s %d)的形式出现,数据基本上代表了一个有特定任务的程序,看起来像这样:

01 READ 60
02 LOAD 60
03 SUB 61
04 STOR 60
05 BRNG 15
06 READ 70
07 LOAD 70
08 ADD 80
09 STOR 80
10 LOAD 60
11 SUB 61
12 STOR 60
13 BRNG 15
14 BRAN 6
15 WRIT 80
16 HALT 99
61 SET 1
80 SET 0

有一个函数作为编译器工作,应该逐行读取这些数据,但出于某种原因,每当此函数运行时,我都会得到 “不正确格式的程序现在将退出”。一段时间以来,我一直在试图弄清楚为什么它会这样做,但没有任何线索。

程序逐行读取stdin流,当没有更多stdin时它应该停止并检查格式是否正确,并且确实是正确的格式,为什么它不能正确读取?我个人的猜测是由于某种原因它没有逐行阅读,但我不确定是不是这样!

PS:我第一次制作这个程序时使用的是文件指针,它工作得很好,但是当我将流切换到标准输入时,它开始给出不正确的格式错误!

int compile ( int memory [], int* instructionCounter , int* instructionRegister ,int*operationCode ,int* operand){
    char s[80]; /* The buffer */
    *instructionRegister=0;
    *operationCode=0;
    while(((*instructionRegister)=scanf("%d %s %d", operationCode,s,operand)) != NULL){ /*Reads data line by line then stores the integer returned by fscanf to instructionRegister pointer so that I can check for formating */
       if((*instructionRegister) ==3 ){ /*Checks for improper format by comparing the current instructionRegister count to 3, returns improper format otherwise */
            if(*operand >9999|| *operand <0){  /* Checks for word overflow in compiler, makes sure that digits do not exceed 9999 */
                printf("attempts to place a word in memory that is larger than 4 digits, or attempted to pass in a negative value\n ");
                exit(0);
            }
            /*Compares the string section of the code and checks if it matches the following words and then it converts it to it's 4 digit value by adding into it the operand */
            if(strcmp(s,"READ") == 0) {
                memory[*operationCode] = 10 * 100 + *operand;
            }
            else if(strcmp(s,"WRIT") == 0) {
                memory [*operationCode] = 11 * 100 + *operand;
            }
            else if(strcmp(s,"LOAD") ==0){
                memory [*operationCode] = 20 * 100 + *operand;
            }
            else if(strcmp(s,"PRNT") ==0){
                memory [*operationCode] = 12 * 100 + *operand;
            }
            else if(strcmp(s,"STOR") ==0){
                memory [*operationCode] = 21 * 100 + *operand;
            }
            else if(strcmp(s,"SET") ==0){
                memory [*operationCode] = *operand;
            }
            else if(strcmp(s,"ADD") ==0){
                memory [*operationCode] = 30 * 100 + *operand;
            }
            else if(strcmp(s,"SUB") ==0){
                memory [*operationCode] = 31 * 100 + *operand;
            }
            else if(strcmp(s,"DIV") ==0){
                memory [*operationCode] = 32 * 100 + *operand;
            }
            else if(strcmp(s,"MULT") ==0){
                memory [*operationCode] = 33 * 100 + *operand;
            }
            else if(strcmp(s,"MOD") ==0){
                memory [*operationCode] = 34 * 100 + *operand;
            }
            else if(strcmp(s,"BRAN") ==0){
                memory [*operationCode] = 40 * 100 + *operand;
            }
            else if(strcmp(s,"BRNG") ==0){
                memory [*operationCode] = 41 * 100 + *operand;
            }
            else if(strcmp(s,"BRZR") ==0){
                memory [*operationCode] = 42 * 100 + *operand;;
            }
            else if(strcmp(s,"HALT")==0){
                memory [*operationCode] =9999;
            }

            else {   /* Prints back to the user that the compiler did not recognize one of them commands as it was going through it */
                printf ("This is an unknown command, commands are case sensitive, program will now exit \n");
                exit(0);

            }
        }
        else{    /* Returns improper format if instructionRegister does not match 3*/
            printf("Improper Format, program will now exit \n");
            exit(0);
        }

    }
    /* Checks if the instruction data contains a HALT, if not it would terminate */
    while(*instructionCounter<100){
        if (memory[*instructionCounter] == 9999){
            return 1;
        }
        else
            (*instructionCounter)++;
    }
    printf("Halt was not found, program will now exit");
    exit (0);
}

此函数的预期目的是逐行读取数据并将其存储在内存虚拟单元中。它应该检查这些行的格式是否为%d %c %d,以便它可以提取数据并将其相应地存储在内存中。

【问题讨论】:

  • 请发布Minimal, Complete, and Verifiable example 并附上一些输入数据和所需行为的示例。
  • 您可能想阅读a scanf (and family) reference。这些函数不返回指针,因此您不应将返回的值与NULL 进行比较。
  • 我已将 NULL 切换为 feof(stdin) 但它仍然给我一个错误!
  • 我将编辑帖子以显示输入数据的示例
  • 很明显,如果您的代码打印“格式不正确”,scanf 的返回值不是 3。如果我站在你的立场上,我会很好奇它是什么。

标签: c function computer-science stdin


【解决方案1】:

你的问题是这一行:

while(((*instructionRegister)=scanf("%d %s %d", operationCode,s,operand)) != NULL){

scanf() 函数返回

  • 成功转换的次数,介于 0 和 3 之间,或
  • EOF 以防在任何成功转换之前发生输入失败(文件结束或读取错误)。 EOF 宏是一些负数,通常是 -1

您将返回值与NULL 进行比较,即0(或(void *)0 或类似)。使用您提供的输入,while 循环将继续读取,直到scanf() 返回EOF。这不会跳出while 循环,但下一次测试会失败:

    if((*instructionRegister) ==3 ){ 
        /* big snip */
    else{
        printf("Improper Format, program will now exit \n");
        exit(0);
    }

当然,解决方案是将结果与EOF 进行比较,而不是NULL


在您的scanf() 调用中也存在潜在的缓冲区溢出。如果字符串长度超过 79 个字符,%s 转换说明符将导致 scanf() 写入超出 s[] 缓冲区的末尾。 (别忘了它会写一个终止\0。)

您可以通过添加最大字段宽度来限制数量:

scanf ("%d %79s %d", /*...*/)

如果输入字符串长度超过 79 个字符,则输入将无法匹配 "%d" 修饰符之前的空格,scanf() 将返回 2 以指示不完整的结果。

【讨论】:

  • 非常感谢您的回答,但我仍然会溢出!浮点数和字溢出,我认为 Scanf 没有正确扫描。在我对程序进行修改之前,我使用 fscanf 从文件中进行扫描,程序运行良好,但是当我切换到 STDIN 时,它就不再工作了。
  • @Mohammed:您发布的代码中的任何地方都没有浮点。也许您应该发布一个新问题,其中包含与这些问题相关的代码。
  • 我可以发布整个程序,但它很长。基本上我有两个检查错误的函数: int checkSegmentationFault(int *operand) { if(*operand 100){ printf("SEGMENTATION FAULT: Attempted to access an unknown address \n");退出(0); } 返回 0; }
  • int checkWordFlow(int instructionCounter, int memory []) { instructionCounter=0; while(instructionCounter9999) { printf("Word Overflow at memory element %d\n program will exit\n", instructionCounter);退出(0); } 指令计数器++; } 返回 1; }
  • 当我运行程序时出现此错误:内存元素 70 处的字溢出
猜你喜欢
  • 1970-01-01
  • 2019-07-26
  • 2013-03-30
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
相关资源
最近更新 更多