-4

Why this version of C code is not working (cause segmentation fault)

#include <stdio.h>

int main()
{
    int *p;
    *p = 10;
    return 0;
}

while this one is working?

int main()
{
    char c = 'c';
    int *p;
    *p = 10;
    return 0;
}
  • 5
    Define "working." – Robert Harvey Aug 29 '21 at 14:24
  • 7
    Pure coincidence. The second one is as much Undefined Behaviour as the first. – Thomas Aug 29 '21 at 14:24
  • Coincidence, the more memory used, the less a bug might be exposed. – Joop Eggen Aug 29 '21 at 14:25
  • 2
    I'm going to get hammered by the C pedants for this again, but I'm going to say it (again) anyway. Trying to reason about when UB works and when it doesn't is *pointless.* It's *undefined behavior.* That's it. The only reasonable response is "don't write code like this." – Robert Harvey Aug 29 '21 at 14:25
  • I am confused, why the second version works, even trying to print the value of `p` will work, even the pointer is uninitialized? – Abdullah Almariah Aug 29 '21 at 14:30
  • @RobertHarvey The classic example I use is the type-punning via pointer done by the [Fast inverse square root](https://en.wikipedia.org/wiki/Fast_inverse_square_root) that shipped in Quake 3, and happened to work great. Mathematically brilliant code, but overlooked that type-punning via pointer was illegal. UB is some tricky stuff. – Alexander Aug 29 '21 at 14:32
  • @AbdullahAlmariah: Because it does. There can be no better answer, unless you decide to dig into the compiler's internals. – Robert Harvey Aug 29 '21 at 14:33
  • @AbdullahAlmariah You have to define "working". In general, no, that program doesn't work. It *happens* to work, for the specific compiler version, compiler settings, and platform you happen to currently be using. "Even a stopped clock is right twice a day." You're violating the semantic rules of C. The compiler only its correctness with respect to the valid semantics of C. It might happen to work now, but as soon as you raise the optimization level, or add some other code, it could break, because *it was always broken*. Please see https://stackoverflow.com/q/2397984/3141234 – Alexander Aug 29 '21 at 14:36
  • 1
    Look for warnings after compilation. I guess they are not 0. Try to compile with 0 warnings. – i486 Aug 29 '21 at 14:38
  • If you are using `clang` or `gcc` add these options when debug compiling: `-g -fsanitize=address,undefined`. It can save hours of speculation. Here's an [example](https://godbolt.org/z/Edq7r3Px8) of the output when running your "working" code. – Ted Lyngmo Aug 29 '21 at 14:53
  • One possible result of undefined behavior is that your code *appears* to work with no issues - in the second snippet, `*p` just happened to correspond to a location that could be written to without triggering a segfault. It "worked" in the sense that it didn’t blow up immediately, but depending on what you modified it could cause problems elsewhere. – John Bode Aug 29 '21 at 18:06

2 Answers2

1

For int* p, no storage space is allocated for the actual integer number. You need to modify your code as follows to make it work properly. In C++, you can use new, but in C you can use malloc.

#include <stdio.h>

int main()
{
    int* p = malloc(sizeof(int));
    *p = 10;
    free(p);
    return 0;
}
WStar
  • 187
  • 2
  • 12
1

Both code snippets are wrong, we can't say that one is more wrong than the other, p is uninitialized in both cases and therefore it may or may not contain a valid memory address, it's impossible to predict, this means that the behavior is undefined. That being the case, working, whatever that may mean, is well within the realm of possible outcomes.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • 1
    Re “`p` is uninitialized in both cases and therefore will not contain any valid memory address” is a partial definition of the behavior. The behavior is **un**defined, which means we do not know (from the C standard alone) whether or not it will contain any valid memory address. – Eric Postpischil Aug 29 '21 at 15:30