【问题标题】:void pointer to a struct pointer指向结构指针的 void 指针
【发布时间】:2016-03-21 19:11:22
【问题描述】:

我在将 void 指针分配给另一个结构指针时遇到问题。 我的输入参数在函数 semaphoreCreateBinary 内部发生了更改,但是当它返回到 main 时,它又是空的。我可能必须做某种类型的演员,但我似乎无法让它发挥作用。

我将包含我认为理解我的问题所必需的代码:

来自我的头文件。

typedef struct semaphoreStruct
{
    int               smValue;  
    tcbExtS           *smHolder;  
    int               smCeiling;  
}semaS;

typedef void * SemaphoreHandle;

在我的 C 文件中

unsigned int semaphoreCreateBinary(void *ro_Handle,unsigned int i_InitialValue)
{
    semaS *Semaphorehandle1;

    Semaphorehandle = malloc (sizeof(*Semaphorehandle));

    Semaphorehandle1->smValue = i_InitialValue;
    ro_Handle = Semaphorehandle1; //seems to get the correct value

    return resultUnInt;
}

int main(void)
{
    SemaphoreHandle s1vPtr;

    semaphoreCreateBinary(&s1vPtr,0);

    int IV = s1vPtr->smValue//s1vPtr is empty again here
}

有什么建议可以改正吗?

编辑: 即使我将参数作为地址传递: semaphoreCreateBinary(&s1vPtr,0); 这是行不通的。 我无法更改输入类型,因为我们从老师那里得到了它作为 API 规范,否则我会更改它。

【问题讨论】:

  • 您传递一个 void* 指针,然后在函数中更改指针的值,但指针的值是副本,因此不会保存更改。您需要将地址传递给 void* 指针,然后更改将被保存。
  • semaS *Semaphorehandle1; Semaphorehandle1->smValue = i_InitialValue; 可能会由于未初始化的指针变量而导致 segfault。而且,该函数尝试更改作为参数传递的变量的副本,但即便如此,它也会分配一个在函数返回时超出范围的值。
  • 您的问题缺少对代码打算做什么的描述:应该 semaphoreCreateBinary modify/initialize 一个作为指针传递给它的信号量 struct ,还是应该动态地分配和初始化一个新的信号量?
  • 它应该动态创建一个新的信号量,然后当函数运行完成时输入参数应该指向新的信号量,这样我就可以在 main 中使用它
  • 如果您不能使用**,则更改函数类型并返回指向已分配内存的指针:您不使用当前返回值。如果您需要返回失败状态,return NULL... 并且请不要更改问题以响应 cmets 和答案,当通读整个问题和对话时,这会使他们的意图变得毫无意义。

标签: c pointers struct pass-by-reference pass-by-value


【解决方案1】:

在 C 中,参数按值传递给函数。因此,您只更改函数内部的值。另外,还有一个错误:你没有分配Semaphorehandle1。所以,会有段错误。这是正确的:

unsigned int semaphoreCreateBinary(void **ro_Handle,unsigned int i_InitialValue)
{
    semaS *Semaphorehandle1 = malloc(sizeof(semaS));
    Semaphorehandle1->smValue = i_InitialValue;
    *ro_Handle = Semaphorehandle; //seems to get the correct value
    return resultUnInt;
}

使用后别忘了释放内存。

【讨论】:

  • 我不能使用双指针作为输入参数,因为 API 是我老师指定的。
  • @JSmannen,你不能在不改变函数签名的情况下改变参数的值。
  • 这是我想要的,但没有遵循我老师的 API... 有没有其他方法可以做到不改变而不改变函数签名?
【解决方案2】:

这行得通:

unsigned int semaphoreCreateBinary(void *ro_Handle, unsigned int i_InitialValue)
{
    semaS *Semaphorehandle1 = malloc(sizeof(semaS));
    Semaphorehandle1->smValue = i_InitialValue;
    *(semaS**)ro_Handle = Semaphorehandle1;
}

int main(void)
{
    semaS* s1vPtr;
    semaphoreCreateBinary(&s1vPtr, 1);

    int IV = s1vPtr->smValue;

    free(s1vPtr);
    printf("%d\n", IV);
}

说明:理解为什么这是一个有用的问题解决方案需要两个重要的见解 - 作为未来的软件开发人员,您需要自己获得这些见解:

  1. 在 C 中,如果您想要一个函数来修改某些内容,您必须传递一个指向该内容的指针。在您的情况下,您想要修改 semaS* 指针(让它指向新的 malloced 内存位置)。所以如果你想修改semaS*,你必须将semaS**传递给函数。
  2. void* 可以转换为任何指针类型,包括到指针的指针。

另请注意,您最初的 malloc 大小是错误的。由于您想分配一个新的semaS 结构,您必须malloc 一个大小为size(semaS) 的内存块(您malloc 分配了一个指针大小的内存块)。不幸的是,使用任何其他块大小都不会在 C 中引发编译器警告或错误。但它会浪费内存(如果块大小太大)或导致内存损坏(如果块大小太小)。

【讨论】:

  • 工作!太感谢了!知道通过某种方式投射是可能的 =)
  • 这将改进代码以使第一个参数semaS **ro_Handle 并避免强制转换
  • @M.M OP 解释说他不允许更改函数签名,因为这是作为 API 接口提供给他的。
【解决方案3】:

在您的代码中,ro_Handle = Semaphorehandle1; 不会更改 main 范围内的指针值,因为指针是 semaphoreCreateBinary 范围内的副本(按值传递)。为了编辑指针的值,你需要一个指向它的指针:

unsigned int semaphoreCreateBinary(void **ro_Handle,unsigned int i_InitialValue) {
    ...
    *ro_Handle = Semaphorehandle1;

然后您需要将指针的地址传递给函数:

semaphoreCreateBinary(&s1vPtr,0);

【讨论】:

  • 我不能使用双指针作为输入参数,因为 API 是我老师指定的。
  • 这是我想要的,但没有遵循我老师的 API... 有没有其他方法可以做到不改变而不改变函数签名?
  • 不,你不能改变 ro_handle 指向的位置而不通过指针传递它。
【解决方案4】:

您似乎对指针的工作方式有一些严重的误解。指针是一个可以存储有效变量的位置的变量,但不是必须的 - 这取决于您是否正确初始化了指针。你的线路

semaS *Semaphorehandle1;

声明一个未初始化的指针,即指向任意内存位置的指针。下一行

Semaphorehandle1->smValue = i_InitialValue;

然后取消引用您未初始化的指针,从而写入任意内存位置 - 这是典型的内存损坏,可能会导致整个程序出现未定义的行为。

【讨论】:

  • 我没有包括我的所有代码,我为我的问题中指向的结构分配内存,因为我认为这对这个特定问题无关紧要。
  • 这很重要,因为您的代码没有表现出您想要的行为,您正试图找出原因。丢失的分配可以解释上述行为,但其他问题也是如此。我们无法知道您的代码的哪些部分是错误的,因为您选择遗漏了代码,哪些部分是“真正”错误的,因此我们必须指出任何可能的问题。这可能会导致不必要的误解。
【解决方案5】:

在您的代码中,在 semaphoreCreateBinary() 函数内

 ro_Handle = Semaphorehandle1;

不会达到您的目的。指针ro_Handle itself 通过值传递传递给函数,因此您不能从函数更改指针本身并期望它反映函数外部的更改。你可以改变指针指向的值,它会维持,但指针不能。

如果你想改变指针,你需要传递指针的地址,作为一个指向指针的指针。

话虽如此,

semaS *Semaphorehandle1;
Semaphorehandle1->smValue = i_InitialValue;

是完全错误的,因为此时,Semaphorehandle1 未初始化(即,未指向任何有效的内存位置)并尝试取消引用未初始化的指针将导致 undefined behavior,导致分段错误。您需要先分配适当的内存,然后才能真正继续并取消引用该指针。

【讨论】:

  • 即使我使用指针的地址作为输入 semaphoreCreateBinary(&s1vPtr,0);我仍然遇到同样的问题。
猜你喜欢
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-04
  • 2012-03-28
  • 1970-01-01
  • 2018-05-16
相关资源
最近更新 更多