如何为输入的输入分配内存(在'C'中)

时间:2012-08-10 18:49:25

标签: c pointers memory-management input

我正在为假想的机器(SMAC-0机器)编写汇编程序,需要一些内存分配方面的帮助。

我将从给定文件中获取并标记字符串,并将这些标记保存在指针中。

以下是代码段:

tokenCount = sscanf(buffer,"%s %s %s %s", tokenOne, tokenTwo, tokenThree, tokenFour);

其中tokenCount是整数,buffer是存储从输入文件中获取的行的临时缓冲区,tokenOnetokenTwotokenThreetokenFour是字符指针。

从文件中接受的字符串可以有一到四个单词:

  

实施例:   


            READ    N
    N:      DS      1
    SUM:    DS      1
    LOOP:   MOVER   AREG    N
            ADD     AREG    N
            COMP    AREG    ='5'
            BC      LE      LOOP
            MOVEM   AREG    SUM
            PRINT   SUM
            STOP

我的疑问是:

  • 如何找出令牌的大小,从而知道如何为各自的令牌指针分配内存?
  • (该问题也适用于buffer指针,因为标签(例如LOOPNSUM)可以是可变大小。)

  • 如何使用scanf()或其他输入函数(如gets())执行相同的操作?
  • 1 个答案:

    答案 0 :(得分:1)

    您应该声明您的令牌缓冲区足够大。为了安全起见,最好使它们与输入缓冲区本身一样大。有关详细信息,请参阅此主题How to prevent scanf causing a buffer overflow in C?

    如果您正在使用GNU编译器,则可以使用可以代表您动态分配缓冲区的扩展。查看Dynamic allocation with scanf()

    实施例

    为扫描的令牌使用预定义缓冲区:

    注意所有标记与输入缓冲区的大小相同:

    /* sscanf-test.c */
    #include <stdio.h>
    
    int main(int argc, char** argv)
    {
      FILE *file = fopen("sample.txt", "r");
      const int BufferSize=256;
      char buffer[BufferSize];
      char tokenOne[BufferSize];
      char tokenTwo[BufferSize];
      char tokenThree[BufferSize];
      char tokenFour[BufferSize];
    
      while (fgets(buffer, sizeof(buffer), file) != NULL)
      {
        tokenOne[0]='\0';
        tokenTwo[0]='\0';
        tokenThree[0]='\0';
        tokenFour[0]='\0';
        int tokenCount = sscanf(buffer, "%s %s %s %s", tokenOne, tokenTwo, tokenThree, tokenFour);
        printf("scanned %d tokens   1:%s 2:%s 3:%s 4:%s\n", tokenCount, tokenOne, tokenTwo, tokenThree, tokenFour);
      }
    
      fclose(file);
      return 0;
    }
    

    程序产生以下输出(我稍微清理了格式以提高可读性):

    gcc sscanf-test.c -o sscanf-test
    ./sscanf-test 
    scanned 2 tokens   1:READ   2:N    3:     4: 
    scanned 3 tokens   1:N:    2:DS    3:1    4: 
    scanned 3 tokens   1:SUM:  2:DS    3:1    4: 
    scanned 4 tokens   1:LOOP: 2:MOVER 3:AREG 4:N 
    scanned 3 tokens   1:ADD   2:AREG  3:N    4: 
    scanned 3 tokens   1:COMP  2:AREG  3:='5' 4: 
    scanned 3 tokens   1:BC    2:LE    3:LOOP 4: 
    scanned 3 tokens   1:MOVEM 2:AREG  3:SUM  4: 
    scanned 2 tokens   1:PRINT 2:SUM   3:     4: 
    scanned 1 tokens   1:STOP  2:      3:     4:
    

    如果要存储扫描的令牌以供以后处理,则必须将它们复制到while循环中的其他位置。您可以使用函数strlen来获取令牌的大小(不包括尾随字符串终结符'\ 0')。

    为令牌使用动态内存分配:

    就像我说的那样,你也可以让scanf动态地为你分配缓冲区。 scanf(3)手册页指出您可以使用GNU扩展“a”或“m”来执行此操作。具体来说它说:

      

    可选的'a'字符。这用于字符串转换,和   减轻调用者需要分配相应的缓冲区   保持输入:相反,scanf()分配足够的缓冲区   size,并将此缓冲区的地址分配给相应的   指针参数,它应该是指向char *变量的指针   (此变量不需要在调用之前初始化)。该   当调用者不再使用时,调用者应随后释放(3)此缓冲区   需要。这是一个GNU扩展; C99使用'a'字符作为   转换说明符(也可以在GNU中使用它)   实现)

    我无法使用'a'修饰符让scanf工作。然而,还有'm'修饰符可以做同样的事情(以及更多):

      

    从版本2.7开始,glibc也为它提供了m修饰符   作为修饰语的目的。 m修饰符具有以下内容   优点:

         
        
    • 它也可以应用于%c转换说明符(例如,%3mc)。

    •   
    • 它避免了%a浮点的模糊性   转换说明符(并且不受gcc -std = c99等影响)

    •   
    • 在即将发布的POSIX.1标准版本中指定。

    •   
    /* sscanf-alloc.c */
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv)
    {
      FILE *file = fopen("sample.txt", "r");
      const int BufferSize=64;
      char buffer[BufferSize];
      char *tokenOne   = NULL;
      char *tokenTwo   = NULL;
      char *tokenThree = NULL;
      char *tokenFour  = NULL;
    
      while (fgets(buffer, sizeof(buffer), file) != NULL)
      {
        // note: the '&', scanf requires pointers to pointer to allocate the buffers.
        int tokenCount = sscanf(buffer, "%ms %ms %ms %ms", &tokenOne, &tokenTwo, &tokenThree, &tokenFour);
        printf("scanned %d tokens   1:%s 2:%s 3:%s 4:%s\n", tokenCount, tokenOne, tokenTwo, tokenThree, tokenFour);
    
        // note: the memory has to be free'd to avoid leaks
        free(tokenOne);
        free(tokenTwo);
        free(tokenThree);
        free(tokenFour);
        tokenOne   = NULL;
        tokenTwo   = NULL;
        tokenThree = NULL;
        tokenFour  = NULL;
      }
    
      fclose(file);
      return 0;
    }
    
    gcc sscanf-alloc.c -o sscanf-alloc
    ./sscanf-alloc
    scanned 2 tokens   1:READ  2:N      3:(null) 4:(null)
    scanned 3 tokens   1:N:    2:DS     3:1      4:(null)
    scanned 3 tokens   1:SUM:  2:DS     3:1      4:(null)
    scanned 4 tokens   1:LOOP: 2:MOVER  3:AREG   4:N
    scanned 3 tokens   1:ADD   2:AREG   3:N      4:(null)
    scanned 3 tokens   1:COMP  2:AREG   3:='5'   4:(null)
    scanned 3 tokens   1:BC    2:LE     3:LOOP   4:(null)
    scanned 3 tokens   1:MOVEM 2:AREG   3:SUM    4:(null)
    scanned 2 tokens   1:PRINT 2:SUM    3:(null) 4:(null)
    scanned 1 tokens   1:STOP  2:(null) 3:(null) 4:(null)