By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,384 Members | 671 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,384 IT Pros & Developers. It's quick & easy.

Weird behaviour of compiler

P: 8
I was working on a project in c++,which involved managing accounts.Here is an extract of source code of project

1.logging in

Expand|Select|Wrap|Line Numbers
  1. user user::login(short int pur)
  2. {
  3.     clrscr();
  4.     fstream f("users.dat",ios::in|ios::out|ios::binary);
  5.     user u[10];
  6.     int i=0;
  7.     while(f.read((char*)&u[i],sizeof(user)))
  8.         i++;
  9.     f.close();
  10.     cout<<"Enter user name\n";
  11.     char n[30];
  12.     gets(n);
  13.     int pos=search(u,n,i);
  14.     int chk=0;
  15.     if(pos==-1)
  16.     {
  17.         cout<<"Sorry user not found\n";
  18.         return fail();
  19.     }
  20.     cout<<"Enter password\n";
  21.     gets(n);
  22.     int ver=verify_password(u[pos],n);
  23.     if(ver==0)
  24.     {
  25.         if(pur==0)
  26.         {
  27.             cout<<"Access granted\n";
  28.             getch();
  29.         }
  30.         return u[pos];
  31.     }
  32.     cout<<"Incorrect password\n";
  33.     return fail();
  34. }
  35.  
2.Changing password

Expand|Select|Wrap|Line Numbers
  1. user user::change_password()
  2. {
  3.     user u;
  4.     u=login();
  5.     .
  6.     .          //The problem occurs within this.Hence,
  7.     .          //I don't think the rest of the code
  8.     .          //is required
  9.     .
  10.  
You don't have to read the whole of the first code, because the problem occurs within the first few lines.As you might have guessed, user is the name of a class.

Now, here is the most weird problem I have ever faced-

1.If I directly call the directly,login() function it executes properly.OK very good.

2.If I call the login() function from change_password() function(by running it normally using ctrl+F9) it shows divide error exception.OK maybe something to do with the arguments passed.

3.If I execute the same function, through the same change_password() function, step by step,it shows General Protection Fault(not divide error exception)!!!

That's not all!!When I execute the change_password() function normally ,it fails to clear the screen itself ( the very first statement).However if I execute the same function step by step it get struck just before array of object is initialised( 3rd statement). Like I already mentioned if I directly call the login() function it does not show any error.Hence it has gone nothing to do with the array size.

Someone please explain this weird behaviour to me and correct my code.I appreciate an early response.
Dec 30 '15 #1
Share this Question
Share on Google+
13 Replies


weaknessforcats
Expert Mod 5K+
P: 9,197
The first thing I see is that login() is supposed to return a user but there are places where it's returning fail(). That fail appears to trigger a user constructor so login() returns a corrupt object.

As a rule in C++ functions should receive reference arguments so there's nothing to return. The function return value would then be available for pass/fail values.
Dec 30 '15 #2

P: 8
Forget about returning values.It encounters the exception even before the declaration of object takes place.Moreover if what you told is right, then when I directly call login() function, it shouldn't work.But in reality it does work properly.
Dec 31 '15 #3

weaknessforcats
Expert Mod 5K+
P: 9,197
What does user::operator= look like? You might post the user class code.

What exception?

Also, when you say it works when you call login() directly do you mean:

Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3.    login();
  4. }
or do you mean:

Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3. user u;
  4. u=login();
  5. }
I do say again that the return from fail() is not a valid user constructor argument. You need to have a user& as an argument to user::change_password. That way you can use the return from login() for fail() as you are currently doing.

Note also that the return from user::change_password is a user object and the only one around is a local object which I presume is returned so that would trigger a copy constructor call to get from the local user object to the returned user object. I would like to see the user copy constructor.

Where is the password? Is the object used by user::change_password the this object? If so, then why have a user object in this code when the this is all you need.

Hopefully your code post will clear this up
Dec 31 '15 #4

P: 8
I haven't defined an operator like '=' in my class.Instead,I have used the operator '=' which the compiler itself provides. I have done so,because there are too many members in the class and none of these require a change in value when an object is initialized to another object.Hence,I would be wasting ultra lot of time for typing this, but would gain nothing.But anyway, since you asked for the class definition of 'user', here it is-

Expand|Select|Wrap|Line Numbers
  1. class user
  2. {
  3.     char name[30],pass[30];
  4.     unsigned int pts,n_pts;
  5.     short int dif,a_dif,prev_mis,no_wins,cons_mis,cons_switch,tot_wins,loss;
  6.     float wrong;
  7.     public:user(char n[]="\0\0\0",char p[]="\0\0\0")
  8.     {
  9.         strcpy(name,n);
  10.         strcpy(pass,p);
  11.         pts=n_pts=dif=a_dif=prev_mis=no_wins=cons_mis=cons_switch=cons_switch=tot_wins=loss=0;
  12.         wrong=0;
  13.     }
  14.  
  15.     /*The code after this
  16.     has all member functions
  17.     declared within it*/
  18.     .
  19.     .
  20.     .
  21.  
  22. };
  23.  
When I said "calling the login() function directly" ,I meant the second code, which you gave.

The function fail() is not a constructor.It is a user-defined(non-member) function, which is defined this way-

Expand|Select|Wrap|Line Numbers
  1. inline user fail()
  2. {
  3.     user u;
  4.     return u;              
  5. }
  6.  
Here, the function fail() makes use of the fact that the default constructor is called when an object of a class is initialized normally(without parameters).So basically, this function initializes an object u with username like "\0\0\0"(see the constructor of the user function) and returns this.Hence any object, which is returned from the function with username like "\0\0\0" is taken as failure.This proves the significance of using "return fail()" statement frequently.Also, there is no way of typing 4 null characters on the key board.Hence,this is the only way how this fail() value can be returned.Hence, no clashes can take place.I haven't directly returned the user() constructor directly b'coz it affects the program's understandability.

ok.Maybe the working of the fail() function would be a little confusing.But my point here is that the function fail () is not a constructor of some other class, nor does it return an object of some other class.Hence, there is no chance this can give corrupted values.

This program does not have a copy constructor defined in it. Instead, uses the copy constructor provided by the compiler, again b'coz of those 2 reasons, which I had already mentioned above(the reasons for not defining the operator '=').

Password as you would have recognized above, is a member of the class user.

The function user::change_password() doesn't use the this object.

Hopefully I have clarified all your doubts.
Dec 31 '15 #5

weaknessforcats
Expert Mod 5K+
P: 9,197
I am trying to get a test program working but I find that inside user::change_password there is a login() but the function that was posted as user::login(short int pur) won't compile as a
login(). One has arguments and the other doesn't. Are there two login one of which is not a member function?
Dec 31 '15 #6

P: 8
yeah.One is a non member function and the other the member function. Both functions have 1 parameter with default argument.The non member function just declares an object of user datatype, to invoke the member function.Here is the non member function, just in case u want-
Expand|Select|Wrap|Line Numbers
  1. inline user login(int pur=0)
  2. {
  3.     user u;
  4.     u=u.login(pur);
  5.     return u;
  6. }
  7.  
Dec 31 '15 #7

P: 8
and the second statement in the change_password() function was
Expand|Select|Wrap|Line Numbers
  1. u=login(1
not
Expand|Select|Wrap|Line Numbers
  1. u=login()
.

I'd changed the statement for debugging purposes and had left it like that itself.Anyways, both show the same error though
Dec 31 '15 #8

weaknessforcats
Expert Mod 5K+
P: 9,197
I am able to run your code without a crash using this main():

Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3.     user u;
  4.     user x("HELLO", "WORLD");
  5.  
  6.     u = x;
  7.  
  8.     u = fail();
  9.  
  10.     u = login(1);
  11. }
The only changes I made were:

1) a phony user.dat file
2) commented out //int pos = search(u, n, i); in user::change_password and set pos =0 instead. I didn't have the search function.

That said, there may be a problem in the search. That's the sort of thing where you can get a general protection fault.

My test main runs to completion with or without the debugger.

You might post the search code so I can add it to my test program.
Jan 1 '16 #9

P: 8
Here is the code
Expand|Select|Wrap|Line Numbers
  1. int search(user a[],char b[],short int ub,int pur=0)
  2. {
  3.     for(int i=0;i<=ub;i++)
  4.     {
  5.         if(compare(a[i],b)==0)
  6.         {
  7.             if(pur!=0)
  8.             {
  9.                 a[i].display();
  10.                 getch();
  11.             }
  12.             return i;
  13.         }
  14.     }
  15.     if(pur!=0)
  16.         cout<<"User not found\n";
  17.     return -1;
  18. }
  19.  
Also note that in the main function,I didn't pass any parameters to login() function(The default val ie. 0 was hence the val of pur).I passed 1 as a parameter only in change_password() function.
Jan 1 '16 #10

P: 8
OK, apart from this, as you mentioned the data file "users.dat" is the only requisite which is probably missing in the information which I have provided.Coincidentally, the error is shown after an fstream object f is declared (the fstream object is declared before the array of object u and the compiler stops just before declaration of this array of objects that is @ the statement fstream f("users.dat,ios::in|ios::out|ios::binary)).

Hence I'll provide you with my code of creating phony users.dat file-

Expand|Select|Wrap|Line Numbers
  1. #include<fstream.h>
  2. #include<conio.h>
  3. #include<stdio.h>
  4. #include<string.h>
  5. class user
  6. {
  7.     public:
  8.     char name[30],pass[30];
  9.     unsigned int pts,n_pts;
  10.     short int dif,a_dif,prev_mis,no_wins,cons_mis,cons_switch,tot_wins,loss;
  11.     float wrong;
  12.     user(char n[]="\0\0",char p[]="\0\0")
  13.     {
  14.         strcpy(name,n);
  15.         strcpy(pass,p);
  16.         pts=n_pts=dif=a_dif=prev_mis=no_wins=cons_mis=cons_switch=cons_switch=tot_wins=loss=wrong=0;
  17.     }
  18. };
  19. user fail()
  20. {
  21.     user a;
  22.     return a;
  23. }
  24. int compare(user a,user b)
  25. {
  26.     int ret=strcmpi(a.name,b.name);
  27.     return ret;
  28. }
  29. void main()
  30. {
  31.     cout<<"Are you sure you want to add sample users?\nOther contents may get destroyed\n(yes/no)\n";
  32.     char ch[10];
  33.     gets(ch);
  34.     if(strcmpi(ch,"yes")==0)
  35.     {
  36.         user u[6];
  37.         fstream f("users.dat",ios::out|ios::binary),f2("ldr brd.dat",ios::out|ios::binary);
  38.         strcpy(u[0].name,"admin");
  39.         strcpy(u[0].pass,"admin");
  40.         f.write((char*)&u[0],sizeof(user));
  41.         for(int i=1;i<5;i++)
  42.         {
  43.             char ch[15]="Sample ",no[2];
  44.             no[0]=i+48;
  45.             no[1]='\0';
  46.             strcat(ch,no);
  47.             strcpy(u[i].name,ch);
  48.             strcpy(u[i].pass,ch);
  49.             u[i].pts=(i-1)*100;
  50.             f.write((char*)&u[i],sizeof(user));
  51.         }
  52.         while(i>0)
  53.         {
  54.             if(compare(fail(),u[i])!=0)
  55.             {
  56.                 f2.write((char*)&u[i],sizeof(user));
  57.             }
  58.          i--;
  59.         }
  60.         cout<<"Successfully added\n";
  61.         f.close();
  62.         f2.close();
  63.     }
  64. }
  65.  
Hopefully, this helps you debug the error.
Jan 1 '16 #11

Expert 100+
P: 2,398
I'm more C than C++, so these comments may not be correct or pertinent...
  1. Lines 7-8 of user::login. What if users.dat contains more than 10 entries? Don't see anything in this loop to protect you from running past the end of u.
  2. Lines 8 and 13 of user::login; line 3 of search. Shouldn't line 3 of search be i<ub rather than i<=ub?
Jan 2 '16 #12

P: 8
Thx donbock.But it actually doesn't help.
Jan 3 '16 #13

weaknessforcats
Expert Mod 5K+
P: 9,197
I notice you are using gets() and not fgets(). gets() only works with stdin and copies to a buffer until it reaches a newline. It leaves the newline in stdin for the next operation to trip over and does not let you specify a buffer size leading to overruns followed by general protection faults
gets() has been removed from C++ in 2011 and is effectively removed from C.

You might consider using fgets().

In any case add some error checking code to test the return from gets() to see if any error occurred.
Jan 4 '16 #14

Post your reply

Sign in to post your reply or Sign up for a free account.