为什么全局变量在不同方法中表现不同?

时间:2015-06-29 10:44:15

标签: c arrays string variables segmentation-fault

目标:

  1. 制作字符串(字典)的全局数组,因为只能在函数load()中计算大小。
  2. 使用功能print()在屏幕上打印字典。
  3. 我的方法:

    创建指向字符串的全局指针,在load()中创建字符串数组,并将本地数组指定给全局指针。

    问题:

    如果我尝试在load()内打印全局数组(以及本地数组),一切都很好,但是如果使用print()进行打印,则会在数组末尾的某处发生段错误。 GDB和valgrind输出对我来说似乎很神秘。我放弃。怎么了?

    来源和字典是here

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    // length of the longest word in dictionary
    #define LENGTH 45
    // dictionary file
    #define DICTIONARY "large"
    
    // prototypes
    void load(const char* dictionary);
    void print(void);
    
    // global dictionary size
    int dict_size = 0;
    // global dictionary
    char **global_dict;
    
    int main(void)
    {
        load(DICTIONARY);
        print();
        return 0;  
    }
    
    /**
     * Loads dictionary into memory.
     */
    void load(const char* dictionary)
    {
        // open dictionary file
        FILE *dict_file = fopen(dictionary, "r");    
    
        // compute size of dictionary
        for (int c = fgetc(dict_file); c != EOF; c = fgetc(dict_file))
        {
            // look for '\n' (one '\n' means one word)
            if (c == '\n')
            {
                dict_size++;
            }
        }
    
        // return to beginning of file
        fseek(dict_file, 0, SEEK_SET);
    
        // local array
        char *dict[dict_size];
    
        // variables for reading
        int word_length = 0;
        int dict_index = 0;
        char word[LENGTH + 1];   
    
        // iteration over characters
        for (int c = fgetc(dict_file); c != EOF; c = fgetc(dict_file))
        {
            // allow only letters
            if (c != '\n')
            {
                // append character to word
                word[word_length] = c;
                word_length++;
            }
            // if c = \n and some letters're already in the word
            else if (word_length > 0)
            {
                // terminate current word
                word[word_length] = '\0';
    
                //write word to local dictionary
                dict[dict_index] = malloc(word_length + 1);
                strcpy(dict[dict_index], word);
                dict_index++;
    
                // prepare for next word
                word_length = 0;
            }
        }
    
        // make local dictioinary global
        global_dict = dict;
    }
    
    /**
     * Prints dictionary.
     */
    void print(void)
    {
        for (int i = 0; i < dict_size; i++)
            printf("%s %p\n", global_dict[i], global_dict[i]);
    }
    

3 个答案:

答案 0 :(得分:6)

答案很简单,您将指针指向load()的本地变量,并在load()返回时将其解除分配,因此它在{{1}中无效导致未定义的行为。

你甚至评论过它

print()

您有两种选择:

  1. 不要使用全局变量,与全局变量一起使用的模式没有任何好处,相反,它非常危险。您可以从函数// local array <-- this is your comment not mine char *dict[dict_size]; 返回动态分配的poitner,然后将其传递给load()

  2. 使用print()分配指针数组。

    malloc()
  3. 为什么我不喜欢全局变量?

    • 因为你可以在你的程序中完成你所做的事情,甚至没有收到编译器发出的警告。

    但是,当然,当你获得经验时,你不会做这种事情,所以它更多是你的错,而不是全局变量,但看到仍在学习的程序员是很常见的,使用全局变量来解决函数之间共享数据的问题,这就是参数的用途。

    所以使用全局变量+不知道如何正确处理它们是不好的,而是学习函数参数,你将解决所有需要全局变量通过程序中的不同函数传递数据而不使用全局变量的问题。

    这是你自己的代码,我删除了global_dict = malloc(dict_size * sizeof(*global_dict)); 变量,并在global_dict中使用了动态内存分配,我也对load()执行了一些错误检查,你应该改进那部分你希望代码是健壮的,其余的是自我解释

    malloc()

答案 1 :(得分:1)

LibGit2Sharp.0.21.0.176中,您创建并填充局部变量NuGet,然后只将指针load()指定给该变量。但是只要char *dict[dict_size];返回,就不能再访问任何局部变量了。 那个问题stealing the hotel keys,因为它在答案中得到了很好的解释

答案 2 :(得分:0)

问题解释(灵感来自@Ingo Leonhardt)

问题在这里:

char *dict[dict_size];

通过这样的声明,数组的内存被自动分配(它只能在load()中触及),在load()之后调用dict的内存可以访问覆盖。似乎覆盖发生在程序结束的某个地方(意外)。

解决方案(受@ iharob启发)

char **dict = malloc((1 + dict_size) * sizeof(*dict));

因此,我为dict动态分配内存(在程序结束或free(global_dict)之前不可触及)

P.S。 我同意全局变量是危险的,但解决这种设计的问题是分配的约束。