2012-06-23 108 views
2

有像這樣的結構。結構中的字符串。損壞

struct Address { 
    int id; 
    int set; 
    char name[MAX_DATA]; 
    char email[MAX_DATA]; 
}; 

和函數集合的地址。

void Database_set(struct Connection *conn, int id, const char *name, const char *email) { 
    struct Address *addr = &conn->db->rows[id]; 
    if(addr->set) die("Address already set"); 

    addr->set = 1; 
    char *res = strncpy(addr->name, name, MAX_DATA); 
    if(!res) die("Name copy failed"); 

    *res = strncpy(addr->email, email, MAX_DATA); 
    if(!res) die("Email copy failed"); 
} 

但addr-> name的第一個字符在此行後面被破壞。

*res = strncpy(addr->email, email, MAX_DATA); 

任何想法?

+3

'如果死( 「名稱複製失敗」)'......我聞到PHP(RES!):d – LihO

+0

'空模(爲const char *消息){ \t如果(錯誤){ \t \t PERROR(消息); (「ERROR:%s \ n」,message);}} \t} \t exit(1); }' 來自PHP :) –

+1

沒有必要檢查'strncpy()'的返回值,因爲它總是返回第一個參數的值。總是。 –

回答

6

strncpy返回它的第一個參數,以便後

char *res = strncpy(addr->name, name, MAX_DATA); 

可變res保持addr->name(等同於&(addr->name[0])),以便當

*res = strncpy(addr->email, email, MAX_DATA); 

運行它是

等效
addr->name[0] = strncpy(addr->email, email, MAX_DATA); 

這個任務破壞了addr->name的第一個字符。正如Greg Hewgill所說,您不需要檢查甚至保存strncpy的返回值。

+0

謝謝。優秀的解釋! –

+0

注意:如果您需要確保字符串爲空終止,strncpy的第三個參數應該是MAX_DATA - 1,您應該手動將最後一個字符設置爲0.如果第二個參數比第一個字符短,則strncopy僅插入一個空值尺寸。一個簡單的解決方案是將MAX_DATA常量加1,然後傳入MAX_DATA-1作爲第三個參數,從而爲空終止保留空間。再次,這假定您將調用依賴於空終止的函數。 – mda

3

我覺得strncpy()函數不是你想要的。考慮電話:

strncpy(addr->name, name, MAX_DATA); 

倘若nameMAX_DATA或多個字符,這將name複製字節到addr->name,將 NUL終止目標。你有兩個選擇一般:

  1. 手動使用下面的代碼NUL,終止結果作爲

    addr->name[MAX_DATA-1] = '\0'; 
    

    但是,因爲你要記住,每次做這個很容易出錯。

  2. 使用一個庫函數,如strlcpy()(通常在BSD派生系統上可用,但不是標準版本),即使源不會完全適合,它也總是NUL終止目標。

+0

請注意,strlcpy不是任何標準的一部分,可能不適用於所有平臺(包括Linux glibc)。 –

+0

謝謝,我已經澄清了參考。 –

+0

感謝strlcpy建議:) –