C语言函数中结构体数组元素访问的二级指针误用问题
二级指针访问结构体数组的常见误区
首先定义了如下结构体:
typedef struct counter_Nval { systs_t N; uint16_t cntr; } countN_t;
为了分配该结构体的数组,我将指向该结构体的二级指针传入函数:
extern size_t __count_shnnr_N(size_t len, my_type_array *arr, countN_t **nNs) { size_t ln = 1; size_t tmp = 1; *nNs = malloc(sizeof(**nNs) * ln--); nNs[ln]->N = arr[ln].N; nNs[ln]->cntr = 1; while (ln++ < len-1) { if (arr[ln].N == (*nNs+tmp-1)->N) { (*nNs+tmp-1)->cntr++; } else { *nNs = realloc(*nNs, sizeof(**nNs) * ++tmp); (*nNs+tmp-1)->N = arr[ln].N; (*nNs+tmp-1)->cntr = 1; } } return tmp; }
实际使用中,当我尝试用nNs[tmp-1]->N替代(*nNs+tmp-1)->N访问结构体数组元素时,出现了Segmentation fault错误,但最初的nNs[ln]->N = arr[ln].N;和nNs[ln]->cntr = 1;却能正常运行。这两种写法难道不是等价的吗?我存在什么误区?
问题本质:混淆二级指针自身的偏移与指向的一级指针的偏移
你混淆了二级指针nNs本身的内存偏移,和它指向的一级指针(结构体数组的首地址)的内存偏移:
nNs是countN_t **类型,也就是指向指针的指针。nNs[x]等价于*(nNs + x),这里的偏移是针对nNs这个二级指针变量所在的内存地址进行的,而不是针对*nNs指向的结构体数组。- 最初的代码能运行是因为
ln--后ln的值是0,nNs[0]等价于*nNs,也就是你用malloc分配的结构体数组的首指针,这时候nNs[0]->N和(*nNs)->N是完全等价的,自然能正常访问。 - 但当
tmp-1不为0时(比如tmp=2时tmp-1=1),nNs[1]会去访问nNs这个二级指针变量内存地址的下一个位置,而这个位置根本不是你分配的结构体数组的指针,属于非法内存访问,直接触发段错误。
正确的等价写法
如果你想用下标语法替代指针偏移,应该先解引用二级指针得到一级指针,再对一级指针用下标:
(*nNs)[tmp-1].N
或者保持原来的指针偏移写法:
(*nNs + tmp-1)->N
这两种才是真正等价的,因为它们都是对*nNs(结构体数组的首指针)进行偏移访问。
内容的提问来源于stack exchange,提问作者opisthofulax
相关产品推荐
相关产品推荐

