【问题标题】:Having a fatal error code - corrupted heap有一个致命的错误代码 - 损坏的堆
【发布时间】:2019-08-23 05:14:35
【问题描述】:

来自外部编译器的新图片..退出代码正常吗?

enter image description here

这是完整的代码。在将想要的输出打印到屏幕后,我遇到了一个故障程序。我想这是我为结构数组分配内存的方式以及 for 循环中每个结构的 .name 字段的问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

#define MAX_NAME_LEN 50

typedef struct stud
{
char *name;
int marks[4];
float avg;
}student;


student* Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void printExcellent(student*);

void main()
{
int size, i;
student *arr, *newArr;
printf("\nEnter the number of students: ");
scanf_s("%d", &size);
newArr = Create_Class(&size);
for (i = 0; i < size; i++)
{
    printExcellent(newArr+i);
}
for (i=0;i<size;i++) free(newArr[i].name);
free(newArr);
_getch();
}

student* Create_Class(int size)
{
student *p;
char str[MAX_NAME_LEN];
int i, j;
p = (student*)calloc(size , sizeof(student));
if (!p)
{
    printf("Memory allocation failure.");
    exit(1);
}

for (i = 0; i < size; i++)
{
    printf("Enter your name: ");
    rewind(stdin);
    gets(str);
    p[i].name = (char*)calloc(strlen(str)+1,sizeof(char));
    if (!(p[i].name))
    {
        printf("Memory allocation error!");
        exit(1);
    }
    strcpy_s(p[i].name,50,str);
    printf("Enter your marks: ");
    for (j = 0; j < 4; j++)
    {
        scanf_s("%d", &p[i].marks[j]);
    }
    Avg_Mark(p + i);
}
return p;
}


void Avg_Mark(student* s)
{
int i, sum=0;
for (i = 0; i < 4; i++)
    sum += s->marks[i];
s->avg = (float)sum / 4;
}


void Print_One(student* s)
{
printf("The average of %s is %.1f\n", s->name, s->avg);
}

void printExcellent(student* s)
{
if ((s->avg) > 85)
    Print_One(s);
}

【问题讨论】:

  • 您错过了发布功能代码。
  • 请贴出你的完整代码,可能str分配不足是罪魁祸首。无论如何gets() 有点邪恶,并且 rewind(stdin) 是一个无操作在最好的情况下
  • student* Create_Class(int);newArr = Create_Class(&amp;size); ???你传递的论点真的正确吗?
  • 经验法则是:首先消除所有警告,然后寻求帮助。
  • 正如我所写:它与您发布的代码不同。您应该可以从某处的菜单中调整设置级别。

标签: c structure dynamic-memory-allocation


【解决方案1】:

我会为你指出我看到的所有可疑之处:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

#define MAX_NAME_LEN 50

typedef struct stud
{
    char *name;
    int marks[4];
    float avg;
}student;


student* Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void printExcellent(student*);

void main()
{
    int size, i;
    student *arr, *newArr;
    printf("\nEnter the number of students: ");
    scanf_s("%d", &size);

    // This is wrong. Remove the &...
    newArr = Create_Class(&size);

    for (i = 0; i < size; i++)
    {
        printExcellent(newArr+i);
    }
    for (i=0;i<size;i++) free(newArr[i].name);
    free(newArr);
    _getch();
}

student* Create_Class(int size)
{
    student *p;
    char str[MAX_NAME_LEN];
    int i, j;

    // Consider checking size for a sane value.

    // Ok, allocate an array of students.
    p = (student*)calloc(size , sizeof(student));
    if (!p)
    {
        printf("Memory allocation failure.");
        exit(1);
    }

    for (i = 0; i < size; i++)
    {
        printf("Enter your name: ");

        // These 2 lines scare the heck out of me.  I'd really do this differently.
        // gets is the devil and the see:
        // https://stackoverflow.com/questions/20052657/reversing-stdin-in-c
        // for why this may not work well.

        rewind(stdin);
        gets(str);

        // What if str is not a terminated string?  Then 1 char of 0?  Guess this is ok.  Hope it doesn't overflow on the copy below though (consider fixed max size and not using a temporary)
        p[i].name = (char*)calloc(strlen(str)+1,sizeof(char));
        if (!(p[i].name))
        {
            printf("Memory allocation error!");
            exit(1);
        }
        // Do a fast copy of up to 50 chars. I'd really want to verify this output to be sure it works. 
        strcpy_s(p[i].name,50,str);
        printf("Enter your marks: ");
        for (j = 0; j < 4; j++)
        {
            // Hope this inputs the way you want.
            scanf_s("%d", &p[i].marks[j]);
        }

        // This should work, but I prefer more explicit pointers.
        Avg_Mark(p + i);
    }

    return p;
}


void Avg_Mark(student* s)
{
    // What if s is Null?

    int i, sum=0;

    // 4 is a magic number.  Make this a constant.
    for (i = 0; i < 4; i++)
        sum += s->marks[i];

    // This won't be as accurate as you want.  Consider an integer solution.
    s->avg = (float)sum / 4;
}


void Print_One(student* s)
{
    // What if s is Null?  What about s->name?
    printf("The average of %s is %.1f\n", s->name, s->avg);
}

void printExcellent(student* s)
{
    // What if s is Null?
    if ((s->avg) > 85)
        Print_One(s);
}

注意:在浏览这段代码时,我没有看到任何“危险信号”,除了大小上的 & 可能还有获取/倒带调用。我仍然会向您的函数添加空断言,并使用调试器对其进行检查,以确保一切都如您所愿。老实说,这里发生了很多事情,我更喜欢调试器的帮助,而不是我在编写 cmets 时快速跟踪代码。


更新

如果我将您的所有 scanf_s 调用更改为 scanf() 调用,请将您的 gets() / rewind() 调用替换为简单的 scanf("%s", str) 调用,并将您时髦的 strcpy_s() 函数更改为更简单的 strcpy()strncpy() 调用,你的程序对我来说似乎没有崩溃。我的钱是strcpy_s() 调用在进行“快速”复制时会损坏 RAM。

【讨论】:

  • 非常感谢您为我实际分析代码。如果你愿意,有几个问题: 1.为什么平均值不准确? 2.更多“显式”指针是什么意思?而不是发送 p+i 发送 &p[i]??最后一个问题, 3. 没有 rewind(stdin) 程序打印 enter name : 并标记用户没有机会将他的名字输入缓冲区。感谢所有的帮助!
  • 1.此处的浮点值可能会显示 1.2499994787 而不是平均值的 1.25。不过有些事以后再说。 2. 是的,类似的。我怀疑这就是问题所在,但我个人能够比添加更容易阅读&amp;newArr[i] - 虽然这是一种偏好。 3.这听起来像你以前的scanf上次没有从stdin获得所有输入?我像瘟疫一样避免scanf,并会在这里问其他人如何解决这个问题。
  • 最后,用 -Wall 编译它并修复任何剩余的警告,以确保我没有错过任何其他“简单”的东西
  • -Wall -Wextra -pedantic(用于gcc/clang)或/W3(用于VS/cl.exe)编译并修复所有警告。在没有任何警告的情况下编译之前不要接受代码。
猜你喜欢
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
  • 2021-08-10
  • 2011-12-03
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
相关资源
最近更新 更多