使用free()函数会导致运行时错误

时间:2019-01-04 22:55:53

标签: c struct free dynamic-memory-allocation

我有一个名为Person的结构,其中包含两个属性-名字和姓氏。 在为Person类型的变量成功动态分配内存后,为我想要释放内存的属性提供值,但是我不断遇到运行时错误(程序窗口崩溃) 这是代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct {
char firstName[15];
char lastName[15];
} Person;

void main(){
int len = 0;
char  firstName[]="danny", lastName[]="johnes";

Person *temp = (Person*)malloc(sizeof(Person));
if (temp == NULL)
    return;

    len = strlen(firstName);
    temp->firstName[len] = (char*)malloc(sizeof(char)*(len));
    if (temp->firstName == NULL)
        return;
    strcpy(temp->firstName, firstName);

    len = strlen(lastName);
    temp->lastName[len] = (char*)malloc(sizeof(char)*(len));
    if (temp->firstName == NULL)
        return;
    strcpy(temp->lastName, lastName);

freePerson(temp);
system("pause");
return;
}

这是我用来释放内存的功能:

void freePerson(Person* ps) {
    if (ps != NULL) {
        free(ps->firstName);
        free(ps->lastName);
        free(ps);
    }
}

我要做的所有代码-将名称存储在动态分配的结构中,然后释放它。 稍后,我计划用从文件输入的值替换硬编码名称。

对错误有任何想法吗?谢谢。

4 个答案:

答案 0 :(得分:1)

至少5个问题:

  1. 要复制字符串,请确保分配给字符(包括空字符)留有足够的空间。

否则,strcpy()会在分配之外写入未定义行为(UB)。

    len = strlen(firstName);
    // temp->firstName[len] = (char*)malloc(sizeof(char)*(len ));
    temp->firstName = (char*)malloc(sizeof(char)*(len + 1));
    //                                                + 1 
    ...
    strcpy(temp->firstName, firstName);

lastName相同。

  1. 也分配给指针,而不是char@Barmar

  2. Person成员是数组。对于动态分配,它们应该是指针。 @NthDeveloper

    typedef struct {
      // char firstName[15];
      // char lastName[15];
      char *firstName;
      char *lastName;
    } Person;
    

  1. 第二次测试是错误的

    // if (temp->firstName == NULL)
    if (temp->lastName == NULL)
    
  2. intsize_t

int len = 0;假定字符串长度适合int。尽管这非常普遍,但从strlen()返回的类型是size_t。该 unsigned 类型的大小适合数组索引和大小调整-不太宽,也不太窄。这不是学习者代码中的关键问题。

// int len = 0;
size_t len = 0;

提示:不需要强制转换。分配给引用的对象,而不是类型。更容易编写正确的代码,进行审查和维护。

// Person *temp = (Person*)malloc(sizeof(Person));
Person *temp = malloc(sizeof *temp);

// temp->firstName[len] = (char*)malloc(sizeof(char)*(len + 1));
temp->firstName = malloc(sizeof *(temp->firstName) * (len + 1));

提示:尽管不是C标准,但是许多平台都提供strdup()来分配和复制字符串。样本strdup() code

temp->firstName = strdup(firstName);

提示:可能是最有价值的提示:良好启用了警告的良好编译器应该警告temp->firstName[len] = (char*)malloc(sizeof(char)*(len));,因为它是赋值中可疑的类型不匹配。这些警告可以节省您和我们的所有时间。确保您的下一个编译已启用所有警告。

答案 1 :(得分:1)

您已经为firstName分配了空间,因此必须在大小限制(15个字节)内复制该名称。您可以像这样用snprintf做到最好:

snprintf(temp->firstName, sizeof(temp->firstName), "%s", firstName);

lastName也一样。请注意,如果长度超过字段的大小,两者都可能会被截断。

另一个选择是动态分配字段。然后,您的struct成员应该是指针,而不是char数组:

typedef struct {
    char *firstName;
    char *lastName;
} Person;

然后您可以像这样分配和分配名称:

temp->firstName = strdup(firstName); // (same for lastName)

但是请记住,如果要释放整个项目,则必须分别释放这些字段。

答案 2 :(得分:1)

如果您不想为结构中的名称指定最大大小,则需要将其声明为指针,而不是数组。

typedef struct {
    char *firstName;
    char *lastName;
} Person;

然后,您应将malloc()的结果分配给成员,而不对其建立索引。您还需要将1添加到strlen(firstName),以为空终止符腾出空间。

temp->firstName = malloc(strlen(firstName)+1);
if (temp->firstName == NULL) {
    return;
}
strcpy(temp->firstName, firstName);

答案 3 :(得分:1)

这就是我的写法:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FIRSTNAME_MAXLEN 15
#define LASTNAME_MAXLEN 15

typedef struct
{
        char firstName[FIRSTNAME_MAXLEN+1];
        char lastName[LASTNAME_MAXLEN+1];
} person_t;

void freePerson(person_t *ps) {
        if (ps) {
                free(ps); ps=NULL;
        }
}

int main(){
        const char *firstName="danny";
        const char *lastName="johnes";

        person_t *temp = calloc(1, sizeof(person_t));
        if (!temp) return 1;

        strncpy(temp->firstName, firstName, FIRSTNAME_MAXLEN);
        strncpy(temp->lastName, lastName, LASTNAME_MAXLEN);

        printf("test: firstname: %s\n", temp->firstName);
        printf("test: lastname: %s\n", temp->lastName);
        freePerson(temp);

        return 0;
}

您在堆上分配了足够的空间,并使用calloc()进行清理,然后使用strncpy()复制字符串,将其限制为保留的字节数,并避免了缓冲区溢出。最后,您需要free()由calloc()返回的内存。 由于您在结构体内部分配了char firstName []和char lastName [],因此无需使用malloc()为这些成员保留其他内存,也无需释放它们。