我在 OS X Mavericks 上使用 Apple LLVM 版本 5.1 (clang-503.0.40) 在 C 中调试“中止陷阱 6”错误时遇到问题。目标是构造一个数据结构word2class
其中包含 num_words
词汇表中的每个单词words 该单词所属的类 ID 数组(任意,但例如:名词、动词、...,作为整数 ID)及其倒数,class2word
其中包含每个类 0 <= class < num_class
它包含的单词数组。
为此,我维护了指向 long long 数组的全局指针数组。前向数据结构(word2class
)和后向数据结构(class2words
)的构造方式相同,暂且称之为A。 A 和每个元素 A[i] 指向的每个数组都是动态分配的。在构造时,我们知道 A 可能包含的元素的最大数量( num_words
或 num_class
)。 A 是通过从文件中读取 index,id 对构造的(index
是一个词 ID,id
是一个类 ID)。每个id
应该插入到 A[index]
指向的数组中.属于多个类别的单词存储为每个类别 ID 的单独行(例如 0<tab>0<newline>0<tab>1
)。在构造期间,我维护一个数组,每个数组的当前最大大小 A_max_size[i]
, 以及每个数组中的当前元素数 A_cur_size[i]
, 如果每个 *A[i] 变得太小则懒惰地 realloc() 。每当 A[i] 变得太小时,我都会通过因子 2 调整其大小来摊销内存分配成本。以下是代码的实际相关部分:
#include <stdio.h>
#include <stdlib.h>
// global arrays of pointers to long longs
long long **word2class = NULL, **class2word = NULL;
// bounds for each array pointed to by word2class[i] / class2word[j]
long long *w2c_cur_size = NULL, *c2w_cur_size = NULL;
// max number of words, passed as first argument argv[1]
// max number of classes, read from file
long long num_words, num_classes = 0;
void AllocateAndInsert(long long **A, long long *A_cur_size, long long *A_max_size,
long long index, long long item) {
if (A == NULL || A_cur_size == NULL || A_max_size == NULL) {
printf("NULL pointer passed.\n"); exit(1);
}
// Check if A[index] is big enough, realloc if needed
if (A_cur_size[index] + 1 >= A_max_size[index]) {
if (A_max_size[index] == 0) A_max_size[index] = 1;
else A_max_size[index] *= 2; // amortize memory allocation
// dynamically allocate a large enough array of long longs
A[index] = (long long*)realloc(A[index], A_max_size[index] * sizeof(long long));
if (A[index] == NULL) {
printf("(Re)allocation error.\n");
exit(1);
}
}
// insert item at end of array pointed to by A[index]
A[index][A_cur_size[index]] = item;
A_cur_size[index]++;
}
void PrintDS(long long **A, long long max_index, long long *A_size) {
int i, j;
for (i = 0; i < max_index; i++) {
printf("Index %d:\n", i);
for (int j = 0; j < A_size[i]; j++) {
printf("%lld ", A[i][j]);
}
printf("\n");
}
}
void BuildDataStruct(char *fname) {
FILE *fin = fopen(fname, "r");
long long index, id;
long long *w2c_max_size, *c2w_max_size; // temp variables used during construction
if (fin == NULL) {
printf("Error opening file.\n");
exit(1);
}
// read max number of classes as first line from file
if (fscanf(fin, "%lld\n", &num_classes) != 1) {
printf("File format error.\n");
exit(1);
}
// word2class
w2c_max_size = calloc(num_words, sizeof(long long)); // initialized to 0s
w2c_cur_size = calloc(num_words, sizeof(long long));
word2class = calloc(num_words, sizeof(long long *));
// class2word
c2w_max_size = calloc(num_classes, sizeof(long long));
c2w_cur_size = calloc(num_classes, sizeof(long long));
class2word = calloc(num_classes, sizeof(long long *));
if (w2c_max_size == NULL || w2c_cur_size == NULL || word2class == NULL ||
c2w_max_size == NULL || c2w_cur_size == NULL || class2word == NULL) {
printf("Allocation error.\n");
exit(1);
}
while (!feof(fin)) {
if (fscanf(fin, "%lld\t%lld\n", &index, &id) != 2) {
printf("Format error.\n");
exit(1);
}
if (index < 0 || index >= num_words || id < 0 || id >= num_classes) {
printf("Bounds error.\n");
exit(1);
}
AllocateAndInsert(word2class, w2c_cur_size, w2c_max_size, index, id);
AllocateAndInsert(class2word, c2w_cur_size, c2w_max_size, id, index);
}
fclose(fin);
free(w2c_max_size);
free(c2w_max_size);
// DATA STRUCTURE PRINTS FINE HERE
PrintDS(word2class, num_words, w2c_cur_size);
PrintDS(class2word, num_classes, c2w_cur_size);
}
int main(int argc, char *argv[]) {
if (argc <= 2) {
printf("Usage: %s num_words word2class_file\n", argv[0]);
exit(1);
}
num_words = atoi(argv[1]);
BuildDataStruct(argv[2]);
// <-- 'Abort Trap 6' RAISED HERE
return 0;
}
对于那些感兴趣的人,可以使用以下脚本生成测试数据 python script.py num_words max_class_id max_class_per_word out_file
并使用上述 C 代码作为 ./build_ds num_words out_file
使用:
import sys
from random import sample, randint
num_words = int(sys.argv[1])
max_class_id = int(sys.argv[2])
max_class_per_word = int(sys.argv[3])
f = open(sys.argv[4], 'w')
f.write("%d\n" % (max_class_id,))
for w in xrange(num_words):
num_classes = randint(1, max_class_per_word)
classes = sample(xrange(max_class_id), num_classes)
for c in classes:
f.write("%d\t%d\n" % (w, c))
f.close()
此代码有效(即使在“真实”数据上),但是,一旦我将此确切代码用作更大应用程序的一部分,程序就会终止并出现神秘的“Abort trap 6”错误。
BuildDataStruct()
从另一个函数调用,似乎对构造部分工作正常。从 BuildDataStruct()
返回之前可以打印出这两种数据结构没问题。但是,在函数返回后立即生成错误。
通过阅读其他各种答案,Abort Trap: 6
当缓冲区被覆盖时,OS X 上似乎会出现错误。但是,我添加了对 index
的检查确保不会发生这种情况,所以我不确定还有什么问题?我可能会以某种方式覆盖堆栈吗?有没有人知道我可以在哪里或如何开始寻找问题?
最佳答案
您的代码存在一些问题:
它没有编译,因为几个
{
被注释掉了:if (A == NULL) { // handle allocation error }
我假设这只是转录错误。
您不检查
fscanf
的返回值确保读取了两个参数。文件中的任何语法错误都可能导致损坏。您从每一行读取两个字段,
index
和id
,但只使用第一个。第二个被忽略了。此外,您永远不会在cur_size
数组中设置任何值,因此它在您的代码中始终为零。所以,我要作一个假设:
index
是外层数组A
中的索引,id
是一个索引到相应的内部数组中,即您希望能够分配A[index][id]
存在的足够大的数组。根据我的假设,存在一个算法问题:如果
max_size[index]
小于cur_size[index]
,则将其加倍——但是不要认为cur_size[index]
可能是原来的两倍多。您需要将大小加倍并确保它大于id+1
。您应该保留
cur_size
数组,以便稍后检查越界索引。calloc
用零填充内存,但是realloc
使新分配部分的值不确定。在我的平台上,
long long
是 64 位,但calloc
和realloc
接受size_t
第一个参数,所以我看到了几个“从‘__int64’到‘size_t’的转换,可能丢失数据”错误。您应该检查以确保calloc
在您的平台上使用long long
。
因此,问题 1-6 的修复可能如下所示:
long long **A = NULL; // global array of pointers to long longs
long long *A_cur_size_array = NULL;
long long N = 1000; // for exax1mple
// If your platform has a predefined version of "max", use it instead.
static long long max_long_long(long long a, long long b)
{
// If your platform has a predefined version of "max", use it instead.
return (a > b) ? a : b;
}
void construct_A(char *fname)
{
FILE *fin = fopen(fname, "r");
long long index, id;
long long *max_size_array;
A_cur_size_array = calloc(N, sizeof(int));
A = calloc(N, sizeof(long long *));
max_size_array = calloc(N, sizeof(int)); // init to 0
if (A == NULL || max_size_array == NULL || A_cur_size_array == NULL)
{
// handle allocation error
}
while (!feof(fin))
{
if (fscanf(fin, "%lld\t%lld\n", &index, &id) != 2)
{
printf("File format error.\n");
exit(1);
}
if (index < 0 || index >= N)
{
printf("BOUNDS ERROR\n");
exit(1);
}
if (id < 0)
{
printf("BOUNDS ERROR\n");
exit(1);
}
if (id >= A_cur_size_array[index])
{
A_cur_size_array[index] = id + 1;
if (A_cur_size_array[index] >= max_size_array[index])
{
long long new_max_size = max_long_long(id + 1, 2 * max_size_array[index]);
long long i;
// dynamically allocate a large enough array of long longs
A[index] = (long long*)realloc(A[index], new_max_size * sizeof(long long));
if (A[index] == NULL)
{
// handle allocation error
}
for (i = max_size_array[index]; i < new_max_size; i++)
A[index][i] = 0;
max_size_array[index] = new_max_size;
}
}
}
fclose(fin);
free(max_size_array);
}
关于c - 使用动态内存分配在函数返回时中止陷阱 6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26514952/