我有一个函数,它返回一个多个间接指针,结果如下:
typedef struct {
int id;
char *name;
} user;
user **myfn(int users_count) {
user **a;
a = malloc(sizeof(user) * user_counts);
for(int i = 0 ; i<user_counts ; i++) {
*(a+i) = malloc(sizeof(user));
(*(a+i))->id = 1;
(*(a+i))->name = malloc(sizeof(char) * 25);
strncpy((*(a+i))->name, "Morteza", 25); // just for example
}
return a;
}
现在,当我想在main函数中抓取此结果时,它会显示所有用户名,但最后会遇到Segmentation fault
错误。
int main() {
user **a = myfn(10);
int i = 0;
while((*(a+i)) != NULL) {
printf("ID: %d \t %s\n", (*(a+i))->id, (*(a+i))->name);
i++;
}
}
结果:
ID: 1 Morteza
ID: 2 Morteza
...
...
ID: 10 Morteza
Segmentation fault (core dumped)
为什么condition
的{{1}}不能正常工作?
答案 0 :(得分:2)
首先,
a = malloc(sizeof(user) * user_counts);
有问题 - 您希望将指针的user_counts
个实例分配给user
,而不是user
的实例,因此该行应为
a = malloc(sizeof(user *) * user_counts);
但是,有一种更简单的方法 - sizeof
运算符可以将表达式作为参数以及类型名称。所以你可以将该行重写为
a = malloc( sizeof *a * user_counts );
表达式 *a
的类型为user *
,因此sizeof *a
相当于sizeof (user *)
。这使你的生活变得更简单,因为你不必弄清楚a
指向的类型 - 让编译器付出艰苦的努力。
您应该始终检查malloc
来电的结果。
a = malloc( sizeof *a * users_count );
if ( a )
{
// do stuff with a
}
其次,请勿使用*(a+i)
索引a
- 请改用a[i]
。使事情更容易阅读。所以,
*(a+i) = malloc(sizeof(user));
(*(a+i))->id = 1;
(*(a+i))->name = malloc(sizeof(char) * 25);
变为
a[i] = malloc(sizeof *a[i]);
if ( a[i] )
{
a[i]->id = 1;
a[i]->name = malloc(sizeof *a[i]->name * 25);
}
else
{
/* deal with memory allocation failure */
}
现在,针对您的实际问题。您的代码崩溃是出于以下原因之一:
malloc
的初始a
失败,因此您在使用a[i]
的第一行崩溃; malloc
之一的a[i]
失败,因此您在a[i]->id = 1
上崩溃; users_count
的所有a
元素分配了内存 - 否 a[i]
为NULL
,因此您循环显示最后一个数组的元素,并尝试取消引用紧随其后的对象,很可能不是有效的指针。除了在每次malloc
调用后添加支票外,您应该根据users_count
进行循环:
for ( i = 0; i < users_count; i++ )
printf("ID: %d \t %s\n", a[i]->id, a[i]->name);
或者,您需要为a
分配一个额外元素并将其设置为NULL
:
a = malloc( sizeof *a * (users_count + 1) );
if ( a )
{
a[users_count] = NULL;
for ( i = 0; i < users_count; i++ )
...
}
请注意calloc
将所有已分配的内存初始化为0,因此您可以使用它而不必担心明确将元素设置为NULL
:
a = calloc( users_count + 1, sizeof *a );
if ( a )
{
for ( i = 0; i < users_count; i++ )
...
}