0

Below, I have provided three different scenarios in which the codes spit out "segmentation fault" and I am not sure why! Scenario 1 only performs the first line (This is i: 42) and then it crashes with the segmentation fault message. In scenario 2, where I just declare the pointers (but do not initialise them), the code works up to std::cout << "This is *pi3: " << *pi3 << std::endl; (it does not perform this line and the rest). Finally, in scenario 3, once again it only performs the first line (i.e. "This is i: 42") even though I only added int j = 5;!

Scenario 1:

#include <iostream>
#include <cstdlib>

int main(){
    
    int i    = 42;
    int *pi  = nullptr;
    int *pi2 = &i     ;
    int *pi3 = nullptr;

    std::cout << "This is i: "    << i    << std::endl;
    std::cout << "This is *pi: "  << *pi  << std::endl;
    std::cout << "This is pi: "   <<  pi  << std::endl;
    std::cout << "This is *pi2: " << *pi2 << std::endl;
    std::cout << "This is pi2: "  << pi2  << std::endl;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    pi3 = pi2;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    return 0;
}

Scenario 2:

#include <iostream>
#include <cstdlib>

int main(){
    
    int i    = 42;
    int *pi      ;
    int *pi2 = &i;
    int *pi3     ;

    std::cout << "This is i: "    << i    << std::endl;
    std::cout << "This is *pi: "  << *pi  << std::endl;
    std::cout << "This is pi: "   <<  pi  << std::endl;
    std::cout << "This is *pi2: " << *pi2 << std::endl;
    std::cout << "This is pi2: "  << pi2  << std::endl;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    pi3 = pi2;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    return 0;
}

And Scenario 3 (where I just add int j = 5;):

#include <iostream>
#include <cstdlib>

int main(){
    
    int i    = 42;
    int j    = 5 ;
    int *pi      ;
    int *pi2 = &i;
    int *pi3     ;

    std::cout << "This is i: "    << i    << std::endl;
    std::cout << "This is *pi: "  << *pi  << std::endl;
    std::cout << "This is pi: "   <<  pi  << std::endl;
    std::cout << "This is *pi2: " << *pi2 << std::endl;
    std::cout << "This is pi2: "  << pi2  << std::endl;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    pi3 = pi2;
    std::cout << "This is *pi3: " << *pi3 << std::endl;
    std::cout << "This is pi3: "  << pi3  << std::endl;
    return 0;
}

I understand that initialising pointers (and to a greater extend all variables) is good practice. Then, why does it not work here? And why does it only work half way through the code when I do not initialise *pi and *pi3 in scenario 2? I would be thankful if you could explain to me what is happening in each scenario and the source of error(s). I use both g++ and clang++ on a 2019 MacBook Pro!

Thank you.

zhuser
  • 21
  • 1
  • 5
  • 3
    You can't dereference a nullptr. – drescherjm Jul 07 '20 at 18:57
  • Any attempt to dereference a null pointer will result in undefined behavior. A segmentation error is a sure sign of UB. – Mark Ransom Jul 07 '20 at 18:57
  • 2
    Can you share what you expect `*nullptr` to result in? – François Andrieux Jul 07 '20 at 18:58
  • Scenario 2 is also incorrect because you dereference a pointer that was not initialized, but by sheer luck, on your particular machine and on this particular day, it happens to point somewhere that doesn't cause a crash when accessed. It's still undefined behavior. – Nate Eldredge Jul 07 '20 at 19:00
  • 2
    It's not the *initialisation* that is the problem, it's the *dereferencing* of a null pointer. I.e. in your first example `std::cout << *pi` is the problem, until that point there's been no errors. – john Jul 07 '20 at 19:01
  • @ François Andrieux, at this point I am just doing some trial and errors. My understanding was that once I initialise a pointer with either NULL, nullptr, or 0 I can dereference it and get the value of 0. But I was wrong! – zhuser Jul 07 '20 at 19:09
  • `std::cout << "This is pi: " << pi << std::endl;` is legal in the first example `std::cout << "This is *pi: " << *pi << std::endl;` is not legal because the latter statement dereferences the null pointer with `*pi` – drescherjm Jul 07 '20 at 19:11
  • On a modern CPU a block of memory is reserved as a death zone at the beginning of memory to make it easy to detect null pointer accesses. This isn't guaranteed, though. – user4581301 Jul 07 '20 at 19:13
  • 3
    @zhuser The problem is that it is not possible to learn C++ by trial-and-error. This is because not all compilable code necessarily has defined behavior. C++ has Undefined Behavior meaning it is possible to write invalid code that still compiles, that may appear to work in some way, but that behavior could change at any time, for no apparent reason. When trying to learn by trial-and-error it isn't possible to know if what you observe is actually well defined behavior or the result of Undefined Behavior. You need to be certain that the code you write is allowed before you can draw conclusions. – François Andrieux Jul 07 '20 at 19:13
  • @Nate Eldredge, in scenario 2 the code prints out the value of 0 for the line `std::cout << "This is *pi: " << *pi << std::endl;`. So, based on what you just said that means I should not have gotten that value. Instead it should have crashed right there! – zhuser Jul 07 '20 at 19:15
  • 2
    @zhuser That is the annoying thing about Undefined Behavior, it doesn't need to produce an easy to diagnose behavior like a crash. It can just (by coincidence) do something that seems reasonable when you try it making it harder to detect the actual cause of the problem. – François Andrieux Jul 07 '20 at 19:17
  • 1
    I didn't say that! It *could* have crashed right there. But the compiler is not required to make that happen. By sheer luck, the uninitialized garbage value stored in `pi` *happened* to contain the address of a memory location that you're able to read, and by *even more sheer luck*, that memory location happened to contain the value 0. None of those things were guaranteed to happen, and if you try it on another machine, the result *may* be very different. – Nate Eldredge Jul 07 '20 at 19:17
  • 2
    [Classics of undefined behaviour](https://www.youtube.com/watch?v=73wMnU7xbwE). How many times do you think this demo worked perfectly before Bill Gates agreed to go on stage to lend weight to the presentation? – user4581301 Jul 07 '20 at 19:21
  • On my machine 1 crashes, 2 does not compile, 3 does not compile. I have warnings turned on, and warnings-as-errors turned on. – Eljay Jul 07 '20 at 19:55
  • I appreciate your comments people. Thank you. – zhuser Jul 07 '20 at 21:27

0 Answers0