0

Function 5:
The Display Sales History Function.. It is just displaying the last entry twice...

Function 1:
The 'Add Book' Feature.. It was actually working alright until I added the 'Edit Book' and 'Add Sales' Features. Now it writes something to the file("Books.txt"); that none of the other functions identify. Earlier,i.e. when 'Edit Book' and 'Add Sales' weren't coded and structure Sale not declared, 'Search Book' could work properly with the entry done by 'Add Book'.

((This is what I found in BOOKS.txt when I only coded functions 1 and 2 and did a test run: {{Mein Kampf ÿu)<èÿX 0@ Ÿ0 :òÿ2 XThe Accidental Prime Minister Ÿ0 :òÿ< ^Quantico ental Prime Minister Ÿ0 :òÿ ÂSurely You Are Joking, Mr. Feynman X0- ô}}

If you paste this in Books.txt, all features except 'Add' work allright))

#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();
    }
}

I do not understand what this is. A piece of code added to some code is disrupting working w/o being executed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
D.A.
  • 1
  • 1
  • 5
    Use strings. Will solve your issues. – Matthieu Brucher Feb 06 '19 at 16:28
  • 6
    Don't use plain `gets()` — it's a C function that is no longer part of the C standard. See [Why the `gets()` function is too dangerous to be used — ever!](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) – Jonathan Leffler Feb 06 '19 at 16:31
  • Go back to the version that worked (you are using either version control or copies of working code, aren't you?). Look at what changed between the two. Work out which change did the damage, and rethink that code. – Jonathan Leffler Feb 06 '19 at 16:33
  • 12
    "do not tell me my code is prehistoric" Your code is antediluvian. – George Feb 06 '19 at 16:34
  • If you add code and it breaks the execution of existing code, it will have being executed somehow. If you add code and the compilation breaks, then that's a different matter. But as said before, compare and find what changed - then investigate that. – Phil_12d3 Feb 06 '19 at 16:40
  • 2
    "Why does adding code break what was working even if it isn't executed?" - My first guess would be that your code contains Undefined Behaviour, so *any* change could cause the compiler to generate some new interresting version of broken - but you really could not rely on the "seems to work" broken behaviour in the first place. But that's just what my crystal ball tells me. – Jesper Juhl Feb 06 '19 at 16:42
  • 2
    You are clearly using some really old version of Borland C++ or Zortech C++ or something like that. If you have an 80386 or newer you can probably run a Linux distribution on it and get a very recent version of GNU C++ or clang. Do this. This is seriously extremely ancient C++. Probably more than 20 years old. If you have an 80286 or earlier... I don't know what to say. Your code is not even C++98 compliant. – Omnifarious Feb 06 '19 at 16:47
  • 1
    Please, please, *please* get a modern compiler and write modern standards compliant C++17 (I'd even settle for C++11; even if that's also getting a bit old by now). This pre-standard dinosaur should be taken out back and shot - it's the humane thing to do. – Jesper Juhl Feb 06 '19 at 16:47
  • 2
    `` is not a standard C++ header. `void main()` is not valid C++ and shouldn't compile. There are plenty of free alternatives to the ancient compiler you are using. What you learn using the compiler you are using now has to be unlearnt later on. – Ted Lyngmo Feb 06 '19 at 16:47

1 Answers1

7

First, you are using stuff that's seriously ancient. There is free, absolutely, completely, and totally free stuff out there that's much more modern than this. If this is production code, you should be moving it to a newer platform. If it's student code, you shouldn't be learning on this platform at all. If you have at least an 80386, there are perfectly serviceable tiny Linux distributions available for free download that will run on the hardware you have. And then you'll have a modern compiler.

You clearly have access to the Internet, so you should have some ability to do this. In fact, the hardware you're using to access this site could probably run a modern, completely free to use compiler like GNU C++ or clang.

I can tell from the headers and lack of ::std namespace you have that you're using a really old MS-DOS based compiler. Turbo C++, Borland C++, Zortech C++, maybe whatever Microsoft called their thing back then. Something like that. I know because I've written C++ for that platform... in 1990.

Even given that ancient platform, your code is written poorly. You are mixing stdio and iostreams. While this isn't inherently bad, it's confusing. Additionally, you're using gets which makes it easy for bad input to crash your program. There are other problems, but I won't get into all of them because I don't think they're relevant to your question.

The reason, in general, why adding code that's never executed causes your program to crash is that it had an already existing problem that moving stuff around in memory made appear. I can't compile or run your code because it's too ancient. Additionally, I have no available input to use.

But, were I to hazard a guess, it would be because you are using gets and the input is causing a buffer overrun (you are reading more than 40 characters into your buffer). It always caused a buffer overrun, but because the new code moved stuff around in memory, it's now causing your program to crash instead of having no effect or causing some other problem you didn't see before. Buffer overruns result in undefined behavior, which means the program is allowed to do anything, even seemingly work perfectly normally.

Here is a function to replace all your gets calls with:

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.
   }
}

This function will return a non-zero (aka true) value if it did not encounter EOF and 0 (aka false) if it did. It will discard any characters that don't fit in your buffer but still read until the end of line (aka '\n') character. In your code, a call to it would look like fetch_line(name, sizeof(name));.

Your code may have other problems, but if it does, they aren't obvious to me. The gets one is a huge red flag though. You should never use gets. My compiler gives me scary deprecation warnings that I can't turn off if I use it because the call is going away completely in a few years.

In general, any function that works with C-style strings and doesn't have a parameter declaring the maximum size of any string being written to is a bad function to use that's prone to buffer overrun behavior.

BTW, I have no platform on which calls to getch or clrscr work anymore. Using those functions makes your program very non-portable.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • THANK YOU FOR THE ANSWER. Though I resolved the issue myself now... with my ancient ways ofcourse. And thanks for the suggestions of what I have to do next by the way.. Will surely think of upgrading after examinations..THANKS AGAIN – D.A. Feb 07 '19 at 16:35
  • @D.A. - Did the issue turn out to be a buffer overrun with `gets`? – Omnifarious Feb 07 '19 at 16:52