C语言聚类初始化函数出现SIGSEGV内存访问错误求助
排查k聚类初始化函数中的SIGSEGV错误
问题描述
编写基于点间距离选择初始中心的k聚类初始化函数时,执行*p_discard_set[i] = id;触发interrupted by signal 11: SIGSEGV错误,而*p_discard_set[0] = i;能正常执行,且k>2,确认数组无越界情况,需要排查错误原因。
相关代码
初始化函数代码
int *inizialize_centroids(int *p_dataset, int d, int k, int **p_discard_set) { int* centroids = (int*) malloc(k*((2*d)+1)*sizeof(int)), *point_to_compare = (int*) malloc(d*sizeof(int)), *cluster_point = (int*) malloc(d*sizeof(int)); float* distance = (float*) malloc(2*k*sizeof(float)); if(centroids == NULL || point_to_compare == NULL || cluster_point == NULL || distance == NULL){ printf("Something went wrong in inizialize_centroids(), memory allocation failed! (row 94/95)"); exit(1); } centroids[0]=1; for(int i = 1; i < d; i++){ centroids[i] = p_dataset[i]; centroids[i+d] = pow(p_dataset[i],2); } *p_discard_set[0] = 1; *p_discard_set[1] = p_dataset[0]; memcpy(cluster_point, &p_dataset[0], (d + 1)*sizeof(int)); int j; int i = 1; int t; while (i < k){ j = 0; while(j < 2*CHUNK ){ memcpy(point_to_compare, &p_dataset[j/2 * (d + 1)], (d + 1) * sizeof(int)); distance[j] = (float) point_to_compare[0]; j++; distance[j] = compare(cluster_point, point_to_compare, i, d); j++; } int id = (int) distance[0]; float max = distance[1]; j = 0; while (j < 2* CHUNK){ if(distance[j+1] > max){ max = distance[j+1]; id = distance[j]; } j+=2; } i++; *p_discard_set[0] = i; *p_discard_set[i] = id; // 触发错误的行 [....] } return centroids; }
main函数调用代码
int *discard_set = (int*) malloc((k + 1) * sizeof(int)), *compressed_set = (int*) malloc(sizeof(int)), *retained_set = (int*) malloc(sizeof(int)); // discard_set 结构: [n, id_1, ... , id_n] if(discard_set == NULL || compressed_set == NULL || retained_set == NULL){ printf("Something went wrong in main(), memory allocation failed! (row 39)"); exit(1); } int* centroids = inizialize_centroids(dataset, d, k, &discard_set);
错误原因
核心问题是运算符优先级:数组下标运算符[]的优先级高于解引用运算符*。
*p_discard_set[i]实际等价于*(p_discard_set[i]):先取p_discard_set的第i个元素(但p_discard_set是指向单个指针的指针,仅p_discard_set[0]有效),再解引用这个不存在的指针,直接导致内存访问越界,触发SIGSEGV。- 而
*p_discard_set[0]能运行是巧合:它等价于*(p_discard_set[0]),也就是discard_set[0],刚好访问的是合法内存,但这种写法本身是错误的,存在隐藏风险。
修复方案
将所有涉及*p_discard_set的下标访问改为先解引用指针,再访问数组下标,即用(*p_discard_set)[index]替代*p_discard_set[index]:
修改后的关键代码:
// 初始化部分 (*p_discard_set)[0] = 1; (*p_discard_set)[1] = p_dataset[0]; // 循环内赋值部分 (*p_discard_set)[0] = i; (*p_discard_set)[i] = id;
这样先通过(*p_discard_set)得到main函数中分配的discard_set数组指针,再访问其下标,就能保证内存访问合法,解决段错误问题。
内容的提问来源于stack exchange,提问作者Luca Lotifi
相关产品推荐
相关产品推荐

