sprintf 的小问题

3161阅读 0评论2012-08-23 datao0907
分类:C/C++

最近需要将数组转换为字符串,就想到了库函数snprintf,sprintf,在使用sprintf的时候出现了一个奇怪的问题,程序如下:

  1. #include <stdio.h>
  2.     #include <string.h>

  3.     #define N 5

  4.     int main(int argc,char *argv[])
  5.     {
  6.        int i = 0;//i = 2;
  7.        int a[N] = {0,1,2,3,4};
  8.        char str[N];

  9.        //memset(str,'\0',N 1);
  10.     
  11.        for(; i < N; i)
  12.        {
  13.            sprintf(str i,"%d",a[i]);
  14.            printf("%d,%c,%d\n",a[i],str[i],i);
  15.         }
  16.     
  17.       puts(str);
  18.     
  19.       return 0;
  20.     }
snprintf会在末尾加上一个'\0',来标记字符串的结束,编译运行程序,得到的是一个死循环,通过gdb调试查看其汇编代码,发现一些异常.

  1.     gdb ./tas
  2.     
  3.     set disassembly-flavor intel
  4.     
  5.     disassemble main
在数据初始化部分的代码片断如下:

  1. 0x0804848e < 10>:    mov DWORD PTR [esp 0x2c],0x0
  2.      0x08048496 < 18>:    mov DWORD PTR [esp 0x10],0x0
  3.      0x0804849e < 26>:    mov DWORD PTR [esp 0x14],0x1
  4.      0x080484a6 < 34>:    mov DWORD PTR [esp 0x18],0x2
  5.      0x080484ae < 42>:    mov DWORD PTR [esp 0x1c],0x3
  6.      0x080484b6 < 50>:    mov DWORD PTR [esp 0x20],0x4
  7.      0x080484be < 58>:    jmp 0x8048522 <main 158>
  8.      0x080484c0 < 60>:    mov eax,DWORD PTR [esp 0x2c]
  9.      0x080484c4 < 64>:    mov ecx,DWORD PTR [esp eax*4 0x10]
  10.      0x080484c8 < 68>:    mov edx,0x8048610
  11.      0x080484cd < 73>:    mov ebx,DWORD PTR [esp 0x2c]
  12.      0x080484d1 < 77>:    lea eax,[esp 0x27]
  13.      0x080484d5 < 81>:    add eax,ebx
  14.      0x080484d7 < 83>:    mov DWORD PTR [esp 0x8],ecx
  15.      0x080484db < 87>:    mov DWORD PTR [esp 0x4],edx
  16.      0x080484df < 91>:    mov DWORD PTR [esp],eax
  17.      0x080484e2 < 94>:    call 0x8048364 <sprintf@plt>
从代码上基本可以发现在分配变量地址的问题

  1. a[0] --> esp + 0x10
  2.      a[1] --> esp + 0x14
  3.      a[2] --> esp + 0x18
  4.      a[3] --> esp + 0x1c
  5.      a[4] --> esp + 0x20
  6.      
  7.      str[0] --> esp + 0x27
  8.      .....
  9.      str[5] --> esp + 0x2b
  10.      
  11.      i ----> esp + 0x2c
在C语言书中提到字符串数组末尾都会默认添加一个'\0',这里似乎没看到,于是,通过gdb调试,打印地址,来验证假设:

  1. p &i
  2.      $1 = (int *) 0xbffff82c
  3.      
  4.      p &str[4]
  5.      $2 = 0xbffff82b "\b\001"
  6.      
  7.      p &str[5]
  8.      $3 = 0xbffff82c "\001"
地址和i一样,末尾可能真的没有加零,如果将上面的注释替换掉的话,通过执行memset后,i的值已经变成0了。后来发现只有未初始化的字符串末尾均未加'\0',这个之前都没有注意过。

上一篇:tcp/ip 分析(1)
下一篇:最大子数组连续和问题(数组为环)