使用指向结构指针的指针时出现C分段错误
我已经定义了结构StructA和函数StructA createStructA。。。它创建并返回一个新结构。我希望有一个函数foo,它将显式返回int错误代码,以及一个我希望在foo外部使用的新结构。看来我需要指向指针的指针:使用指向结构指针的指针时出现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.)
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++。