我有一个缓冲区,我正在进行很多 strncat 操作。我想确保不会溢出缓冲区大小。
char buff[64];
strcpy(buff, "String 1");
strncat(buff, "String 2", sizeof(buff));
strncat(buff, "String 3", sizeof(buff));
我想用buff - xxx代替sizeof(buff),以确保我不会覆盖缓冲区。
我有一个缓冲区,我正在进行很多 strncat 操作。我想确保不会溢出缓冲区大小。
char buff[64];
strcpy(buff, "String 1");
strncat(buff, "String 2", sizeof(buff));
strncat(buff, "String 3", sizeof(buff));
我想用buff - xxx代替sizeof(buff),以确保我不会覆盖缓冲区。
需要考虑现有字符串的大小以及空终止符
#define BUFFER_SIZE 64
char buff[BUFFER_SIZE];
//Use strncpy
strncpy(buff, "String 1", BUFFER_SIZE - 1);
buff[BUFFER_SIZE - 1] = '\0';
strncat(buff, "String 2", BUFFER_SIZE - strlen(buff) - 1);
strncat(buff, "String 3", BUFFER_SIZE - strlen(buff) - 1);
snprintf
?与strncat
不同,它需要缓冲区的大小,但更重要的是,没有隐藏的O(n)。Strcat需要在每个连接的字符串上查找空终止符,并且每次运行时通过整个缓冲区查找末尾。随着字符串变得越来越长,strcat会变慢。另一方面,sprintf可以跟踪末尾,你会发现...snprintf(buf, sizeof buf, "%s%s%s", "String1", "String2", "String3");
经常是更快、更易读的解决方案。
snprintf
函数会返回写入的字符数,因此您可以存储缓冲区偏移量并使用 offset+=snprintf(buf+offset, (sizeof buf)-offset, "%s", "String2")
进行操作。 - Davestrncat
函数的方式实际上适用于另一个函数:strlcat
(注意是l
而不是n
)。strlcat
函数不是标准函数,但它是一个流行的实现提供的strncat
替代品。 strlcat
期望作为其最后一个参数提供整个目标缓冲区的总大小。strncat
期望作为其第三个参数提供目标缓冲区剩余未使用部分的大小。因此,您的原始代码是错误的。strncpy
进行恶劣的滥用,并使用那些strlen
调用进行显式重新扫描,而是使用实现提供的strlcat
或自己实现一个(如果您的实现没有提供strlcat
)。
http://en.wikipedia.org/wiki/Strlcpy
这是最好的方法。如果您没有在本地分配(在这种情况下,您已经在本地分配),sizeof()
只会给出指向数据的指针大小,但最好用这种方式处理,如果代码重构,它仍然可以工作。
#define MAXBUFFSIZE 64
char buff[MAXBUFFSIZE];
buff[0] = 0; // or some string
strncat(buff, "String x",MAXBUFFSIZE - strlen(buff) - 1);
sizeof
将给出整个缓冲区的大小,因为它是一个数组,而不是动态分配的内存块。 - yansizeof
应用于数组对象时,它会计算出整个数组对象的总大小。在OP的代码中没有任何形式的“指向数据”的指针。 - AnT stands with Russiastrcat(...)
中的缓冲区溢出,那么你同样应该担心所有其他字符串函数中的缓冲区溢出。strnlen(...)
和strncpy(...)
确保您真正留在缓冲区范围内。如果没有strnlen(...)
函数,请编写它。strnlen
和strncpy
都是用于处理定长字符串的函数,与空字符结尾的字符串无关。与此同时,根据问题描述,OP特别关注空字符结尾的字符串。确实,我们经常看到strncpy
被错误地用于空字符结尾的字符串。但是,strnlen
在这里的作用完全不清楚。 - AnT stands with Russiamemccpy
而不是strncat
——它更安全,速度也更快。 (它还比Dave提到的snprintf
方法更快mentioned):/**
* Returns the number of bytes copied (not including terminating '\0').
* Always terminates @buf with '\0'.
*/
int add_strings(char *buf, int len)
{
char *p = buf;
if (len <= 0)
return 0;
p[len - 1] = '\0'; /* always terminate */
p = memccpy(buf, "String 1", '\0', len - 1);
if (p == NULL)
return len - 1;
p = memccpy(p - 1, "String 2", '\0', len - 1 - (p - buf));
if (p == NULL)
return len - 1;
p = memccpy(p - 1, "String 3", '\0', len - 1 - (p - buf));
return (p == NULL ? len : p - buf) - 1;
}