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]解决了这个问题。

+2

当buf被溢出时,无限循环发生的原因是因为sprintf将buf [2]设置为'\ 0'。很可能在堆栈buf之后是z(小端)。因此,z的低字节被设置为0,因为高字节已经为0,所以每次将z设置为0。 – jstanley

你忘记了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的缓冲区,会导致问题。