sscanf函数更改另一个字符串的内容

时间:2013-05-16 16:50:15

标签: c string pointers buffer-overflow scanf

我在使用sscanf阅读字符串时遇到问题。我已经愚弄了代码以专注于这个问题。下面是整个代码中的一个函数,它应该打开一个文件并读取一些东西。但是sscanf表现得很奇怪。例如,我声明了一个名为atm的字符串,其内容为'ATOM'。在sscanf之前,它将此字符串打印为ATOM,而在它为空之后。可能是什么问题呢?我认为它一定是分配问题,但我找不到它。我尝试了其他主题的一些建议,例如将%s替换为其他内容,但它没有帮助。

 void Get (struct protein p, int mode, int type) 
 {
   FILE *fd; //input file
   char name[100]="1CMA"; //array for input file name
   char string[600]; //the array where each line of the data file is stored when reading
   char atm[100]="ATOM";
   char begin[4];
   int index1 =0;

   fd = fopen(name, "r"); // open the input file

   if(fd==NULL) {
     printf("Error: can't open file.\n");
     return 1;
   }    

   if( type==0 ) { //pdb file type
     if( mode==0 ) { 
       while( fgets(string, 600, fd)!=NULL ) {
         printf("1 %s\n",atm);
         sscanf (string, "%4s", begin );
         printf("2 %s \n",atm);
       }
     }   
   }
   fclose(fd);
   free(fd);
   free(name);
 }

1 个答案:

答案 0 :(得分:1)

字符串begin不足以容纳sscanf将读取\0终止符的四个字符。如果将\0写入atm(取决于字符串在内存中的位置),则会修改atm。从sscanf manpage开始,关于s指令:

  

s匹配一系列非空白字符;下一个指针必须是指向字符数组的指针,该指针足够长以容纳输入序列和终止空字节('\ 0'),这是自动添加的。输入字符串在空格或最大字段宽度处停止,以先到者为准。

我能够在我的机器上重现这种行为,尽管字符串在内存中的确切位置有点不同。但是,通过打印字符串的地址,可以很容易地确定发生了什么。这是一个最小的例子:

#include<stdio.h>

int main() { 
  char begin[2];
  char atm[100]="ATOM";

  printf("begin:    %p\n", begin);
  printf("begin+16: %p\n", begin+16);
  printf("atom:     %p\n", atm);
  printf("1 %s\n",atm);
  sscanf("AAAABBBBCCCCDDDD", "%16s", begin);
  printf("2 %s \n",atm);
  return 0;
}

这会产生输出:

$ ./a.out 
begin:    0x7fffffffe120
begin+16: 0x7fffffffe130
atom:     0x7fffffffe130
1 ATOM
2  

我打印了指针的值,以确定溢出到atm所需的字符串大小。由于(在我的机器上)atombegin+16开始,将{16}个字符读入begin会将空终结符置于begin+16,这是atm的第一个字符,所以现在atm的长度为0。