我试图实现类似于20个问题的程序,其中加载问题和猜测答案的文本文件,复制到char数组中(其中新的空格行被&#39替换) ; / 0'为了将问题分成单个字符串)。文本文件复制到数组后,数组工作正常。设置树结构以将短语组织到是/否问题树中,其中左子节点是肯定响应,而右侧是无响应,并且叶子是节目在结束时用于猜测的猜测。
我遇到的问题是,在构建树(从InitTree调用treeBuilder)之后,复制文本文件中的短语的数组内容已损坏。
在我调用InitTree之前,数组内容如下所示:
毛茸茸吗?它喵喵吗?一只猫一只狗它有象牙吗?它有大耳朵吗?大象犀牛和鳄鱼
调用之后,它看起来像这样:
毛茸茸吗? - ????? p?狗它有象牙吗?它有大耳朵吗?大象犀牛和鳄鱼
我一直在测试它停止工作的地方,并且在treeBuilder中,数组的所有元素都是完整的,但是一旦对treeBuilder的函数调用结束,数组就会被破坏。每当我分配内存时,我都尝试使用calloc来保护内存,甚至通过使字符数组保持静态,这在类似的情况下也会发生。但是我的所有预防措施似乎都没有起作用,我不确定问题出在哪里。我已经尝试在stackoverflow上查看类似的案例,但我无法解决与我的问题相关的任何问题。
当程序实际开始使用树时,这最终会导致seg错误,原因很明显。
我尝试过运行gdb,但无论出于何种原因,它都不会让我逐行检查,因为它无法找到行信息,只是跳过所有内容,直到它提示输入为止,或者得到内存错误或其他什么,所以运行gdb在这里不是很有帮助。我猜这可能是因为主要功能是在包含的文件或其他东西。但那不是重点。
以下是与问题相关的代码:
struct treeStruct {
char *string;
struct treeStruct *left, *right;
};
typedef struct treeStruct *TreeType;
// Builds a tree
void treeBuilder(TreeType tree, char **phrase, long level){
// Gets the level (number of tabs) of the next phrase
long nextLevel = countTabs(*phrase + strlen(*phrase) + 1);
tree->string = *phrase + level; // Assigns the response pointer to the tree array
// Move the pointer to the next string, since the the strings need to be
// put into the tree in linear order
(*phrase) += strlen(*phrase) + 1;
if (level >= nextLevel){
// Compares the current level with the level of the next string
// to determine if returning up the tree is necessary;
// This should be the answer to a question.
tree->left = NULL;
tree->right = NULL;
return;
}
else{
// Makes sure the left and right pointers of the struct have
// allocated space
tree->left = calloc(1, sizeof(TreeType));
tree->right = calloc(1, sizeof(TreeType));
// Adds the yes and no branches to the tree, recursion will take care
// of adding sub-branches
treeBuilder(tree->left, phrase, level + 1);
treeBuilder(tree->right, phrase, level + 1);
}
return;
}
TreeType InitTree (char *file){
if(file == NULL){
printf("File '%s' does not exist.\n", file);
exit(2);
}
FILE *fp;
fp = fopen(file, "r");
// Create a space in memory for the loaded questions to occupy
static char *phrases;
phrases = (char *)malloc(MAXSTR * MAXNUMQS * sizeof(char));
copyText(fp, phrases);
fclose(fp);
// Create space in memory for the tree structure
TreeType tree;
tree = (TreeType) calloc(1, sizeof(TreeType));
// Create a pointer to a pointer so that treeBuilder can
// change what the first pointer is pointing to, so the strings in
// phrases can be added in order throughout the recursion
static char *phrase_ptr, **phrase_ptr2;
phrase_ptr = &phrases[0];
phrase_ptr2 = &phrase_ptr;
//Build the tree
treeBuilder(tree, phrase_ptr2, 0);
topNode = tree;
return tree;
}
很抱歉,如果这是tl; dr,但我想在我的问题上尽可能清楚。
答案 0 :(得分:3)
我注意到的一件事是你正在使用sizeof(TreeType)
,但TreeType
是指向结构而不是结构本身的指针。这意味着您正在创建指向无处的指针,并且取消引用指针将导致未定义的行为。刚刚阅读完其余问题肯定会解释段错误。
我认为最好不要将你的结构类型化为指针,并且更明确地使用指针。
例如
typedef struct treeStruct TreeType;
void treeBuilder(TreeType *tree, char **phrase, long level){
...
if (!tree->left) {
// calloc returns a pointer to a new bit of memory that has been
// assigned on the heap
TreeType *temp = calloc(1, sizeof(TreeType));
// assignments below not explicitly needed as you're using calloc
temp->string = NULL;
temp->left = NULL;
temp->right = NULL;
tree->left = temp;
}
...
}
这是关于typedefing指针的question。似乎在C中相对常见,并且过去暗示数据类型是不透明的,不应被用户取消引用(仅通过用户将其传递给的API调用)。