我正在为假想的机器(SMAC-0机器)编写汇编程序,需要一些内存分配方面的帮助。
我将从给定文件中获取并标记字符串,并将这些标记保存在指针中。
以下是代码段:
tokenCount = sscanf(buffer,"%s %s %s %s", tokenOne, tokenTwo, tokenThree, tokenFour);
其中tokenCount
是整数,buffer
是存储从输入文件中获取的行的临时缓冲区,tokenOne
,tokenTwo
,tokenThree
,tokenFour
是字符指针。
从文件中接受的字符串可以有一到四个单词:
实施例:
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
指针,因为标签(例如LOOP
,N
,SUM
)可以是可变大小。)
scanf()
或其他输入函数(如gets()
)执行相同的操作?
答案 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)