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

标签 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)

为什么 whilecondition 不能正常工作?

最佳答案

首先,

a = malloc(sizeof(user) * user_counts);

有一个问题 - 你想分配 user_countspointers 实例给 user,而不是 user , 所以那一行应该是

a = malloc(sizeof(user *) * user_counts);

但是,有一个更简单的方法来解决这个问题 - sizeof 运算符可以将 expressions 作为参数以及类型名称。所以你可以将该行重写为

a = malloc( sizeof *a * user_counts );

表达式 *a 的类型是user *,所以sizeof *a 等价于 sizeof(用户 *)。这让您的生活变得更简单了,因为您不必弄清楚 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 */
   }

现在,针对您的实际问题。您的代码因以下原因之一而崩溃:

  • a 的初始 malloc 失败,因此您在使用 a[i] 的第一行崩溃;
  • 您的 a[i] 之一的 malloc 失败,因此您在 a[i]->id = 1 上崩溃>;
  • 您已成功为 a 的所有 users_count 元素分配内存 - no 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++ )
    ...
}

关于在 C 中检查 NULL 指针不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41862570/

相关文章:

C 堆/堆栈和函数返回值

c++ - 作为对象的类成员 - 指针与否? C++

c - 从函数修改结构?

mongodb - Grails 2 和 mongodb 不工作

javascript - Stripe 支付示例未显示

c - INT_MAX+1 = INT_MIN 是有符号整数吗?

c - 从 C 中的函数返回二维数组

php - 远程服务器上的 exec() 仅返回 return-var 1 |尝试了7种方法但没有成功

C++从数组到指针的转换

javascript - 尝试解决 Promise 时,Firebase Auth 给我一个错误