【问题标题】:100% of array correct in function, 75% of array correct in CALLING function - C100% 的数组在函数中正确,75% 的数组在 CALLING 函数中正确 - C
【发布时间】:2013-04-25 17:28:05
【问题描述】:

注意:我使用的是 c++ 编译器,因此我可以使用按引用传递

我有一个奇怪的问题,我真的不知道发生了什么。

基本上,我有一个文本文件:http://pastebin.com/mCp6K3HB 我正在将文本文件的内容读入一个原子数组:

typedef struct{
    char * name;
    char * symbol;
    int atomic_number;
    double atomic_weight;
    int electrons;
    int neutrons;
    int protons;
} atom;

这是我对 atom 的类型定义。

void set_up_temp(atom (&element_record)[DIM1])
{
    char temp_array[826][20];
    char temp2[128][20];
    int i=0;
    int j=0;
    int ctr=0;

    FILE *f=fopen("atoms.txt","r");

    for (i = 0; f && !feof(f) && i < 827; i++ ) 
    {
        fgets(temp_array[i],sizeof(temp_array[0]),f);
    }

    for (j = 0; j < 128; j++)
    {
        element_record[j].name = temp_array[ctr];
        element_record[j].symbol = temp_array[ctr+1];
        element_record[j].atomic_number = atol(temp_array[ctr+2]);
        element_record[j].atomic_weight = atol(temp_array[ctr+3]);
        element_record[j].electrons = atol(temp_array[ctr+4]);
        element_record[j].neutrons = atol(temp_array[ctr+5]);
        element_record[j].protons = atol(temp_array[ctr+6]);
        ctr = ctr + 7;
    }

    //Close the file to free up memory and prevent leaks
    fclose(f);
} //AT THIS POINT THE DATA IS FINE

这是我用来读取数据的函数。当我调试这个函数并让它运行到最后时,我使用调试器检查它的内容,并且数组有 100% 正确的数据,也就是说,所有元素都是它们应该与文本文件相关的内容。 http://i.imgur.com/SEq9w7Q.png 这张图片显示了我在说什么。在左边,所有元素,从 0 到 127,都是完美的。 然后,我进入调用它的函数。

atom myAtoms[118];
set_up_temp(myAtoms); //AT THIS POINT DATA IS FINE
region current_button_pressed; // NOW IT'S BROKEN
load_font_named("arial", "cour.ttf", 20); 
panel p1 = load_panel("atomicpanel.txt");   
panel p2 = load_panel("NumberPanel.txt");

只要调用任何东西,在我调用set_up_temp 之后,我的数组的元素 103 到 127 就会变成乱码。随着越来越多的事情被调用,更多的数组变成了乱码。这很奇怪,我不知道发生了什么......有人知道吗?谢谢。

【问题讨论】:

  • void set_up_temp(atom (&amp;element_record)[DIM1]) 无效 C:&amp; 在那里是非法的。
  • @pmg 抱歉,我可能应该补充说我正在使用 c++ 编译器。我在 OP 顶部添加了一个注释
  • feof 可能不像你想象的那样工作。
  • @CarlNorum 或者,就此而言,fgets

标签: c++ c arrays struct output


【解决方案1】:
for (j = 0; j < 128; j++)
{
    element_record[j].name = temp_array[ctr];

您正在存储然后返回指向堆栈上的temp_array 的指针。从函数返回的那一刻,temp_arrayall 变得无效——在该点之后取消引用任何这些指针是未定义的行为。正如您所说,“未定义的行为”包括您仍然可以毫无问题地读取元素 0 到 102,但 103 到 127 变成乱码的可能性。您需要为这些与atom 对象一样长的字符串分配空间。由于您说您使用的是 C++,因此最简单的解决方法是将两个 char * 成员更改为 std::string。 (如果你不想使用std::string,第二个最简单的解决方法是使用strdup,但是你必须明确地free那个内存。)

这可能不是此代码中唯一的错误,但它可能是导致您立即出现问题的错误。

如果您很好奇,数据的高端被破坏的原因是在大多数(但不是所有)计算机上,包括您正在使用的计算机,堆栈都会增长向下,即从高地址到低地址。然而,数组总是从低地址索引到高地址。所以过去temp_array的内存区域的高端是调用者中最接近堆栈指针的部分,因此最有可能被后续函数调用覆盖。

【讨论】:

  • 非常感谢zack,我使用了strdup方法,因为即使我使用的是c++编译器,我正在做的课程与C有关;我们只使用 C++ 编译器来允许通过引用传递(因为我们首先学习了 pascal,它允许它)。这是 strdup 的正确用法吗? ` element_record[j].name = strdup(temp_array[ctr]);` element_record[j].symbol = strdup(temp_array[ctr+1]); 这可以防止数据损坏,但我只是想确保它的使用正确:)
  • 是的,strdup 用法是正确的。请告诉你的导师,互联网上的人认为他或她的教学方法是错误的——要么教正确的 C++,要么教正确的 C,不要教带有随​​机 C++ 特性的 C 的某些子集。
【解决方案2】:

随意检查会得出这样的结论:

char temp_array[826][20];

...

for (i = 0; f && !feof(f) && i < 827; i++ )

您的代码可能允许i 变为826。这意味着您正在访问 temp_array 的第 827 个元素。这是一个过去的结束。哎呀。

此外,您正在分配一个包含 118 个原子 (atom myAtoms[118];) 的数组,但您在 for (j = 0; j &lt; 128; j++) 循环中将其中的 128 个设置在 set_up_temp 内。

这个故事的寓意:注意你的索引,因为你使用 C++,所以利用 std::vectorstd::string 之类的东西,避免直接使用数组。

更新 正如 Zack 指出的那样,您正在返回指向堆栈分配变量的指针,这些指针将在 set_up_temp 函数返回时消失。此外,您使用的 fgets 并没有按照您的想法进行操作,而且它的开头是 HORRIBLE 代码。请阅读fgets 的文档并问问自己您的代码是做什么的。

【讨论】:

  • 感谢您指出我的索引问题。出于某种原因,我似乎一直在用我的很多代码来解决这个问题。我真的需要更多地关注他们。
  • 另外,我最初使用的是(!feof(f)),但根据我的问题:stackoverflow.com/questions/16196965/… 它已被我接受的答案的海报更改为:"Note that in the solution I proposed, I added a test for the row exceeding DIM1 -- that prevents the condition of trying to read an extra block from occurring." 但是,我会继续阅读fgets 并感谢您指出。
  • @Anteara 拥有一个只有 one 元素的文件可能会有所帮助,并创建一个读取该元素并填充 one 原子结构的函数,然后您可以显示(或在调试器中查看)以验​​证它是否被正确读回。
  • 我重写了我的代码,你说的那部分是坏代码。我没有使用string::getline 的选项,因为我不允许使用字符串。这就是我想出的:while (fscanf(f, "%s", temp_array[i]) != EOF) 在里面我做i++;。我无法让 fscanf 使用 for 循环。不过,这是更好的代码,还是仍然很糟糕?
【解决方案3】:

您正在为一个包含 118 个元素的空间分配一个数组,但代码设置了 128 个元素,因此会覆盖数组之后发生的任何内容。

正如其他人所说,您在数组中存储指向函数临时数据的指针(禁止)。

我的建议是在编程之前先阅读a good book 关于 C++ 的内容,否则你会无缘无故地让你的生活变得更艰难。 C++ 不是一门可以通过实验取得重大进展的语言。

【讨论】:

  • 您好,感谢您的建议。我似乎在保持索引一致方面存在问题。
  • @Anteara:不能通过实验来学习 C++ 的原因是错误通常会受到未定义行为的惩罚,而不是运行时错误。此外,在某些地方,由于历史原因,该语言有些“不合逻辑”,因此有时猜测不会带您走上正确的道路。学习 C++ 的唯一明智方法是阅读好书。
  • 谢谢,我错误地认为通过引用传递它意味着调用者会“记住”所有内容。另外,我现在正在攻读计算机科学学士学位,但我们一直在学习帕斯卡,一两周后我们将开始 C。我可能会投资你建议的书,因为我确实计划这样做C 之后的 C++。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-22
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多