【问题标题】:Read the first three strings of a line into individual arrays, then read the rest of the line into a fourth string in C?将一行的前三个字符串读入单独的数组,然后将该行的其余部分读入 C 中的第四个字符串?
【发布时间】:2018-03-23 23:00:27
【问题描述】:

我正在用 C 编写一个汇编程序的第一遍以进行赋值,并且需要读取带有汇编代码的文本文件的行,并存储标签、操作码和操作数,以及行中的任何 cmets在前三个字符串之后。我最初使用过

fscanf(fileptr1,"%s\t%s\t%s",label,opcode,operand);

对于没有 cmets 的文件,但 sscanf 无法将行的其余部分放入单个 char 数组中。好像我会使用fgets,但是我如何将它分成前三个用空格分隔的字符串,然后是行的其余部分,直到换行符?

作为参考,这些行遵循以下格式:

LABEL   OPCODE  OPERAND     COMMENTS IN MULTIPLE STRINGS

我希望将标签、操作码和操作数放在单独的字符串中,就像我现在所做的那样,然后在整个行的其余部分使用单独的字符串。汇编代码中的几行供参考:

COPY    START   1000        COPY FILE FROM INPUT TO OUTPUT
FIRST   STL     RETADR      SAVE RETURN ADDRESS
CLOOP   JSUB    RDREC       READ INPUT RECORD
        LDA     LENGTH      TEST FOR EOF (LENGTH = 0)
        COMP    ZERO
        JEQ     ENDFIL      EXIT IF EOF FOUND
        JSUB    WRREC       WRITE OUTPUT RECORD
J       CLOOP   LOOP

【问题讨论】:

    标签: c assembly scanf fgets


    【解决方案1】:

    第 1 步:读取带有fgets() 的行

    char buffer[256];
    while (fgets(buffer, sizeof buffer,fileptr1) {
    

    我如何将它分成由空格分隔的前三个字符串,...

    这是对问题的错误评估。在" LDA LENGTH TEST FOR EOF (LENGTH = 0)" 为第一个“字符串”或label 为空的情况下,这3 个“字符串”不使用空格分隔。

    代码需要寻找缺失的字段。

    第 2 步:有多种方法:下面是 try-it-1-of-2-方法,具体取决于前导字符是否为空格。通过测试n来测试扫描是否成功

        char label[8];
        char opcode[8];
        char operand[12];
        char comment[sizeof buffer];  // big enough to handle the rest of the line
        label[0] = '\0';
        opcode[0] = '\0';
        operand[0] = '\0';
        comment[0] = '\0';
    
        int n = 0;  
        if (isspace((unsigned char) buffer[0])) {
          //                      vv--------- Save offset of scan if we got that far
          sscanf(buffer, "%7s%11s %n" , opcode, operand, &n); 
        } else {
          sscanf(buffer, "%7s%7s%11s %n" , label, opcode, operand, &n); 
        }
        if (n == 0) {
          // Handle bad input with TBD code
          continue;
        }
        // look for comment starting at `n`
        if (buffer[n]) {
          // scan in comment  
          sscanf(buffer + n, "%[^\n]" , comment); 
        }
    
        // do something with input
        printf("<%s> <%s> <%s> <%s>\n", label,opcode,operand,comment);
    }
    

    代码可能会测试“太长”的label,opcode,operand。示例:

        // Assume max length of opcode == 7
        char opcode[7 + 1 + 1];  // +1 for extra, +1 for null character
        ...
        sscanf(..., "...%8s...", .... opcode ...);
        if (opcode[7 + 1]) Handle_TooLoong();
    

    【讨论】:

    • 感谢对空白的更正/澄清和关注。只需要在while() 条件下修复fgets() 以使用buffer 而不是fileptr1 就可以了!谢谢!
    • @TivonMohammed 代码已修改。
    【解决方案2】:

    为每个字段定义特定的分隔符

    fscanf( fileptr1, "%[^\t] %[^\t] %[^\t] %[^\n]", label, opcode, operand, comment ) ;
    

    您也许应该添加字段宽度说明符并检查返回值,以检查错误和超限,但这是一个不同的问题。

    但还有其他方法。例如,您可以将整行fgets() 分成一个数组,然后使用strtok() 将其拆分,并使用\t 作为分隔符。

    char line[1024] = {0} ;
    
    fgets( line, sizeof(line), fileptr1 ) ;
    
    char* label = strtok( line, "\t" ) ;
    char* opcode = label != 0 ? strtok( 0, "\t" ) : 0 ;
    char* operand = opcode != 0 ? strtok( 0, "\t" ) : 0 ;
    char* comment = operand != 0 ? strtok( 0, "\n" ) : 0 ;
    

    【讨论】:

    • 对于最后一个strtok(),我是否要使用\n 作为分隔符,因为我希望将行的其余部分存储在注释中?
    • 另外,我在将此解决方案集成到我的代码中时遇到了一些问题。删除声明,因为我之前已经将字符串声明为数组,导致char*char[] 之间的类型不匹配问题。不知道为什么会这样,因为我认为在这种情况下数组被视为指针。在保留这些声明的情况下尝试了几种不同的组合,也会在代码的其他部分引起类似的问题。我对 C 很陌生,作为一名学生,我的大部分知识都来自 C++,所以也许我误解了什么?
    • @TivonMohammed :除非注释包含制表符,否则最后一个 strtok 上的分隔符几乎没有区别。 fgets 在任何情况下都会删除换行符; strtok 将在 nul 终止。
    • @TivonMohammed :在替代解决方案中,数据类型确实需要更改。这就是我在片段中包含声明的原因。在 C++ 中没有什么不同;只是在 C++ 中,库允许其他(更好的)选项。但这与库有关,而不是语言本身。
    猜你喜欢
    • 2021-12-22
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    相关资源
    最近更新 更多