2012-06-23 109 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建议:) –