将指针传递给函数不能按预期工作

时间:2017-11-11 22:03:38

标签: c function pointers struct

我有这个很小的代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct Ship Ship;

struct Ship
{
    int x, y;
};

int main()
{
    Ship* ship;

    assignShip(ship);

    printf("%d", ship->x);

    return 0;
}


void assignShip(Ship* ship)
{
    Ship anotherShip;
    anotherShip.x = 10;

    ship = &anotherShip;
}

它不起作用。 我创建一个名为ship的Ship类型的指针,然后我将指针传递给我的函数,我将指针设置为anotherShip,然后尝试查看它是否有效,但控制台进入“没有响应”并崩溃。 我做错了什么?

3 个答案:

答案 0 :(得分:1)

“我做错了什么?”

一堆东西。

首先,在函数assignShip内部,局部变量anotherShip在函数末尾超出范围,使ship指向不再存在的变量。

其次,由于您是按值而不是引用传递变量ship,因此您无法在函数内对其进行永久更改。

相反:

#include <stdio.h>
#include <stdlib.h>

typedef struct Ship Ship;

struct Ship
{
    int x, y;
};

int main()
{
    Ship* ship = NULL;
    assignShip(&ship);
    // Check ship here, it is now non-NULL.
    printf("%d", ship->x);
    return 0;
}

void assignShip(Ship** ship)
{
    static Ship anotherShip;
    anotherShip.x = 10;
    *ship = &anotherShip;
}

答案 1 :(得分:1)

您的代码和方法存在一些问题:

参数按值

传递

C中,参数按值传递。这意味着assignShip会收到main中指针的副本。因此,此赋值ship = &anotherShip;对main的Ship* ship;变量没有影响,因为您修改了函数的本地副本。

对此的修复是指向主变量的指针。即:

int main()
{
    Ship* ship;

    assignShip(&ship); // we pass a pointer to the variable `ship`

    printf("%d", ship->x);

    return 0;
}


void assignShip(Ship** ship) // receive pointer to pointer
{
    Ship anotherShip;
    anotherShip.x = 10;

    *ship = &anotherShip; // ... still wrong
}

然而,这将我们带到您的下一个重大问题:

本地功能变量具有自动存储持续时间

anotherShip是函数assignShip的本地,这意味着一旦函数调用结束该变量被销毁,所以在main中你将留下一个悬空指针

对此的修复是使用动态分配:

int main()
{
    Ship* ship;

    assignShip(&ship);

    printf("%d", ship->x);

    return 0;
}


void assignShip(Ship** ship) // receive pointer to pointer
{
    Ship* anotherShip = malloc(sizeof(Ship));
    anotherShip->x = 10;

    *ship = anotherShip;
}

现在我们有一个对象将在assignShip的调用后继续存在。

这就把我们带到了下一个问题:

具有动态存储持续时间的对象必须具有程序员管理的生命周期

与自动存储持续时间不同,编译器负责管理对象的生命周期,动态存储持续时间是程序员的责任。因此,分配有malloc的每个内存都必须与free一起发布:

int main()
{
    Ship* ship;
    assignShip(&ship);

    printf("%d", ship->x);

    free(ship); // free the memory
    return 0;
}

这将我们带到下一期:

手动管理资源的所有权必须明确

虽然我们程序的上述版本在技术上是正确的,但我们处理内存管理的方式存在问题。

请考虑以下代码段:

Ship* ship;
assignShip(&ship); // we pass a pointer to the variable `ship`

assignShip是否为参数分配内存。我们是否必须在它之后调用free或者它是否期望接收指向有效内存位置的指针?

要回答这个问题,我们必须参考assignShip(如果存在)和/或assignShip

的源代码的文档

一种方法是从函数名称中明确说明。例如allocateAndAssignShip

另一个是将分配移出函数:

int main()
{
    Ship* ship = malloc(sizeof(Ship));
    assignShip(ship);

    printf("%d", ship->x);

    free(ship);
    return 0;
}


void assignShip(Ship* ship)
{
   ship->x = 10;
}

答案 2 :(得分:0)

发货另一艘船;在堆栈中声明,一旦你离开函数指针未声明,这意味着你分配了未声明的指针。 要么分配它,要么在本地静态或全局,它应该工作