您应该声明您的令牌缓冲区足够大。为了安全起见,最好使它们都与输入缓冲区本身一样大。有关详细信息,请参阅此线程 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-测试
扫描 2 个令牌 1:READ 2:N 3:4:
扫描 3 个令牌 1:N: 2:DS 3:1 4:
扫描 3 个令牌 1:SUM: 2:DS 3:1 4:
扫描 4 个令牌 1:LOOP:2:MOVER 3:AREG 4:N
扫描 3 个令牌 1:ADD 2:AREG 3:N 4:
扫描 3 个令牌 1:COMP 2:AREG 3:='5' 4:
扫描 3 个令牌 1:BC 2:LE 3:LOOP 4:
扫描 3 个令牌 1:MOVEM 2:AREG 3:SUM 4:
扫描 2 个令牌 1:PRINT 2:SUM 3:4:
扫描 1 个令牌 1:STOP 2:3:4:
如果您想存储扫描的令牌以供以后处理,则必须将它们复制到 while 循环中的其他位置。您可以使用函数strlen 来获取令牌的大小(不包括尾随字符串终止符'\0')。
对令牌使用动态内存分配:
就像我说的,您也可以让 scanf 为您动态分配缓冲区。 scanf(3) 手册页声明您可以使用 GNU 扩展 'a' 或 'm' 来做到这一点。具体来说:
可选的“a”字符。这与字符串转换一起使用,并且
减轻调用者分配相应缓冲区的需要
保留输入:相反,scanf() 分配了一个足够的缓冲区
大小,并将此缓冲区的地址分配给相应的
指针参数,它应该是一个指向 char * 变量的指针
(这个变量不需要在调用前初始化)。这
调用者随后应该释放(3)这个缓冲区,当它不再是
必需的。这是一个 GNU 扩展; C99 使用 'a' 字符作为
一个转换说明符(它也可以在 GNU
实施)
我无法使用“a”修饰符让 scanf 工作。但是,还有 'm' 修饰符可以做同样的事情(甚至更多):
从 2.7 版本开始,glibc 也提供了 m 修饰符
作为修饰语的目的。 m 修饰符具有以下内容
优点:
/* 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-分配
扫描 2 个令牌 1:READ 2:N 3:(null) 4:(null)
扫描 3 个令牌 1:N: 2:DS 3:1 4:(null)
扫描 3 个令牌 1:SUM: 2:DS 3:1 4:(null)
扫描 4 个令牌 1:LOOP:2:MOVER 3:AREG 4:N
扫描 3 个令牌 1:ADD 2:AREG 3:N 4:(null)
扫描了 3 个令牌 1:COMP 2:AREG 3:='5' 4:(null)
扫描 3 个令牌 1:BC 2:LE 3:LOOP 4:(null)
扫描 3 个令牌 1:MOVEM 2:AREG 3:SUM 4:(null)
扫描 2 个令牌 1:PRINT 2:SUM 3:(null) 4:(null)
扫描 1 个令牌 1:STOP 2:(null) 3:(null) 4:(null)