1

Hi can someone tell why in Linux and windows the same problem occurs :

#include <iostream>
using namespace std;

class A
{
private:
   int _dmember;

public:
   void func()
   {
     cout<<"Inside A!! "<<endl;
     cout<<_dmember; // crash when reach here.
   }
};

int main ()

{

    A* a= NULL;

    a->func(); // prints "Inside A!!!" 

    return 1;
}

can someone tell why this weird behivior occurs ? i mean , the a->func() was not supposed to get inside the func() ,...? this is unwated behavior ,

why the above behivor occurs?

EDIT: Of course , a* =null was intentionaly!! so for all who answered "this is undefined behavior" or "you should never try to call a function on a NULL pointer !!", come on.... that was the point. and this behavior was explained correctly by some of you.

Robocide
  • 6,353
  • 4
  • 37
  • 41
  • I edited your source so that it at least compiles. – Thomas Nov 08 '09 at 12:33
  • For static methods: They don't need any objects at all, so there is nothing that can or should be checked against NULL. You can call static methods directly as `classname::func()`, without ever creating an object. – sth Nov 08 '09 at 12:45
  • Java/C# decided to pay the price and check each pointer before use. But in C++ a deliberate decision was made that this was the programmers responsibility. Because if the compiler does it then everybody has to pay the price (in slower code) because of the few beginners who don't know how to program. Basically I don't want to pay the price of a forced NULL check in my code (because I know long before the call if it will fail) just because you don't know how to use the language (or as you so eloquently put it: because you ???? at C++) – Martin York Nov 08 '09 at 18:18

11 Answers11

12

This is undefined behaviour. You must never call functions on a null pointer.

With that out of the way, let's answer the question I think you're asking: why do we get partway into the function anyway?

When you are invoking UB, the compiler is free to do anything, so it's allowed to emit code that works anyway. That's what happens on some (many?) systems in this particular case.

The reason that you're able to call the function on a null pointer successfully is that your compilers don't store the function "in" the object. Rather, the above code is interpreted somewhat like this:

class A {
    int _dmember;
};

void A::func(A *this) {
    cout << "Inside A!!" << endl;
    cout << this->_dmember << endl;
}

int main() {
    A *a = ...;
    A::func(a);
}

So, you see there is nothing that actually prevents you from calling a function on a null pointer; it'll just invoke the body of the function, with the this pointer set to null. But as soon as the function tries to dereference the this pointer by accessing a field inside the class, the operating system steps in and kills your program for illegal memory access (called segmentation fault on Linux, access violation on Windows).

Nitpicker's corner: Virtual functions are a different story.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • +1 for functions are not internally stored "in" an object. It is a bit different from memory managed languages such as Java or C# as they would throw null pointer exceptions if the program is calling an method on an object that is null. – Spoike Nov 08 '09 at 12:42
  • regarding Nitpicker's corner , virtual function does behave correctly because it tries to dereference the func pointer from vtable. – Robocide Nov 08 '09 at 13:27
  • @nyholku Why not? The question was "the a->func() was not supposed to get inside the func() ,...?". My answer shows how it is possible that we _do_ get partway into `A::func` before the crash happens. – Thomas May 12 '18 at 11:57
  • @Thomas: I'm nit picking but the answer I think is that the answer to "why the above behivor occurs?" is that even though the OP said this is unwanted (what a concept!), the code is using undefined behaviour (as pointed out in other answers) which I do not read from your answer, even if otherwise nice and useful. – nyholku Jun 11 '18 at 15:01
  • @nyholku Yeah, I've improved the answer a bit, thanks. – Thomas Jun 12 '18 at 10:03
7

Undefined behavior because you are accessing a NULL pointer:

A* a= NULL;
a->func(); // is not defined by the language

Note that even if func() didn't try to access a member variable, the behavior still is undefined. For example, the following code could run without errors, but it is not correct:

   func()
   {
     cout<<"Inside A!! "<<endl;
   }

EDIT: With my full respect, C++ doesn't suck!

What you need is a smart pointer, not a raw pointer. As my professor says always, if you don't know what you are doing in C/C++, it is better not to do it!

Use boost::scoped_ptr, and enjoy exception safety, automatic memory management, zero overhead and NULL checking:

struct test
{
    int var;
    void fun()
    {
        std::cout << var;
    }
};

int main()
{
    boost::scoped_ptr<test> p(NULL);
    p->fun(); // Assertion will fail, Happy debugging :)
}
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • UnDefined behavior ?? i really expected the language not to actually execute func() because the object is NULL , there is no object alive for executing this Member function. its really sucks. – Robocide Nov 08 '09 at 12:28
  • 8
    That would require the runtime system to check for `NULL` pointers - something which goes against the spirit of C++. (You don't want those checks in the inner loops of your graphic card driver.) – sbi Nov 08 '09 at 12:32
  • 2
    @Avishay: It's the other way around: The language expects you, the programmer, to not try to execute func() on a NULL pointer. The language says that you are not allowed to do this. It doesn't say what happens if you do it anyway, it trusts you that you are not going to do things that are not allowed. – sth Nov 08 '09 at 12:40
  • I stand corrected and amazed. Yet another reason to hate C++! – Carl Smotricz Nov 08 '09 at 12:41
  • Me too another reason c++ Sucks – Robocide Nov 08 '09 at 13:24
  • A decent compiler will warn you of obvious cases like this, though – Hasturkun Nov 08 '09 at 13:27
  • 11
    Well, preventing null pointers is relatively straightforward. In the simplest case, null pointers can be removed completely from consideration (by just not having them; often, this works very well). Blaming the language for one’s own ineptitude isn’t really constructive … C++ has a lot worse deficiencies. – Konrad Rudolph Nov 08 '09 at 13:51
  • 2
    Wow so the language sucks because it doesn't do what you want it to do, even if you use it in a way you are NOT supposed to. Great way of thinking. It's just slow to do NULL checking every time, and most of the time it's not needed because the programmer is supposed to know what he is doing. If you really need it in some point, just add it. – AntonioMO Nov 08 '09 at 15:21
  • machielo , i did not ment to manualy check everytime, debuging through Log files which prints entering and exiting functionsis a way allot of companies work.what i ment is to add the check inside the macro, but its not good for static methods, and btw machielo , as you know when you work allot of code is not written by you and your trying to debug bugs. – Robocide Nov 08 '09 at 17:29
  • 2
    @_Avishay: Sorry but I don't want to pay the price of checking each pointer is NULL just because you suck as a programmer. I know my code works so why should I pay the extra price (in slower code) to support you(re inexperience)? – Martin York Nov 08 '09 at 18:09
  • Martin : there is no need to be personnaly offensed, there are times when you just debug code you did'nt write , and when you debug through log files and see, "Entered Function X" , i personaly want to know the instance operating Function X is alive and not NULL. – Robocide Nov 09 '09 at 09:30
  • @_Avishay_: Fair enough, that's a pretty good reason. May I adapt Martin's statement then? "I don't want to pay the price of checking each pointer is NULL just because whoever wrote that code you're debugging sucks as a programmer. I know my code works so why should I pay the extra price (in slower code) to support their inexperience?" I guess it works just as well now. – sbi Nov 12 '09 at 23:10
1

Dereferencing a null pointer is undefined behaviour. Everything could happen, so don't do it. You must check that the pointer is valid before dereferencig it. this pointer cannot be null so you wouldn't avoid the undefined behaviour.

Francesco
  • 3,200
  • 1
  • 34
  • 46
0

Most compilers just pass the pointer to the class as the first parameter (The this pointer). If you don't go on to de-reference the this pointer then you are not actually going to cause a crash. Your this pointer, inside the functiom, will simply be NULL.

As AraK pointed out this is undefined behaviour so your mileage mat vary...

Goz
  • 61,365
  • 24
  • 124
  • 204
0

Aren't you supposed to allocate a memory for your pointer? I just wonder what is the intention to call a function of a NULL pointer? It's supposed to crash immediately. It doesn't crash on the line where you don't call to A member _dmember,but the moment you call it your function crashes cause the object is simply not allocated. _dmember points on undefined memory... That's why it crashes

Nava Carmon
  • 4,523
  • 3
  • 40
  • 74
  • you must allocate heap memory for the pointer only if the object is being constructed. If you already have a well formed object (maybe on the stack) you are not required to allocate memory for it. But you are always required to check that the pointer is valid! – Francesco Nov 08 '09 at 12:34
0

Its a null pointer, you simply can't define what should happen if we call a function on it.

alternative
  • 12,703
  • 5
  • 41
  • 41
0

Any pointer variable is supposed to point to some object.

Your declaration A * a = NULL; does not point anywhere and so will not yield the results as it should.

You can however try this

A * a = NULL;
A b;
a=&b;
a->func();

this will yield the output.

avakar
  • 32,009
  • 9
  • 68
  • 103
manugupt1
  • 2,337
  • 6
  • 31
  • 39
0

Since there are no virtual functions in your class, it's easier here to think about what C code would be generated to represent this type. Approximately:

#include <stdio.h>


typedef struct
{
  int d_;
} A;


FILE* print_a_to(A* a, FILE* dest)
{
  return fprintf(dest, "Inside A!! \n") < 0 ||
         fprintf(dest, "%d", a->d_) < 0 ?
         NULL :
         dest;
}


int main(int argc, char* argv[])
{
  A* a = NULL;
  return NULL == print_a_to(a, stdout) ?
         -1 :
         0;
}

Look at the second line of function print_a_to; see the dereferencing of pointer a? Per the first line of function main, you're passing NULL as the value of pointer a. Dereferencing a null pointer here is equivalent to calling a member function on your class that needs access to its member variables through a null pointer.

seh
  • 14,999
  • 2
  • 48
  • 58
0

if i was'nt clear, i am not trying to do deliberately below:

A* a=NULL;    
a->f(); 

i wrote that code just to check why is it working , and ofcourse i was disappointed and my reason to be disapointed is that i debug very big program in Redhat-Linux , through log-files concept( meaning - Printing Entering,Exiting from functions to logs, including printing imporant values). AND, on my way on the logs i hoped that if im on specific STACK of function calls i hoped at least the instances operating these functions are alive, but as i discovered and disapointed its not ought to be , which for me disapointement because it makes the debug through log files even more difficult.

Robocide
  • 6,353
  • 4
  • 37
  • 41
0

I hope you described the symptoms exactly as what you saw. I tried on both Windows and Linux. Linux gives a segment fault, and Windows displays the error dialog.

The address area around 0x0 is protected by Windows and Linux. Reading and writing in this memory area will cause the OS throws an exception. Your application can catch the exception. Most application do not, and OS default handling routine is to print some error message and terminate the program.

One may ask why the message ""Inside A!! " is printed before termination. The answer is that at backend, C++ compiler converts class methods into procedure calls. This step does not involve pointer dereference. You can think that the result look like this:

void A_func(A* a)
{
     cout<<"Inside A!! "<<endl;
     cout<<a->_dmember; // crash when reach here.
}

A* a = NULL; A_func(a);

The dereference of NULL pointer happened at the second statement. So the first statement was executed just fine.

cuteCAT
  • 2,251
  • 4
  • 25
  • 30
  • please try assigning a*=NULL; before invoking the function and see the expected results as i said, and the explaination by in the first answer by thomas. – Robocide Jan 13 '10 at 08:07
0

the point is that the -> operator on class object (with no vtable) is not a dereference of the pointer

a->foo()

is really shorthand for

A::foo(a)

where the first param gets transformed into the this pointer. Its when u try to deref 'this' by referring to member variable that things go bad.

pm100
  • 48,078
  • 23
  • 82
  • 145