为什么我的程序在调试时会崩溃?

时间:2015-10-08 10:59:24

标签: c crash structure scanf

我已经开始编写一个程序,用于读取和存储团队信息并将其存储在结构中,重新排序并打印结果。

首先,我正在尝试阅读团队名称并将其存储在结构中的成员中,然后阅读团队成绩并将其存储在其他成员中。

但是,只要我调试文件,它就会崩溃。它甚至没有正确启动。我收到此错误

  

PA2.exe中0xFEFEFEFE处的未处理异常:0xC0000005访问   违规执行地点0xFEFEFEFE。

我已经回溯到足以弄清楚它是在while循环中的某个地方但却无法弄清楚它有什么问题。

我正在使用visual studio 2012,当我构建它时我没有错误。

#include "stdafx.h"
#include "string.h"
#include <stdio.h>

struct team
{
    char name[20];
    int no_games;
    int points;
    int goals_scored;
    int goals_let;
};


int main(void)
{
    FILE *input2a;
    FILE *input2b;
    int error1;
    int error2;
    int i;
    char team1_name[20];
    char team2_name[20];
    int team1_goals;
    int team2_goals;
    struct team teamlist[20];

    error1 = fopen_s(&input2a, "C:\\Users\\New PC\\Desktop\\input2a.dat", "r");

    i = 0;
    while (i < 20)
    {
        i ++;
        fscanf_s(input2a, "%s", teamlist[i].name);
    }

    error2 = fopen_s(&input2b, "C:\\Users\\New PC\\Desktop\\input2b.dat", "r");

    while (fscanf_s(input2b, "%s %d %s %d", team1_name, &team1_goals, team2_name, &team2_goals) !=EOF)
    {
        if (team1_goals < 0)
        {
            printf("Team %s has negative goals - Invalid entry\n", team1_name);
        }

        else if (team2_goals < 0)
        {
            printf("Team %s has negative goals - Invalid entry\n", team2_name);
        }

        else
        {
        }
    }
    return 0;
}

2 个答案:

答案 0 :(得分:5)

从仅查看while循环:你写入内存越界。

struct team teamlist[20];

而在此期间:

i = 0;
while (i < 20)
{
    i ++;
    fscanf_s(input2a, "%s", teamlist[i].name);
}

所以你在i=19时输入while并将其增加到20,这使得它超出了数组的范围。

答案 1 :(得分:3)

问题在这里(见我的评论):

i = 0;
while (i < 20)
{
    i ++; // was 19, become 20, but maximal allowed value is 19
    fscanf_s(input2a, "%s", teamlist[i].name);
}

此问题的名称是ABW(数组边界写入)。这意味着,您的程序在数组外部写入(它发生在i==19时,因此循环i < 20的条件得到满足,但是在它之后你会增加它:i++)。要修复它,你只需要交换这个循环体的两行:

{
    fscanf_s(input2a, "%s", teamlist[i].name);
    i++;
}

更好更简单的是在这里使用for循环:

for (i = 0; i < 20; i++)
    fscanf_s(input2a, "%s", teamlist[i].name);

最后修复:现在仍然可能出现ABW错误。原因很简单:teamlist[i].name的大小为20.因此,如果输入文件包含长行,则程序将在此数组外写入。要解决此问题,您可以通过这种方式扩展"%s(我们在这里&#34; 19&#34;而不是&#34; 20&#34;因为最后一个字符是'\0'):

for (i = 0; i < 20; i++)
    fscanf_s(input2a, "%19s", teamlist[i].name);

关于fscanf_s()还有一件事:这个函数应该返回成功匹配和分配的输入项的数量。因此,在第二个循环中,最好检查它是否返回4

<强>更新

如果没有任何反应,请打开documentation

  

与scanf和wscanf不同,scanf_s和wscanf_s需要缓冲区大小   要为c,C,s,S或string类型的所有输入参数指定   包含在[]中的控件集。缓冲区大小以字符为单位   在指针指向后立即作为附加参数传递   缓冲区或变量。例如,如果您正在读取字符串,则   该字符串的缓冲区大小传递如下:

     

char s[10];

     

scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9

所以在你的情况下,第一个循环应该以这种方式纠正:

for (i = 0; i < 20; i++)
    fscanf_s(input2a, "%19s", teamlist[i].name, _countof(teamlist[i].name));

你需要在第二个循环中为fscanf_s的下一次调用提供相同的修复,因为该调用中有两个"%s"