我如何在这里错误地使用malloc?
我试图学习如何在C99中正确分配运行时内存 我已经尽可能少地写了一个例子,我认为这对我正在尝试做的事情是有启发性的。出于某种原因,对我如何在这里错误地使用malloc?,c,arrays,struct,segmentation-fault,malloc,C,Arrays,Struct,Segmentation Fault,Malloc,我试图学习如何在C99中正确分配运行时内存 我已经尽可能少地写了一个例子,我认为这对我正在尝试做的事情是有启发性的。出于某种原因,对malloc的“内部”调用只分配大小为sizeof(letter_t)的内存块,以实现我对数组中第一个元素的预期(即分配内存) #include <stdlib.h> #include <stdio.h> typedef struct letter_t { char *from; int lines; } letter_t;
malloc
的“内部”调用只分配大小为sizeof(letter_t)
的内存块,以实现我对数组中第一个元素的预期(即分配内存)
#include <stdlib.h>
#include <stdio.h>
typedef struct letter_t {
char *from;
int lines;
} letter_t;
typedef struct letterbox_t {
char *name;
int n_letters;
struct letter_t **letters;
} letterbox_t;
int main() {
char *name[] = { "amy", "bob", "claud" };
int n_letters[] = { 1, 3, 2 };
// layout memory and populate letterbox_t array
struct letterbox_t *letterboxes;
letterboxes = malloc(sizeof(letterbox_t) * 3);
for (int i = 0; i < 3; i++) {
letterboxes[i].name = name[i];
letterboxes[i].n_letters = n_letters[i];
struct letter_t *letters[n_letters[i]];
for (int j = 0; j < n_letters[i]; j++) {
letters[j] = malloc(sizeof(letter_t));
}
letterboxes[i].letters = letters;
}
// populate letter_t array for each letterbox_t
for (int i = 0; i < 3; i++) {
for (int j = 0; j < letterboxes[i].n_letters; j++) {
// =========================================
letterboxes[i].letters[j]->from = "spammer";
// =========================================
// the above line fails for i = 1, j = 1
}
}
for (int i = 0; i < 3; i++) {
printf("%s has %d letters from\n", letterboxes[i].name, letterboxes[i].n_letters);
for (int j = 0; j < letterboxes[i].n_letters; j++) {
printf(" %s\n", letterboxes[i].letters[j]->from);
}
}
return 0;
};
更改此项:
struct letter_t* letters[n_letters[i]];
为此:
struct letter_t** letters = malloc(n_letters[i] * sizeof(struct letter_t*));
因为,正如@TomKarzes所评论的,您在for循环的主体内创建了字母
,因此一旦循环终止,它就超出了范围
因此,您需要为它动态分配内存,以便在循环终止后不会释放内存
PS:不要忘记在程序结束时释放内存,顺序与动态分配内存时的顺序相反。您有很多小问题。首先,正如我在评论中提到的,您尝试为
struct letter_t*letters[n_letters[i]]分配代码>与结构字母**字母不匹配代码>
接下来,在继续之前,nit,“*”
属于变量名,而不是大多数情况下的类型。为什么?
int* a, b, c;
在上面,您肯定没有声明指向int
的三指针。而是声明整数指针a
,以及整数b,c
。更清楚地写为:
int *a, b, c;
分配内存时,必须验证分配是否成功--每次都是,例如
size_t n_people = sizeof name / sizeof *name;
// layout memory and populate letterbox_t array
struct letterbox_t *letterboxes;
/* allocate letterboxes for each of the people */
letterboxes = malloc (sizeof *letterboxes * n_people);
if (!letterboxes) { /* validate Every allocation */
perror ("malloc-letterboxes");
return 1;
}
您现在已经分配了3个信箱的存储空间,可以开始处理内容了。您可以为每个项目指定名称和字母数:
for (size_t i = 0; i < n_people; i++) {
/* assigning pointer to string literal */
letterboxes[i].name = name[i];
letterboxes[i].n_letters = n_letters[i]; /* int assignment */
现在,所有存储都已正确分配并经过验证,您可以将每个字母填充到每个人,然后输出结果,例如
// populate letter_t array for each letterbox_t
for (size_t i = 0; i < n_people; i++) {
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j]->from = "spammer";
/* added lines just to complete assignments */
letterboxes[i].letters[j]->lines = letterboxes[i].n_letters * 10;
}
}
// output all letterboxes and letters
for (size_t i = 0; i < n_people; i++) {
printf("%s has %d letters from\n",
letterboxes[i].name, letterboxes[i].n_letters);
for (int j = 0; j < letterboxes[i].n_letters; j++) {
printf(" %s %d\n", letterboxes[i].letters[j]->from,
letterboxes[i].letters[j]->lines);
}
}
然后,当您使用完内存后,您可以释放()
它,例如
for (size_t i = 0; i < n_people; i++) /* free each letterbox */
freeletterbox (&letterboxes[i]);
free (letterboxes); /* free pointers */
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要它时可以释放它
必须使用内存错误检查程序,以确保您不会试图访问内存或写入超出/超出分配的块的边界,尝试在未初始化的值上读取或建立条件跳转,最后确认释放所有已分配的内存
对于Linux,valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可
$ valgrind ./bin/letters
==4735== Memcheck, a memory error detector
==4735== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4735== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4735== Command: ./bin/letters
==4735==
amy has 1 letters from
spammer 10
bob has 3 letters from
spammer 30
spammer 30
spammer 30
claud has 2 letters from
spammer 20
spammer 20
==4735==
==4735== HEAP SUMMARY:
==4735== in use at exit: 0 bytes in 0 blocks
==4735== total heap usage: 10 allocs, 10 frees, 216 bytes allocated
==4735==
==4735== All heap blocks were freed -- no leaks are possible
==4735==
==4735== For counts of detected and suppressed errors, rerun with: -v
==4735== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放所有已分配的内存,并且没有内存错误
仔细检查一下,如果您还有其他问题,请告诉我。结构字母t*字母[n字母[i]代码>与结构字母**字母不匹配因为字母是结构字母**
,所以在分配内存块地址给每个字母[i]
之前,您需要分配所需的指针的数量代码>这是本地存储。它超出范围时未定义。为此,您需要使用malloc
。
/* simple function to free single letterbox_t completely */
void freeletterbox (letterbox_t *l)
{
for (int i = 0; i < l->n_letters; i++)
free (l->letters[i]);
free (l->letters);
}
for (size_t i = 0; i < n_people; i++) /* free each letterbox */
freeletterbox (&letterboxes[i]);
free (letterboxes); /* free pointers */
#include <stdio.h>
#include <stdlib.h>
typedef struct letter_t {
char *from;
int lines;
} letter_t;
typedef struct letterbox_t {
char *name;
int n_letters;
struct letter_t **letters;
} letterbox_t;
/* simple function to free single letterbox_t completely */
void freeletterbox (letterbox_t *l)
{
for (int i = 0; i < l->n_letters; i++)
free (l->letters[i]);
free (l->letters);
}
int main (void) {
char *name[] = {"amy", "bob", "claud"};
int n_letters[] = {1, 3, 2};
size_t n_people = sizeof name / sizeof *name;
// layout memory and populate letterbox_t array
struct letterbox_t *letterboxes;
/* allocate letterboxes for each of the people */
letterboxes = malloc (sizeof *letterboxes * n_people);
if (!letterboxes) { /* validate Every allocation */
perror ("malloc-letterboxes");
return 1;
}
for (size_t i = 0; i < n_people; i++) {
/* assigning pointer to string literal */
letterboxes[i].name = name[i];
letterboxes[i].n_letters = n_letters[i]; /* int assignment */
/* allocate letterboxes[i].n_letters pointers */
letterboxes[i].letters =
malloc (sizeof *letterboxes[i].letters * letterboxes[i].n_letters);
if (!letterboxes[i].letters) { /* validate allocation */
perror ("malloc-letterboxes.letters");
return 1;
}
/* allocate letters per-pointer */
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j] =
malloc (sizeof *letterboxes[i].letters[j]);
if (!letterboxes[i].letters[j]) {
perror ("malloc-letterboxes[i].letters[j]");
return 1;
}
}
}
// populate letter_t array for each letterbox_t
for (size_t i = 0; i < n_people; i++) {
for (int j = 0; j < letterboxes[i].n_letters; j++) {
letterboxes[i].letters[j]->from = "spammer";
/* added lines just to complete assignments */
letterboxes[i].letters[j]->lines = letterboxes[i].n_letters * 10;
}
}
// output all letterboxes and letters
for (size_t i = 0; i < n_people; i++) {
printf("%s has %d letters from\n",
letterboxes[i].name, letterboxes[i].n_letters);
for (int j = 0; j < letterboxes[i].n_letters; j++) {
printf(" %s %d\n", letterboxes[i].letters[j]->from,
letterboxes[i].letters[j]->lines);
}
}
for (size_t i = 0; i < n_people; i++) /* free each letterbox */
freeletterbox (&letterboxes[i]);
free (letterboxes); /* free pointers */
return 0;
}
$ ./bin/letters
amy has 1 letters from
spammer 10
bob has 3 letters from
spammer 30
spammer 30
spammer 30
claud has 2 letters from
spammer 20
spammer 20
$ valgrind ./bin/letters
==4735== Memcheck, a memory error detector
==4735== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4735== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4735== Command: ./bin/letters
==4735==
amy has 1 letters from
spammer 10
bob has 3 letters from
spammer 30
spammer 30
spammer 30
claud has 2 letters from
spammer 20
spammer 20
==4735==
==4735== HEAP SUMMARY:
==4735== in use at exit: 0 bytes in 0 blocks
==4735== total heap usage: 10 allocs, 10 frees, 216 bytes allocated
==4735==
==4735== All heap blocks were freed -- no leaks are possible
==4735==
==4735== For counts of detected and suppressed errors, rerun with: -v
==4735== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)