在C中检查NULL指针不起作用

时间:2017-01-25 22:08:30

标签: c pointers runtime-error

我有一个函数,它返回一个多个间接指针,结果如下:

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}}不能正常工作?

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++ )
    ...
}