繁体   English   中英

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

[英]C segmentation fault when using pointer to pointers to struct

我定义了一个结构StructA和函数StructA createStructA(...) ,该函数创建并返回一个新的StructA 我想要一个函数foo() ,该函数将显式返回int错误代码以及我想在foo()之外使用的新StructA 所以看来我需要指向的指针:

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而中断

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

#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 = malloc(sizeof(A)); // crashes with segfault here *ppa = malloc(sizeof(A)); // crashes with segfault here ,ppa尚不是有效的指针,您不能通过* ppa对其取消引用。 需要做ppa = (A**)malloc(sizeof(A*)); 第一。

实际上,我在这里猜测,这是您想要的:



    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问题 ,请参阅: 什么是XY问题?

就是说,在两行之间进行读取,并使ppamain可用,您的parseB必须以某种方式返回值。 您可以通过将type更改为A *parseB (B **ppb)

此外,在将ppappb声明为指针还是将指针声明为type时 ,您似乎有些困惑。 进行初始化和使用后,似乎需要一个指向 ppappb指针 然后,您将每个地址传递给函数parseBparseA并相应地取消引用,以为其内容分配存储空间。 这样做,您可以制作类似于以下内容的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;
}

注意: realloc用于分配,因为您无法控制*ppb是否先前已在parseB本身内分配(您确实可以控制从parseB发送给parseA ,因此mallocparseA是可以的)

要开始分配和赋值的菊花链,您的main可以写成类似于:

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;
}

使用/输出示例

$ ./bin/structptrissue
ppa->x: 1
ppa->y: 2

ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3

内存错误检查

在您编写的任何可以动态分配内存的代码中,对于任何分配的内存块,您都有2个责任 :(1) 始终保留指向该内存块起始地址的指针,因此,(2)在没有内存块时可以将其释放需要更长的时间。

必须使用一个内存错误检查程序来确保您不会尝试在分配的内存块的边界之外/之外进行写操作,不要尝试在未初始化的值上读取或基于条件跳转,最后确认您释放所有已分配的内存。

对于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)

始终确认已释放已分配的所有内存,并且没有内存错误。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM