在结构上使用 strncpy

Using strncpy on struct

假设我定义了这个 student struct

struct student {
    char *name;
};
typedef struct student Student

现在我有以下功能:

void add_student(const char *student_name) {

    // create new student
    Student *new_s;
    new_s = malloc(sizeof(Student));

    strncpy(new_s->name, student_name, sizeof(new_s->name) - 1)
}

我想将 student_name 添加到新学生结构的名称中。但是因为 const charchar 不同,我必须使用 strncpy.

我这样试过,但是我得到了一个分段错误,怎么了?

您只为该行中的结构new_s分配内存

new_s = malloc(sizeof(Student));

这包括变量 char* name,它是一个 pointer to a char。虽然,您还需要该指针指向的内存。

因此,您需要为结构内部的字符指针分配内存name

// create new student
Student *new_s;
new_s = malloc(sizeof(Student));

new_s->name = malloc(100); //assuming you need to store a string of len 100

Haris给出了很好的解决方案。但正如 Florian Zwoch 在评论中所说,您也可以像这样使用 strdup:

void add_student(const char *student_name)
{
    Student *new_s = malloc(sizeof(Student));
    new_s->name = strdup(student_name);
}

请记住,您必须 free new_s->name 而不是 free new_s

您还应该检查 malloc 的 return 值和 strdupNULL 值。因为它 returns NULL 如果可用内存不足。

作为旁注,您可以将 structtypedef 缩短为一个语句,如下所示:

typedef struct student {
    char *name;
} Student;

正如 Johan Wentholt 在他的回答中正确概述的那样,您必须为 Student 结构及其成员 name 指向的字符串分配内存,但您必须 return 新的结构,以便调用者可以用它做一些事情:

Student *add_student(const char *student_name) {
    Student *new_s = malloc(sizeof(Student));
    if (new_s) {
        new_s->name = strdup(student_name);
    }
    return new_s;
}

你的代码调用了未定义的行为,因为你没有为字符串分配内存,更糟糕的是,你让 name 成员未初始化(malloc 没有初始化它的内存 return s).

此外,您不应该使用 strncpy。它 不是 strcpy 的某个安全版本,它是一个 非常 容易出错的函数,大多数程序员对它的语义知之甚少。 切勿使用此功能。如果您看到它已被使用,那么您可能遇到了错误,或者有更好的方法来替换它。

为了完整起见,您的代码:

strncpy(new_s->name, student_name, sizeof(new_s->name) - 1);
  • 会尝试将最多 sizeof(char*)-1 个字符从 student_name 复制到 new_s->name 指向的数组指针中。

  • 如果student_name较长,目标不会以null终止,

  • 如果较短,目标将用空字节填充到给定大小。

  • 此处目标指针未初始化,大小信息无论如何都是伪造的:您真的想复制字符串中的所有字符加上空终止符,这正是 strcpy 所做的。但是你需要为此分配足够的内存。您可以使用:

    new_s->data = malloc(strlen(student_name) + 1);
    strcpy(new_s->data, student_name);
    

Posix 函数 strdup() 在一次调用中完成两个操作:

    new_s->data = strdup(student_name);