【问题标题】:strncpy only copies part of stringstrncpy 只复制字符串的一部分
【发布时间】:2015-01-24 13:48:44
【问题描述】:

假设我有这样的结构

typedef struct _student {
    int studentID;
    char name[30];
    char class[10];
    char department[10];
} Student;

以下函数会创建 Student 类型的新变量:

Student *new_student(int id, char *name, char *class, char *dept) {
    Student *s = (Student *)malloc(sizeof(Student *));

    s->studentID = id;
    strncpy(s->name, name, sizeof(s->name) - 1);
    s->name[sizeof(s->name) - 1] = '\0';
    strncpy(s->class, class, sizeof(s->class) - 1);
    s->class[sizeof(s->class) - 1] = '\0';
    strncpy(s->department, dept, sizeof(s->department) - 1);
    s->department[sizeof(s->department) - 1] = '\0';
    return s;
}

void display_student(Student *s) {
    printf("Student: %d | %s | %s | %s\n", s->studentID, s->name, s->class, s->department);
}

为了测试我的代码,我只是在我的 main() 中写了一些简单的东西

int main() {

    Student *s1 = new_student(20111201, "Lurther King Anders Something", "ICT-56", "SoICT");
    Student *s2 = new_student(20111202, "Harry Potter", "ICT-56", "SoICT");
    Student *s3 = new_student(20111203, "Hermione Granger", "ICT-56", "SoICT");
    Student *s4 = new_student(20111204, "Ron Weasley", "ICT-56", "SoICT");
    display_student(s1);
    display_student(s2);
    display_student(s3);
    display_student(s4);

    return 0;
}

但是,结果对我来说是出乎意料和奇怪的:

谁能帮我解释一下为什么会出现奇怪的结果!我认为我以正确的方式做事,我已经应用了 strncpy 的安全使用,但我不理解输出。

【问题讨论】:

    标签: c string strncpy


    【解决方案1】:

    这个

     ... malloc(sizeof(Student *));
    

    分配

    sizeof(Student *)
    

    字节。通常是 4 或 8,因为 Student * 是指针类型。

    你可能想要

         ... malloc(sizeof(Student));
    

    甚至更好:

    Student * s = malloc(sizeof(*s));
    

    甚至没有无用的括号:

    Student * s = malloc(sizeof *s); /* sizeof is an operator, not a function. */
    

    将malloc(sizeof *s) 读作:“分配与s 指向的字节一样多的字节。”

    【讨论】:

    • 哦,我明白了。非常感谢你。我没看到这么简单的东西。我现在会接受你的回答:D
    【解决方案2】:
    Student *s = (Student *)malloc(sizeof(Student *));
    

    那条线是错误的。您为 Student 分配了要使用的内存,但只要求为 Student* 提供足够的内存。

    您可以通过将表达式而不是类型传递给sizeof 来大大降低发生此类错误的可能性。
    另外,in C you don't cast on assigning from a void* to an other data-pointer-type:

    Student *s = malloc(sizeof *s);
    

    作为建议,如果需要,请考虑使用strlcpy。
    当然,除非您依赖于将缓冲区的其余部分归零,例如因为您将它们直接写入文件。
    strncpy 几乎总是错误的,尽管您似乎已经巧妙地避免了所有的陷阱(可能性能除外)。

    【讨论】:

    • 我没有听说过 strlcpy(我从 C 开始)。感谢您的建议,我会找到更多相关信息
    • strlcpy() 不是 C 标准的一部分。 @DucCuong 它是某些平台上的扩展。
    【解决方案3】:

    好的,首先: malloc(sizeof(Student*)) 你只得到了 4 个字节的指针大小,所以你没有为你的结构获得足够的内存。我想知道它实际上是如何工作的,但无论如何。因此,要获取结构的大小,请使用以下示例:

    学生*s = (学生*)malloc(sizeof(Student));

    第二次你在堆中分配了新的数据,在你尝试执行之后:

    strncpy(s->name, name, sizeof(s->name) - 1);

    这里你的 s->name 在内存中有一些垃圾,因为你没有为这个内存分配任何数据,你应该使用函数参数中的数据长度

     Student *new_student(int id, char *name, char *classSt, char *dept) 
    {
        Student *s = (Student *)malloc(sizeof(Student));
    
        s->studentID = id;
    
        strncpy(s->name, name, strlen(name) + 1);
        strncpy(s->classSt, classSt, strlen(classSt) + 1);
        strncpy(s->department, dept, strlen(dept) + 1);
    
        return s;
    }
    

    【讨论】:

    • "你应该使用数据长度" 这是非常危险的,因为源可能比目标长,这样strncpy() 会写在目标后面。此外,sizeof(s->name) 根据 OP 的代码将始终为 30,无论 s->name 是否已被初始化。 -1
    • 不,你建立了一个缓冲区溢出陷阱。您给出目标缓冲区的大小,而不是输入的长度。
    猜你喜欢
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 2011-03-01
    • 1970-01-01
    • 2018-05-23
    • 2022-01-12
    相关资源
    最近更新 更多