在程序结束时检测到堆栈粉碎

Posted

技术标签:

【中文标题】在程序结束时检测到堆栈粉碎【英文标题】:Stack Smashing Detected at End of Program 【发布时间】:2016-01-02 17:25:02 【问题描述】:

我目前正在测试一个较小规模的程序,以在我尝试在 main 函数末尾通过return 0; 退出程序时区分问题。

Main.c

#include <stdio.h>
#include <stdlib.h>
#include "Header.h"

int main (void)

        int i;
        int Fin = 0;


        Student sStu;
        Array aAry;
        Student *Stu = &sStu;
        Array *Ary = &aAry;

        InitArray(Ary, 1);

        while(Fin != 2)
        
                printf("Please choose a selection.\n");
                printf("1. Add Student\n");
                printf("2. Print Students\n");
                printf("3. Exit\n");
                scanf("%d", &i);
                switch(i)
                
                        case 1:
                        
                                AddStudent(Stu, Ary);
                                break;
                        
                        case 2:
                        
                                for(i = 0; i < Ary->Size; i++)
                                
                                        printf("%s %d\n", Stu[i].Name, Stu[i].IDn);
                                
                                break;
                        
                        case 3:
                        
                                return 0;
                        
                
        

头文件.h

#ifndef HEADER_H_
#define HEADER_H_

typedef struct student

        char Name[30];
        int IDn;
Student;

typedef struct array

        Student *Student;
        size_t Used;
        size_t Size;
Array;


void InitArray(Array *Ary, int InitSize);
void AddArray(Array *Ary);
Student AddStudent(Student *Stu, Array *Ary);

#endif

等级.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Header.h"

void InitArray(Array *Ary, int InitSize)

        Ary->Student =  malloc(InitSize * sizeof(Student));
        Ary->Used = 0;
        Ary->Size = InitSize;
        memset(&Ary->Student[0], 0 , sizeof(Student) * InitSize);


void AddArray(Array *Ary)

        Student Stud;
        if(Ary->Used == Ary->Size)
        
                Ary->Size *= 2;
                Ary->Student = realloc(Ary->Student, Ary->Size * sizeof(Student));
        

        strcpy(Ary->Student[Ary->Used].Name, Stud.Name);
        Ary->Student[Ary->Used].IDn = Stud.IDn;

        Ary->Used++;


Student AddStudent(Student *Stu, Array *Ary)

        int i;

        printf("\nStudent ID numbers cannot be the same!\n");
        printf("Please enter the student's name: ");
        scanf("%s", Stu[Ary->Used].Name);
        printf("Please enter the student's ID Number: ");
        scanf("%d", &Stu[Ary->Used].IDn);
        AddArray(Ary);
        printf("\n");
        return;

在文件末尾,当我尝试return 0; 时,我收到此错误:

* 检测到堆栈破坏 *:./a.out 终止 分段错误(核心转储)

当我使用 valgrind 时,我得到这个输出:

==9966== Invalid write of size 1
==9966==    at 0x402C6C3: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9966==    by 0x8048687: AddArray (in /home/ctj0033/CSCE_1040/Homework/2_Homework/2_Test/a.out)
==9966==    by 0x804874B: AddStudent (in /home/ctj0033/CSCE_1040/Homework/2_Homework/2_Test/a.out)
==9966==    by 0x804881C: main (in /home/ctj0033/CSCE_1040/Homework/2_Homework/2_Test/a.out)
==9966==  Address 0x41f804c is 0 bytes after a block of size 36 alloc'd

valgrind 在我尝试退出程序时因致命错误而终止。

它只发生在最后,我可以正确打印结构数组的内容。我已经查看了realloc();,因为我很确定错误就在其中,但是我不确定我到底做错了什么。我试图改变我在InitArray(); 中分配内存的方式以及我使用realloc(); 的方式,但无济于事。

我做错了什么?

【问题讨论】:

Valgrind 说段错误发生在AddArray 中的strcpy。使用-g 编译以显示行号。 好的,谢谢。我要去试试。 我想这是因为这是我过去遇到的任何老师或讲师教我这样做的方式。在我看来,阅读起来会更清楚。 scanf("%s", Stu[Ary-&gt;Used].Name);。看起来您正在将单个(分配的堆栈)Student 传递给Addstudent,但随后将其用作Students 的数组。 Fin in main() 在使用其值时未初始化。未定义的行为。 【参考方案1】:

您的直接问题是您正在尝试使用“无效指针”。 (其实是完全有效的指针,只是指向了错误的地方)

sStuStudentStu 是指向它的指针。但是当你添加你的第二个学生时,你写信给Stu[1]——这是sStu之后的空格。这个空间很可能还有别的东西,所以当你写信给Stu[1]时,你会覆盖别的东西。 (具体什么在那个空间里是不可预测的。)

您似乎想在拥有Stu 的任何地方使用Ary-&gt;Student

(如果这样做,您可能会发现更多问题 - 例如您检查是否需要在写入下一个元素后扩展数组)

【讨论】:

谢谢,这解决了我的问题,正如你所料,导致了更多问题。不过谢谢! @Arrowkill 不是“引起的”,但可能是“暴露的”。 从这个意义上说你是对的,尽管我选择的措辞很糟糕,但这就是我的意思。

以上是关于在程序结束时检测到堆栈粉碎的主要内容,如果未能解决你的问题,请参考以下文章

调用函数后检测到 C 堆栈粉碎

检测到堆栈粉碎 glGetTexImage

gcc 的 -fstack-protector 选项如何防止堆栈粉碎?

为啥粉碎后没有立即出现“检测到堆栈粉碎”?

在函数中操作int的数组时堆栈粉碎错误

“CRT 检测到应用程序在堆缓冲区结束后写入内存”是啥意思?