使用指针而不是引用时访问指向结构的指针数组时出现段错误

Got segfault accessing array of pointers to struct when using pointers instead of references

本文关键字:指针 数组 段错误 错误 引用 访问 结构      更新时间:2023-10-16

下面的函数获取指向API_AddParType结构的指针数组的指针,并列出每个数组元素的一些字段。使用(*ppParams)[ii]访问每个元素时,一切都像预期的那样工作:

void ParamsListWrapper::ListParams2(API_AddParType** ppParams)
{
unsigned long ii, nParams;
nParams = BMGetHandleSize( (GSHandle)ppParams ) / sizeof(API_AddParType);
// list params
for ( ii = 0; ii < nParams; ii++ ) {
WriteReport( "Param name = "%s", double = %f", (*ppParams)[ii].name, (*ppParams)[ii].value.real );
}
}

好吧,让我们使用一些引用变量,例如API_AddParType& param

void ParamsListWrapper::ListParams1(API_AddParType** ppParams)
{
unsigned long ii, nParams;
nParams = BMGetHandleSize( (GSHandle)ppParams ) / sizeof(API_AddParType);
// list params
for ( ii = 0; ii < nParams; ii++ ) {
API_AddParType& param = (*ppParams)[ii];
WriteReport( "Param name = "%s", double = %f", param.name, param.value.real );
}
}

现在尝试使用指向API_AddParType的指针相同的代码:

void ParamsListWrapper::ListParams3(API_AddParType** ppParams)
{
unsigned long ii, nParams;
nParams = BMGetHandleSize( (GSHandle)ppParams ) / sizeof(API_AddParType);
// list params
for ( ii = 0; ii < nParams; ii++ ) {
API_AddParType* pParam = ppParams[ii];
if (pParam != NULL) {
WriteReport( "Param name = "%s", double = %f", pParam->name, pParam->value.real );
} else {
WriteReport( "Param is NULL" );
}
}
}

出现分段错误。怎么可能?为什么在引用工作没有任何问题时通过指针访问数据时会失败?

下面的函数将指针指向指向API_AddParType结构的指针数组

void ParamsListWrapper::ListParams2(API_AddParType** ppParams)

函数的参数是一个指向指针到API_AddParType的指针,它可以是指向API_AddParType指针数组的第一个元素的指针,

ppParams
|
v
pParam0|pParam1|pParam2|...
|       |       |    ...
v       v       v
xyz     abc     mno   ...

或者它可以是指向(指向API_AddParType数组的第一个元素的指针),

ppParams
|
v
pParams
|
v
param0|param1|param2|...

我在哪里命名了指向pParams的匿名内存位置ppParams(指向参数的指针),函数接收指向pParams而不是pParams本身的指针的原因可能是指针pParams本身可能会被函数更改。

现在,在第一种情况下,(*ppParams)[ii] = pParam0[ii] = the object ii units after the start of xyz,所以你永远不会看pParam1pParam2等指向什么(除非这些指针被设置为指向数组内部,pParam1指向第一个元素)。

在第二种情况下,(*ppParams)[ii] = pParams[ii] = the object ii units after the start of param0,然后依次查看所有排列整齐的paramN。看起来不错。

API_AddParType* pParam = ppParams[ii]

在第一种情况下,你会看xyzabcmno、...按顺序,这看起来不错。

但是在第二种情况下,pParam将成为pParams之后的指针ii单位,但这不是指向大小大于 1 的指针数组中的第一个元素API_AddParType,因此访问ppParams[ii]对于ii > 0来说是未定义的行为,并且由于不太可能碰巧有有效的指针指向API_AddParType就在pParams后面, 访问pParam->namepParam->value.real可能会导致段错误。

事实上,你得到了一个分割错误ppParams[ii],而不是(*ppParams)[ii],这强烈暗示这种情况实际上是第二种,而不是第一种。

尝试将API_AddParType* pParam = ppParams[ii];更改为API_AddParType* pParam = *ppParams;并访问pParam->name,如下所示pParam[ii].name

通过访问(*ppParams)[ii]您正在操纵单个API_AddParType,但访问pParam[ii]您正在操作一系列API_AddParType

尝试更改行

API_AddParType* pParam = ppParams[ii];

API_AddParType* pParam = (*ppParams) + ii;

在最后一种情况下,您将ppParams视为指针数组,而不是指向数组的指针。

数组的ii:th 元素在指针大小写和其他情况下都(*ppParams)[ii]
您正在寻找它的地址,即

API_AddParType* pParam = &(*ppParams)[ii];

API_AddParType* pParam = (*ppParams) + ii;