阅读 scanf
手册时,我遇到了这一行:
一个可选的'm'字符。这与字符串转换 (
%s
,%c
,%[
) 一起使用,
有人可以用简单的例子解释一下它的区别和在某些情况下需要使用此选项的原因吗?
gcc -std=c99
或gcc -D_ISOC99_SOURCE
编译程序,则a
修饰符不可用(除非也指定了_GNU_SOURCE
),此时a
将被解释为浮点数的说明符(参见上文)。自2.7版本以来,glibc还提供了m
修饰符,用于相同的目的。 m
修饰符具有以下优点:
它也可以应用于%c
转换说明符(例如%3mc
)。
它避免了与%a
浮点转换说明符有关的歧义(并且不受gcc -std=c99
等的影响)
它在即将发布的POSIX.1标准修订版中进行了规定。
在线Linux手册页面 http://linux.die.net/man/3/scanf 仅记录了以下选项:
一个可选的 'm' 字符。这适用于字符串转换 (
%s
,%c
,%[
),并减轻了调用者分配相应缓冲区以容纳输入的需要:相反,scanf()
分配足够大小的缓冲区,并将该缓冲区的地址赋值给相应的指针参数,该参数应为指向char *
变量的指针 (在调用之前不需要初始化此变量)。调用者在不再需要时应使用free(3)
释放此缓冲区。
Posix标准在其POSIX.1-2008版本中记录了此扩展 (请参见http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html):
%c
、%s
和%[
转换说明符可以接受一个可选的赋值分配字符m
,它将导致分配一个内存缓冲区来保存转换后的字符串,包括一个终止空字符。在这种情况下,相应于转换说明符的参数应该是一个指向指针变量的引用,该变量将接收指向已分配缓冲区的指针。系统将分配一个缓冲区,就像调用了malloc()
一样。应用程序负责在使用后释放内存。如果没有足够的内存来分配缓冲区,则函数将设置errno
为 [ENOMEM
],并将导致转换错误。如果函数返回EOF
,则在函数返回之前,通过此调用使用赋值分配字符m
成功分配的任何内存都将被释放。
使用此扩展,您可以编写:
char *p;
scanf("%ms", &p);
scanf
从标准输入中解析一个单词并分配足够的内存以存储其字符及终止符'\0'
。指向分配数组的指针将被存储到p
中,除非无法从stdin
读取任何非空格字符,否则scanf()
将返回1
。m
来表示类似的语义或完全不同的内容。非标准扩展是不可移植的,应该非常小心地使用,并在标准方法笨重、不切实际或根本不可能的情况下进行记录。scanf()
确实无法解析任意大小的单词:'\0'
之前指定要存储的字符的最大数量:char buffer[20];
scanf("%19s", buffer);
char buffer[20];
scanf("%s", buffer); // potential undefined behavior,
// that could be exploited by an attacker.
char word[32]; scanf("%31s", word);/* 输入的最大字符数已知。 */
- BLUEPIXYchar *word; scanf("%ms", &word);/* 输入大小未知,根据输入动态分配内存空间。 */