简体   繁体   English

C 字符数组在传递到 function 后损坏

[英]C char array getting corrupted after being passed into function

I'm trying to implement a program similar to 20 Questions, in which a text file of the questions and guesses for answers are loaded, copied into a char array (where the new space lines are replaced by '/0' in order to split the questions into individual strings).我正在尝试实现一个类似于 20 个问题的程序,其中加载了问题和答案猜测的文本文件,复制到 char 数组中(其中新的空格行被替换为 '/0' 以便拆分问题到单独的字符串)。 The array works fine after the text file is copied into it.将文本文件复制到数组后,该数组工作正常。 A tree structure is set up to organize the phrases into the yes/no question tree, where the left child is the yes response, while the right is the no response, and leaves are the guesses that the program uses to guess at the end.设置树结构将短语组织成是/否问题树,其中左边的孩子是回答是,而右边是回答不是,叶子是程序最后用来猜测的猜测。

The issue that I'm having is that after I build the tree (call treeBuilder from InitTree), the contents of the array where the phrases from the text file were copied became corrupted.我遇到的问题是,在构建树(从 InitTree 调用 treeBuilder)之后,复制文本文件中的短语的数组内容已损坏。

Before I call InitTree, the array contents look like this:在调用 InitTree 之前,数组内容如下所示:

Is it furry?是毛茸茸的吗? Does it meow?它喵喵叫吗? a cat a dog Does it have tusks? a cat a dog 它有象牙吗? Does it have big ears?它有大耳朵吗? an elephant a rhinoceros an alligator大象 犀牛 鳄鱼

After calling it, it looks like this:调用后,它看起来像这样:

Is it furry?是毛茸茸的吗? -???`?p?a dog Does it have tusks? -???`?p?a dog 它有象牙吗? Does it have big ears?它有大耳朵吗? an elephant a rhinoceros an alligator大象 犀牛 鳄鱼

I've been testing where it stops working, and within treeBuilder, all of the elements of the array are intact, but as soon as the function call to treeBuilder ends, the array becomes corrupted.我一直在测试它停止工作的地方,在 treeBuilder 中,数组的所有元素都完好无损,但是一旦对 treeBuilder 的 function 调用结束,数组就会损坏。 I've tried protecting the memory by using calloc whenever I allocate memory, and even by making the character array static, which worked in a similar situation where this happened.每当我分配 memory 时,我都尝试通过使用 calloc 来保护 memory,甚至通过创建字符数组 static,这在发生这种情况的类似情况下也有效。 But all of my preventative measures don't seem to be working and I'm not sure where the problem lies.但我所有的预防措施似乎都没有奏效,我不确定问题出在哪里。 I've already tried looking at similar cases here on stackoverflow but I couldn't anything that related to my issue.我已经尝试在 stackoverflow 上查看类似案例,但我找不到与我的问题相关的任何内容。

This eventually leads to a seg fault, when the program actually starts to use the tree, for obvious reasons.出于显而易见的原因,当程序实际开始使用树时,这最终会导致段错误。

I've tried running gdb, but for whatever reason it won't let me go through line by line, because it cannot find the line information, and just skips everything until it either prompts for input, or gets a memory error or something, so running gdb isn't very helpful here.我试过运行 gdb,但无论出于何种原因,它都不会让我逐行运行 go,因为它找不到行信息,只是跳过所有内容,直到提示输入或出现 memory 错误或其他内容,所以运行 gdb 在这里不是很有帮助。 I'm guessing this might be because the main function is in an included file or something.我猜这可能是因为主要的 function 在包含的文件中或其他东西中。 But that's beside the point.但这不是重点。

Here's the code related to the problem:这是与问题相关的代码:

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;
}

Sorry if this is tl;dr, but I wanted to be as clear as possible on my issue.对不起,如果这是 tl;dr,但我想尽可能清楚地说明我的问题。

Just one thing I noticed is that you're using sizeof(TreeType) , but TreeType is a pointer to a struct and not the struct itself.我注意到的一件事是您正在使用sizeof(TreeType) ,但TreeType是指向结构的指针而不是结构本身。 This means that you are creating a pointer that is pointing to nowhere, and that dereferencing the pointer will lead to undefined behaviour.这意味着您正在创建一个指向任何地方的指针,并且取消引用该指针将导致未定义的行为。 Which having just read the rest of the question would certainly explain the segfaults.刚刚阅读问题的 rest 肯定会解释段错误。

I think you would be better off not typedef-ing your struct as a pointer, and be more explicit with your use of pointers.我认为你最好不要将你的结构类型定义为指针,并且更明确地使用指针。

eg.例如。

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;
    }
    ...
}

Here's a question about typedef-ing pointers.这是一个关于typedef-ing 指针的问题。 Seems to be relatively common in C, and used to imply that the data type is opaque and should not be dereferenced by the user (only by the API calls that the user passes it to).似乎在 C 中比较常见,用来暗示数据类型是不透明的,不应该被用户取消引用(只能由用户传递给它的 API 调用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM