Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用指向结构指针的指针时出现C分段错误_C_Pointers_Malloc - Fatal编程技术网

使用指向结构指针的指针时出现C分段错误

使用指向结构指针的指针时出现C分段错误,c,pointers,malloc,C,Pointers,Malloc,我已经定义了结构StructA和函数StructA createStructA。。。它创建并返回一个新结构。我希望有一个函数foo,它将显式返回int错误代码,以及一个我希望在foo外部使用的新结构。看来我需要指向指针的指针: int foo(StructA **pA) { // Allocate some memory: *pA = malloc(sizeof(StructA)); // (Editor's note: don't cast the return of malloc.)

我已经定义了结构StructA和函数StructA createStructA。。。它创建并返回一个新结构。我希望有一个函数foo,它将显式返回int错误代码,以及一个我希望在foo外部使用的新结构。看来我需要指向指针的指针:

int foo(StructA **pA) {
  // Allocate some memory:
  *pA = malloc(sizeof(StructA)); // (Editor's note: don't cast the return of malloc.)

  // check that malloc() didn't error.
  assert(*pA);

  // Fill out a new StructA with createStructA():
  StructA a = createStructA(...);

  // return
  *pA = &a;
  return 0;
}
为什么这段代码存在分段错误?这似乎是由于malloc,就好像我注释掉了除malloc行之外的所有其他行,它仍然以segfault中断

由于上面的代码似乎不清楚,以下是我的问题:

#include <stdio.h>
#include <malloc.h>

typedef struct {
  int x;
  int y;
} A;

typedef struct {
  A a;
  int z;
} B;

A makeA() {
  return (A) {.x = 1, .y = 2};
}

B makeB(A a1) {
  return (B) {.a = a1, .z = 3};
}

void parseA(A **ppa) {
  *ppa = malloc(sizeof(A)); // crashes with segfault here
  **ppa = makeA();
}

void parseB(B **ppb) {
  A **ppa;
  parseA(ppa);
  // todo make B .. but it's already crashing
}

int main() {
  B **ppb;
  parseB(ppb);

  return 0;
}
*pA=&a将*pA设置为指向函数foo中的局部变量。当函数返回时,局部变量超出范围,因此*pA无效

编辑: 只要阅读你的新代码。在该行中,*ppa=mallocsizeofA;//这里的segfault崩溃,ppa不是有效的指针,您不能通过*ppa解除对它的引用。需要进行ppa=A**mallocsizeofA*;首先

事实上,我猜这是你想要的:



    void parseA(A **ppa) {
        *ppa = (A*)malloc(sizeof(A)); 
        // todo make A, e.g. ppa->x = 1;
    }

    void parseB(B **ppb) {
        A *ppa = NULL;
        parseA(&ppa);
        // ppa is a valid point now, you can do, e.g. ppa->y=1;
        // todo make B
    }


除了其他更正之外,如果在调用函数main中需要ppa,则无法将值返回到main。虽然你所做的事情有锻炼的价值,但你的实际目标却一点也不明确。这有点像XY问题,请参阅:

也就是说,要在行之间读取,并使ppa在main中可用,您的parseB必须以某种方式返回一个值。您可以通过将类型更改为A*parseB**ppb来实现

此外,您似乎对是将ppa和ppb声明为指针还是指向类型的指针有点困惑。鉴于您的初始化和使用,您似乎需要一个指向ppa和ppb的指针。然后将每个函数的地址传递给函数parseB和parseA,并相应地取消引用以为其内容分配存储。这样,您可以创建一个类似于以下内容的parseB:

A *parseB (B **ppb)
{
    A *ppa = NULL;
    void *tmp = realloc (*ppb, sizeof **ppb);
    if (!tmp) {
        fprintf (stderr, "error: realloc ppb.\n");
        return NULL;
    }
    *ppb = tmp;

    parseA (&ppa);

    if (ppa)
        **ppb = makeB (*ppa);

    return ppa;
}
int main ()
{
    B *ppb = NULL; 
    A *ppa = parseB (&ppb);

    if (ppa && ppb) {
        printf ("ppa->x: %d\nppa->y: %d\n\n"
                "ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
                ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);

        free (ppa);
        free (ppb);
    }

    return 0;
}
注意:realloc用于分配,因为您无法控制*ppb之前是否已在parseB本身中分配。您可以控制从parseB发送给parseA的内容,因此malloc在parseA中是可以使用的

要启动分配和赋值的菊花链,可以将main编写为类似于:

A *parseB (B **ppb)
{
    A *ppa = NULL;
    void *tmp = realloc (*ppb, sizeof **ppb);
    if (!tmp) {
        fprintf (stderr, "error: realloc ppb.\n");
        return NULL;
    }
    *ppb = tmp;

    parseA (&ppa);

    if (ppa)
        **ppb = makeB (*ppa);

    return ppa;
}
int main ()
{
    B *ppb = NULL; 
    A *ppa = parseB (&ppb);

    if (ppa && ppb) {
        printf ("ppa->x: %d\nppa->y: %d\n\n"
                "ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
                ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);

        free (ppa);
        free (ppb);
    }

    return 0;
}
诚然,我并不清楚你们最终想要实现什么。因此,为了利用您分配的值,声明中的间接指针级别被降低,以了解您试图执行的操作。也就是说,把所有的部分放在一起,你可以做如下类似的事情:

#include <stdio.h>
#include <malloc.h>

typedef struct {
    int x;
    int y;
} A;

typedef struct {
    A a;
    int z;
} B;

A makeA ()
{
    return (A) {.x = 1,.y = 2};
}

B makeB (A a1)
{
    return (B) {.a = a1,.z = 3};
}

void parseA (A **ppa)
{
    *ppa = malloc (sizeof (A));
    **ppa = makeA ();
}

A *parseB (B **ppb)
{
    A *ppa = NULL;
    void *tmp = realloc (*ppb, sizeof **ppb);
    if (!tmp) {
        fprintf (stderr, "error: realloc ppb.\n");
        return NULL;
    }
    *ppb = tmp;

    parseA (&ppa);

    if (ppa)
        **ppb = makeB (*ppa);

    return ppa;
}

int main ()
{
    B *ppb = NULL; 
    A *ppa = parseB (&ppb);

    if (ppa && ppb) {
        printf ("ppa->x: %d\nppa->y: %d\n\n"
                "ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
                ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);

        free (ppa);  /* if you allocate it, it is up to you to free it */
        free (ppb);
    }

    return 0;
}
内存错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有两个责任:1始终保留指向内存块起始地址的指针,以便在不再需要时释放内存块

您必须使用内存错误检查程序,以确保您不会试图写入超出分配的内存块边界的内容,尝试读取未初始化的值或将条件跳转建立在未初始化的值上,最后确认您已释放分配的所有内存

对于Linux,valgrind是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可

$ valgrind ./bin/structptrissue
==19399== Memcheck, a memory error detector
==19399== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19399== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==19399== Command: ./bin/structptrissue
==19399==
ppa->x: 1
ppa->y: 2

ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3
==19399==
==19399== HEAP SUMMARY:
==19399==     in use at exit: 0 bytes in 0 blocks
==19399==   total heap usage: 2 allocs, 2 frees, 20 bytes allocated
==19399==
==19399== All heap blocks were freed -- no leaks are possible
==19399==
==19399== For counts of detected and suppressed errors, rerun with: -v
==19399== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放所有已分配的内存,并且没有内存错误


请仔细检查,如果您还有其他问题,请告诉我。

对不起,我的打字错误-我确实使用sizeof。。。编辑您还编写了pa而不是pa,并且a是本地的。*pa=&a;->**pA=a;什么是爸爸?这是否意味着pA将覆盖指向您刚才分配的内存的指针?如果是这样,StructA a在函数结束时超出了作用域和生命周期,因此指向此函数外部使用的StructA a的指针没有任何用处。如有疑问,请发布MCVE。这不是你的实际代码,这是因为它的打字错误。我想这是一个问题,但还有一些问题,因为我甚至不能正确地调用malloc。。。我稍微修改了一段代码,添加了更清晰、更有效的代码,作为我问题的抽象。@micsza,我刚刚修改了您输入的新代码的答案。请不要强制转换malloc的结果。最好是无用的,最坏的是危险的。昆廷,如果它是C还是C++,那就要看情况了。为什么C++需要MALOC的一个强制转换,而C却不需要呢?嗯,C,这里没有提到C++。