2013-05-16 58 views
1

我在使用sscanf讀取字符串時遇到問題。我已經淡化了代碼,專注於這個問題。下面是在應該打開一個文件並閱讀某些內容的整個代碼中的一個函數。但sscanf表現奇怪。例如,我聲明一個名爲atm的字符串,其內容爲'ATOM'。在sscanf之前,它將該字符串打印爲ATOM,而之後爲空。可能是什麼問題呢?我認爲這一定是一個分配問題,但我找不到它。我在其他主題上嘗試了一些建議,例如用其他東西替換%s,但它沒有幫助。sscanf函數更改另一個字符串的內容

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

字符串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。由於(在我的機器上)​​始於begin+16,閱讀十六個字符到begin提出在begin+16空終止符,這是atm第一個字符,所以現在atm具有長度爲0

+0

謝謝你,確實是問題和帖子非常有啓發性。 – Sina

+0

@Sina很高興幫助! 「我祝賀你成功進入緩衝區溢出俱樂部,這是最大的職業程序員協會之一!」,但有時候幽默並沒有出現在文本中。這些是易於編寫的各種錯誤,並且可能潛伏在許多代碼行中。很高興我們今天得到了一個! :) –

+0

謝謝,實際上我有一個關於matlab的消息方式:p我通常在數學部分進行環聊。 後續問題,因爲我使用tcc編譯器很難捕獲這些錯誤,特別是當代碼變得太長時,我甚至發現編譯器也錯過了這些錯誤,甚至被說服寫入第四個輸入需要幾天才能找到的三維數組。是否有任何編譯器或調試器可以建議您捕獲此類錯誤? – Sina