【问题标题】:C char array getting corrupted after being passed into functionC char 数组在传递给函数后被损坏
【发布时间】:2012-04-06 08:13:48
【问题描述】:

我正在尝试实现一个类似于 20 Questions 的程序,其中加载了一个包含问题和猜测答案的文本文件,并将其复制到一个 char 数组中(其中新的空格行被替换为 '/0'为了将问题拆分成单独的字符串)。将文本文件复制到其中后,该数组可以正常工作。建立一个树结构将短语组织成是/否问题树,其中左孩子是是的响应,而右是否响应,而叶子是程序最后用来猜测的猜测。

我遇到的问题是,在我构建树后(从 InitTree 调用 treeBuilder),复制文本文件中的短语的数组的内容被破坏了。

在调用 InitTree 之前,数组内容如下所示:

它是毛茸茸的吗?它喵喵叫吗?猫 狗 它有象牙吗?它有大耳朵吗?一头大象犀牛鳄鱼

调用后是这样的:

它是毛茸茸的吗? -???` ?p ?a dog 它有象牙吗?它有大耳朵吗?一头大象犀牛鳄鱼

我一直在测试它停止工作的位置,在 treeBuilder 中,数组的所有元素都完好无损,但是一旦对 treeBuilder 的函数调用结束,数组就会损坏。我尝试通过在分配内存时使用 calloc 来保护内存,甚至通过使字符数组静态化,这在发生这种情况的类似情况下工作。但我所有的预防措施似乎都不起作用,我不确定问题出在哪里。我已经尝试在 stackoverflow 上查看类似案例,但我无法找到与我的问题相关的任何内容。

这最终会导致段错误,当程序实际开始使用树时,原因很明显。

我尝试过运行 gdb,但无论出于何种原因,它都不允许我逐行遍历,因为它找不到行信息,并且只是跳过所有内容,直到它提示输入或出现内存错误什么的,所以在这里运行 gdb 不是很有帮助。我猜这可能是因为 main 函数在包含的文件中。但这不是重点。

这是与问题相关的代码:

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,但我想尽可能清楚地说明我的问题。

【问题讨论】:

  • 如果您能提供所谓的sscce.org 示例,那就太好了。仍然可以重现您的问题的最小但可编译的代码。这也可以帮助您自己找到错误。
  • 例如在这里,您打开一个文件并使用我们甚至看不到的功能读取它。相反,也许strcpy 是一个字符串常量到phrases
  • 当你递归时,你真的想要level + 1吗?还是你之前计算的nextLevel

标签: c arrays pointers tree char


【解决方案1】:

我注意到的一件事是您使用的是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;
    }
    ...
}

这是关于 typedef 指针的question。似乎在 C 中比较常见,用于暗示数据类型是不透明的,不应由用户取消引用(仅由用户传递给它的 API 调用)。

【讨论】:

  • 我通常会这样做,但我正在做的任务要求 TreeType 是一个指针。
  • @jtcramer:也许这个作业的目的是教你不要把指针隐藏在 typedef 后面?
  • 然后使用sizeof(struct treeType)轻松分配内存。
  • 实际上,这似乎是问题的根源。我将 sizeof(TreeType) 更改为 sizeof(treeStruct) ,它似乎解决了这个问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多