我有snprintf
,它可以避免缓冲区溢出,但是为什么没有名为snscanf
的函数
代码:
int main()
{
char * src = "helloeveryone";
char buf1[5];
sscanf(src,"%s",buf1); // here is a array out of bounds
}
因此,我认为snscanf
也是必要的。为什么我们只有snprintf
发布于 2013-08-21 22:49:07
C11中有争议的(和可选的)附件K添加了一个sscanf_s
函数,该函数在指针参数之后增加一个rsize_t
类型的参数(也在附件K中定义),指定指向数组的大小。无论是好是坏,这些功能没有得到广泛的支持。通过将大小放入转换说明符中,您可以获得相同的结果。
char out[20];
sscanf(in, "%19s", out);
但是,如果目标对象的大小在运行时可能发生变化(您必须使用snprintf
以编程方式构造转换说明符),这是很尴尬和容易出错的。请注意,转换说明符中的字段宽度是要读取的输入字符的最大数量,sscanf
还为%s
转换写入一个终止空字节,因此您传递的字段宽度必须严格小于目标对象的大小。
发布于 2013-08-21 22:43:30
在sscanf(s, format, ...)
中,扫描的字符数组是const char *
。没有写信给s
。当s[i]
为NUL时,扫描停止。几乎不需要n
参数作为扫描的辅助限制。
在sprintf(s, format, ...)
中,数组s
是目标。snprintf(s, n, format, ...)
确保数据不会对s[n]
和其他方面产生影响。
有用的是sscanf()
转换说明符的标志扩展,这样在编译时就可以很容易地指定限制。(现在可以以一种繁琐的方式完成,下面是动态格式或sscanf(src,"%4s",buf1)
。)
// This is a proposed idea for C. - Not valid code today.
sscanf(src, "%!s", sizeof(buf1), buf)
在这里,!
将告诉sscanf()
读取一个size_t
变量,以限制即将出现的字符串的大小。也许在C17?
今天起作用的累赘方法。
char * src = "helloeveryone";
char buf1[5];
char format[1+20+1+1];
sprintf(format, "%%" "%zu" "s", sizeof(buf1) - 1);
sscanf(src, format, buf1);
发布于 2013-08-22 03:58:54
为什么不试试fgets()
(使用标准输入文件stdin
)?
fgets()
允许您指定缓冲区的最大大小。
(在以下内容中,我将使用标准的ISO C99兼容语法。)
因此,您可以编写以下代码:
#include <stdio.h>
#define MAXBUFF 20 /* Small just for testing... */
int main(void) {
char buffer[MAXBUFF+1]; /* Add 1 byte since fgets() inserts '\0' at end */
fgets(buffer, MAXBUFF+1, stdin);
printf("Your input was: %s\n", buffer);
return 0;
}
fgets()
最多从stdin
读取MAXBUFF字符,
它是标准输入(即:键盘)。
结果保存在数组buffer
中。
如果找到'\n‘字符,则读取停止,'\n’也保存在buffer
中(作为最后一个字符)。此外,总是在buffer
末尾添加一个'\0‘,因此需要足够的存储空间。
您可以使用fgets()
和sscanf()
的组合来处理字符串:
char buffer[MAXBUFF+1];
fgets(buffer, MAXBUFF+1, stdin); /* Plain read */
int x; float f;
sscanf(buffer, "%d %g", &x, &f); /* Specialized read */
因此,您有一个“安全”的scanf()
-like方法。
注:这种方法有一个很大的问题。如果fgets()
在获得行尾字符'\n‘之前到达MAXBUFF字符,则其馀的输入将不会被丢弃,并将作为下一个键盘读取的一部分。
因此,必须添加一个刷新机制,这实际上非常简单:
while(getchar()!'\n')
; /* Flushing stdin... */
但是:如果您只是在fgets()
行之后添加最后一段代码,
用户将被迫在每次输入少于MAXBUFF字符的时候按两次输入。最糟糕的是:这是最典型的情况!
要解决这个新问题,请注意一个简单的逻辑条件完全等价于字符'\n‘未到达这一事实,如下所示:
(buffer[MAXBUFF - 1] != '\0') && (buffer[MAXBUFF - 1] != '\n')
(证明!)
因此,我们写道:
fgets(buffer, maxb+1, stdin);
if ((buffer[MAXBUFF - 1] != '\0') && (buffer[MAXBUFF - 1] != '\n'))
while(getchar() != '\n')
;
最后一次触摸是必要的:因为数组缓冲区可以有the,
似乎需要某种初始化。
但是,我们要注意的是,只有[MAXBUFF - 1]
位置需要清理:
char buffer[MAXBUFF + 1] = { [MAXBUFF - 1] = '\0' }; /* ISO C99 syntax */
最后,我们可以在一个快速的宏中收集所有的事实,就像这个程序所显示的:
#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
fgets(buffer, maxb+1, stdin); \
if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
while(getchar() != '\n') \
; \
sscanf(buffer, fmt, __VA_ARGS__); \
}
#define MAXBUFF 20
int main(void) {
int x; float f;
safe_scanf("%d %g", MAXBUFF+1, &x, &f);
printf("Your input was: x == %d\t\t f == %g", x, f);
return 0;
}
在宏中使用了变量数的机制,
根据 C99规范:变元宏
__VA_ARGS__
替换参数的变量列表。
(我们需要可变数量的参数来模拟scanf()
-like行为。)
注释:宏体被封装在一个带有{ }的块中.这并不完全令人满意,而且很容易改进,但它是另一个主题的一部分.
特别是,宏safe_scanf()
不“返回”一个值(它不是表达式,而是块语句)。
备注:宏中的声明了一个数组buffer
,该数组在输入该块时创建,然后在该块退出时被销毁。buffer
的范围仅限于宏的块。
https://stackoverflow.com/questions/18368712
复制相似问题