首页 > 解决方案 > 为什么即使没有执行添加代码也会破坏正在工作的东西?

问题描述

功能5:
显示销售历史功能..它只是将最后一个条目显示两次...

功能 1:
“添加图书”功能。在我添加“编辑图书”和“添加销售”功能之前,它实际上工作正常。现在它将一些内容写入文件(“Books.txt”);其他功能都无法识别。早些时候,即当'Edit Book' 和'Add Sales' 没有被编码并且结构Sale 没有被声明时,'Search Book' 可以与'Add Book' 完成的条目一起正常工作。

((当我只编写函数 1 和 2 并进行测试运行时,这是我在 BOOKS.txt 中发现的:{{Mein Kampf ÿu)<èÿX 0@ Ÿ0 :òÿ2 XThe Accidental Prime Minister Ÿ0 :òÿ< ^Quantico ental Prime部长Ÿ0 :òÿ Â你肯定是在开玩笑,费曼先生 X0-ô}}

如果将其粘贴到 Books.txt 中,除“添加”外的所有功能都可以正常工作))

#include <fstream.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
struct Sale {
    char costumer[40], name[40];
    int quant, pric, netprice;
};
class Book {
public:
    char name[40];
    int qty, code, price;
    void Add()
    {
        cout << "\n Enter Name Of New Book\n";
        gets(name);
        cout << "\n Enter book code:";
        cin >> code;
        cout << "\n Enter book price:";
        cin >> price;
        cout << "\n Enter book quantity:";
        cin >> qty;
    }
    void Display()
    {
        cout << "\n Name:";
        puts(name);
        cout << "Code:" << code;
        cout << "\nPrice:" << price;
        cout << "\nQuantity Available:" << qty;
    }
    void Modify();
    Sale Sell(int q)
    {
        Sale sale;
        sale.pric = price;
        qty -= q;
        sale.quant = q;
        sale.netprice = q * price;
        cout << "\n Enter costumer name\n";
        gets(sale.costumer);
        strcpy(sale.name, name);
        return sale;
    }
};
void Book::Modify()
{
    Display();
    char ch = 'n';
    do {
        cout << "\n Enter detail to modify \n";
        cout << "1.NAME\t2.QUANTITY\t3.CODE\t4.PRICE\n";
        int mod;
        cin >> mod;
        switch (mod) {
        case 1:
            cout << "\nEnter new Name\n";
            gets(name);
            break;
        case 2:
            cout << "\nEnter new available quantity\n";
            cin >> qty;
            break;
        case 3:
            cout << "\nEnter changed CODE\n";
            cin >> code;
            break;
        case 4:
            cout << "\nEnter updated PRICE\n";
            cin >> price;
            break;
        }
        Display();
        cout << "\nWant to edit more? (y/n)\n";
        ch = getch();
    } while (ch == 'y' || ch == 'Y');
}
void Print(Sale s)
{
    cout << "\nCostumer Name:\t";
    puts(s.costumer);
    cout << "Book Name:\t";
    puts(s.name);
    cout << "\nQuantity(units):" << s.quant << "\tPrice per pice:" << s.pric << "\n\t Net Sale:" << s.netprice;
}
void MScreen()
{
    clrscr();
    cout << "\tTHE BOOK STORE MANAGEMENT SOFTWARE\n";
    cout << "\tPLEASE CHOOSE AN OPTION";
    cout << "\n1.ADD NEW BOOK\n2. SEARCH FOR A BOOK\n3. EDIT BOOK DETAILS\n 4.ADD NEW SALES\n5. DISPLAY SALES HISTORY\n";
}
void main()
{
    char ch = 'n';
    while (ch == 'n' || ch == 'N') {
        MScreen();
        int i;
        cin >> i;
        clrscr();
        switch (i) {
        case 1:
            Book a;
            a.Add();
            ofstream obj1("BOOKS.txt", ios::app);
            obj1.write((char*)&a, sizeof(Book));
            obj1.close();
            break;
        case 2:
            Book b;
            ifstream obj2("BOOKS.txt");
            obj2.seekg(0);
            cout << "Enter Book Code:";
            long int x;
            cin >> x;
            while (!obj2.eof()) {
                obj2.read((char*)&b, sizeof(Book));
                if (b.code == x) {
                    b.Display();
                    obj2.close();
                    break;
                }
            }
            break;
        case 3:
            Book c;
            cout << "\n Enter Code of book to be modified\t";
            int y;
            cin >> y;
            fstream obj3("BOOKS.txt", ios::in | ios::out | ios::ate);
            long int pos;
            obj3.seekg(0);
            while (!obj3.eof()) {
                pos = obj3.tellg();
                obj3.read((char*)&c, sizeof(Book));
                if (c.code == y) {
                    c.Modify();
                    obj3.seekp(pos);
                    obj3.write((char*)&c, sizeof(Book));
                    break;
                }
            }
            cout << "\nDATA MODIFIED\n";
            break;
        case 4:
            char ch1 = 'n';
            do {
                Book d;
                cout << "\n Enter the book code \t";
                int z;
                cin >> z;
                fstream obj4("BOOKS.txt", ios::in | ios::out | ios::ate);
                long int pos;
                obj4.seekg(0);
                int found = 0;
                while (!obj4.eof()) {
                    pos = obj4.tellg();
                    obj4.read((char*)&d, sizeof(Book));
                    if (d.code == z) {
                        found = 1;
                        break;
                    }
                }
                if (found == 0) {
                    cout << "\nIncorrect Code\t Aborting";
                    break;
                }
                else {
                    d.Display();
                    cout << "\nEnter Sales Quantity:\t";
                    int q;
                    cin >> q;
                    if (q > d.qty) {
                        cout << "\n Can't Sell. Aborting ";
                        break;
                    }
                    else {
                        Sale newsale;
                        newsale = d.Sell(q);
                        obj4.seekp(pos);
                        obj4.write((char*)&d, sizeof(Book));
                        obj4.close();
                        ofstream obj5("Sales.txt", ios::app);
                        obj5.write((char*)&newsale, sizeof(newsale));
                        obj5.close();
                        cout << "\nSALE SUCCESSFUL\n";
                        sleep(2);
                    }
                }
                cout << "\n Add more sale? (y/n)";
                cin >> ch1;
            } while (ch1 == 'y' || ch1 == 'Y');
            break;
        case 5:
            cout << "\nPlease enter SALE password:";
            char pass[40];
            gets(pass);
            if (strcmp(pass, "creationbydhruvarora\n")) {
                clrscr();
                ifstream obj6("Sales.txt");
                obj6.seekg(0);
                Sale readsale;
                int net = 0;
                while (!obj6.eof()) {
                    obj6.read((char*)&readsale, sizeof(Sale));
                    net += readsale.netprice;
                    Print(readsale);
                    sleep(1);
                }
                cout << "\n END OF SALES\n TODAY NET SALE:" << net;
                break;
            }
            else {
                cout << "\nIncorrect Password\n ABORTING";
                break;
            }
        }
        getch();
        clrscr();
        cout << "Press Any Key To QUIT. To Go To Main Menu Press 'n'\n";
        ch = getch();
    }
}

我不明白这是什么。添加到某些代码的一段代码正在中断工作而没有执行。

标签: c++

解决方案


首先,您使用的是非常古老的东西。有比这更现代的免费、绝对、完全、完全免费的东西。如果这是生产代码,您应该将其移至更新的平台。如果是学生代码,你根本不应该在这个平台上学习。如果您至少有一个 80386,那么可以免费下载可在您拥有的硬件上运行的完全可用的微型 Linux 发行版。然后你将拥有一个现代编译器。

您显然可以访问 Internet,因此您应该具备执行此操作的能力。事实上,你用来访问这个站点的硬件可能运行一个现代的、完全免费的编译器,比如 GNU C++ 或 clang。

我可以从标题和缺少::std命名空间中看出您正在使用一个非常旧的基于 MS-DOS 的编译器。Turbo C++、Borland C++、Zortech C++,也许是微软当时称他们的东西。类似的东西。我知道是因为我在 1990 年为那个平台编写了 C++。

即使考虑到那个古老的平台,您的代码也写得不好。您正在混合 stdio 和 iostreams。虽然这本质上并不坏,但它令人困惑。此外,您正在使用gets这使得错误的输入很容易使您的程序崩溃。还有其他问题,但我不会全部讨论,因为我认为它们与您的问题无关。

一般来说,为什么添加从未执行过的代码会导致程序崩溃的原因是它已经存在一个问题,即在内存中移动东西会出现。我无法编译或运行您的代码,因为它太古老了。此外,我没有可用的输入。

但是,如果我冒险猜测,那将是因为您正在使用gets并且输入导致缓冲区溢出(您正在将 40 多个字符读入缓冲区)。它总是导致缓冲区溢出,但是由于新代码在内存中移动了一些东西,它现在导致您的程序崩溃,而不是没有任何影响或导致您以前没有看到的其他问题。缓冲区溢出会导致未定义的行为,这意味着程序可以做任何事情,甚至看起来可以正常工作。

这是一个替换所有gets调用的函数:

int fetch_line(char *s, int size)
{
   fgets(s, size, stdin);
   if ((size <= 0) || (s[0] == '\0') || (s[strlen(s) - 1] != '\n')) {
      int c = '\0';
      do {
         c = getchar();
      } while ((c != '\n') && (c != EOF));
      return c != EOF;
   } else {
      s[strlen(s) - 1] = '\0'; // Drop trailing newline.
   }
}

如果没有遇到 EOF,此函数将返回一个非零(又名真)值,如果遇到,则返回 0(又名假)。它将丢弃任何不适合您的缓冲区但仍会读取到行尾(又名'\n')字符的字符。在您的代码中,对它的调用看起来像fetch_line(name, sizeof(name));.

您的代码可能还有其他问题,但如果确实如此,它们对我来说并不明显。不过,这gets是一面巨大的红旗。你永远不应该使用gets. 我的编译器给了我可怕的弃用警告,如果我使用它,我将无法关闭它,因为调用将在几年后完全消失。

通常,任何使用 C 样式字符串并且没有参数声明要写入的任何字符串的最大大小的函数都是不好使用的函数,容易出现缓冲区溢出行为。

顺便说一句,我没有平台可以调用getchclrscr工作了。使用这些功能会使您的程序非常不便携。


推荐阅读