我有一个名为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);
}
}
我要做的所有代码-将名称存储在动态分配的结构中,然后释放它。 稍后,我计划用从文件输入的值替换硬编码名称。
对错误有任何想法吗?谢谢。
答案 0 :(得分:1)
至少5个问题:
否则,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
相同。
也分配给指针,而不是char
。 @Barmar
Person
成员是数组。对于动态分配,它们应该是指针。 @NthDeveloper
typedef struct {
// char firstName[15];
// char lastName[15];
char *firstName;
char *lastName;
} Person;
第二次测试是错误的
// if (temp->firstName == NULL)
if (temp->lastName == NULL)
int
与size_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()为这些成员保留其他内存,也无需释放它们。