我已经定义了一个结构StructA
和一个函数StructA createStructA(...)
,它创建并返回一个新的StructA
。我希望有一个函数foo()
,它将明确返回int
错误代码以及我想在StructA
之外使用的新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断开
由于上面的代码可能看起来不清楚,这是我的问题的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;
}
答案 0 :(得分:3)
*pA = &a
设置* pA指向函数foo中的局部变量。当函数返回时,局部变量超出范围,因此* pA变为无效。
修改强>
只需阅读您的新代码即可。在这一行*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
}
答案 1 :(得分:2)
除了其他更正之外,如果您在调用函数ppa
中需要main
,则无法将值返回main
。虽然你正在做的事情有运动价值,但你的实际目标不过是明确的。它有点像 XY问题,请参阅:What is the XY problem?。
也就是说,在行之间阅读,并在ppa
中提供main
,您的parseB
必须以某种方式返回一个值。您可以将type
更改为A *parseB (B **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;
}
注意: realloc
用于分配,因为您无法控制先前是否已将*ppb
分配给parseB本身 (您可以控制从parseA
发送到parseB
的内容,以便在malloc
parseA
中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
示例使用/输出
valgrind
内存错误检查
在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
您必须使用内存错误检查程序,以确保您不会尝试在已分配的内存块的范围之外/之外进行写入,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了已分配的所有内存。
对于Linux $ 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)
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。
$('input:not(:checked)').parent().removeClass("radio_checked");
$('input:not(:checked)').removeAttr("checked");
$('input:checked').parent().addClass("radio_checked");
$('input:checked').parent().addClass("selected");
$('input').click(function() {
$('input:not(:checked)').parent().removeClass("radio_checked");
$('input:not(:checked)').parent().removeClass("selected");
$('input:not(:checked)').removeAttr("checked");
$('input:checked').parent().addClass("radio_checked");
$('input:checked').parent().addClass("selected");
});
$('input[type=radio]').hide();
始终确认已释放已分配的所有内存并且没有内存错误。
仔细看看,如果您有其他问题,请告诉我。