sprintf缓冲区大小
问题描述:
我是一个新手程序员,但通常我可以解开我自己的问题。这一次我解决了这个问题,但它仍然困扰着我。一位朋友建议我向这个社区征求意见。sprintf缓冲区大小
我试图在C中打印数字。我有一个函数使用sprintf来执行此操作。数字不能超过2位,所以我使用2个字符的缓冲区。不知何故,这是我的逻辑失败的地方,因为这会通过修改传递给sprintf的变量之一导致无限循环,但增加缓冲区大小可解决问题。
这里的失败代码:
#include <stdio.h>
void printarray(int array[][4]) {
int y;
int z;
char buf[2];
for (y=0; y<4; y++) {
for (z=0; z<4; z++) {
sprintf(buf, "%d", array[y][z]);
printf("buf is %s, y is %d and z is %d\n",buf,y,z);
}
}
}
int main() {
int arr[4][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0} };
printarray(arr);
return 0;
}
尽快为y到达2,它被重置为0,这样无限循环。改变buf [2]到buf [8]解决了这个问题。
答
你忘记了NUL终结者。在C,strings需要终止一个额外的角色,所以char buf[2]
应该是char buf[3]
至10和99
顺便之间容纳号,你的代码说明了为什么sprintf
是危险的,因为它可以写过去的输出缓冲区,并启用stack smashing attacks。更好的选择是使用snprintf
。
答
C字符串以null结尾。如果你有2个字符(例如“10”),你需要一个2 + 1的空终止符的缓冲区。
sprintf()
将此添加到缓冲区的末尾;在你目前的情况下,你实际上有一个缓冲区溢出,因为你没有提供足够的空间。
现代的,更安全的方法是使用您提供缓冲区长度的snprintf()
。
答
我假设sprintf
在生成的字符串的末尾添加了一个\0
。因此,例如,如果您打印号码99
,则会在缓冲区中获得"99\0"
,因此对于长度为2的缓冲区,会导致问题。
当buf被溢出时,无限循环发生的原因是因为sprintf将buf [2]设置为'\ 0'。很可能在堆栈buf之后是z(小端)。因此,z的低字节被设置为0,因为高字节已经为0,所以每次将z设置为0。 – jstanley