我是一名新手程序员,但通常我可以解开自己的问题。这次我解决了这个问题,但它仍然让我感到困惑。一位朋友建议我向这个社区征求意见。
我正在尝试用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]解决了这个问题。
答案 0 :(得分:12)
您忘记了NUL终止符。在C中,strings需要为终结符添加额外字符,因此char buf[2]
应该char buf[3]
才能容纳10到99之间的数字。
顺便提一下,您的代码演示了为什么sprintf
是危险的,因为它可以写入输出缓冲区并启用stack smashing attacks。更好的选择是使用snprintf
。
答案 1 :(得分:3)
C字符串以空值终止。如果您有2个字符(例如“10”),则需要一个大小为2 + 1的空终止符缓冲区。
sprintf()
将此添加到缓冲区的末尾;在你目前的情况下,你实际上有一个缓冲区溢出,因为你没有提供足够的空间。
现代,更安全的方法是使用snprintf()
来提供缓冲区的长度。
答案 2 :(得分:2)
我假设sprintf
在生成的字符串末尾添加\0
。因此,例如,如果您打印数字99
,您将在缓冲区中获得"99\0"
,因此对于长度为2的缓冲区,会导致问题。