为什么即使不执行添加代码也会破坏正在运行的内容?

时间:2019-02-06 16:27:55

标签: c++

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

功能1:
“添加书”功能。在我添加“编辑书”和“添加销售”功能之前,它实际上一直工作正常。现在它将内容写入文件(“ Books.txt”);其他功能都无法识别。较早 如果未对“编辑书”和“添加销售”进行编码并且未声明结构“销售”, “搜索书”可以与“添加书”完成的条目一起正常使用。

(((这是当我仅对函数1和2进行编码并进行测试运行时在BOOKS.txt中找到的内容: {{Mein Kampfÿu)<èÿX0 @Ÿ0:òÿ2X偶然的总理Ÿ0:òÿ<^量化首相Ÿ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();
    }
}

我不明白这是什么。添加到某些代码中的一段代码破坏了正在执行的工作。

1 个答案:

答案 0 :(得分:7)

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

您显然可以访问Internet,因此您应该具有一定的能力。实际上,您用来访问该站点的硬件可能可以运行完全免费的现代编译器,例如GNU C ++或clang。

我可以从标题和缺少::std命名空间的情况下看出,您使用的是真正的基于MS-DOS的旧编译器。 Turbo C ++,Borland C ++,Zortech C ++,也许那时微软所说的话。这样的事情。我知道是因为我在1990年为该平台编写 C ++。

即使使用了古老的平台,您的代码编写也不佳。您正在混合stdio和iostream。虽然这并不是天生的坏事,但令人困惑。此外,您使用的是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,则此函数将返回非零值(即true),如果未遇到,则将返回0(即false)。它将丢弃缓冲区中不适合但仍要读到行尾(也称为'\n')字符的所有字符。在您的代码中,对其的调用类似于fetch_line(name, sizeof(name));

您的代码可能还有其他问题,但是如果确实存在,它们对我来说并不明显。 gets是一个巨大的危险信号。您应该从不使用gets。我的编译器给我可怕的弃用警告,如果使用它,我将无法关闭,因为该调用将在几年后完全消失。

通常,任何与C样式字符串一起使用并且没有声明要写入的任何字符串的最大大小的参数的函数,使用起来很不好,因为它易于缓冲溢出行为。

顺便说一句,我没有平台可以再使用getchclrscr进行呼叫。使用这些功能使您的程序非常不可移植。