C++ SegFault when dereferencing a pointer for cout
Asked Answered
S

5

10

I'm new to C++ and just trying to get a hang of it. It generally seems not too bad, but I stumbled upon this weird/pathological segfaulting behavior:

int main () {
  int* b;
  *b = 27;
  int c = *b;
  cout << "c points to " << c << endl; //OK                                                                                                                                      
  printf( "b points to %d\n", *b); //OK                                                                                                                                          
  // cout << "b points to " << (*b) << endl; - Not OK: segfaults!                                                                                                               
  return 0;
}

This program, as given, produces what you'd expect:

c points to 27
b points to 27

On the other hand, if you uncomment the second-to-last line, you get a program that crashes (seg-fault) in runtime. Why? This is a valid pointer.

Submediant answered 22/5, 2011 at 1:45 Comment(1)
Note, this question was merged with Why does this program segfault upon printf?Hohenlohe
M
12

int* b points to an unknown memory address because it wasn't initialized. If you initialized it to whatever null pointer value exists for your compiler (0 until C++11, nullptr in C++11 and newer), you'd most certainly get a segfault earlier. The problem lies in the fact that you allocated space for the pointer but not the data it points to. If you instead did this:

int c = 27;
int* b = &c;

cout << "c points to " << c << endl;
printf ("b points to %d\n", *b);
cout << "b points to " << (*b) << endl;

Things would work because int* b refers to a memory location that is accessible by your program (since the memory is actually a part of your program).

If you leave a pointer uninitialized or assign a null value to it, you can't use it until it points to a memory address that you KNOW you can access. For example, using dynamic allocation with the new operator will reserve memory for the data for you:

int* b = new int();
*b = 27;
int c = *b;

//output

delete b;
Macule answered 22/5, 2011 at 1:57 Comment(0)
H
9

Update 3

My answer to Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior? gives a much better answer to why using an uninitialized pointer is undefined behavior. The basic logic from the C++ draft standard, section 24.2 Iterator requirements, specifically section 24.2.1 In general paragraph 5 and 10 which respectively say (emphasis mine):

[...][ Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. —end example ] [...] Dereferenceable values are always non-singular.

Update 2

This was originally an answer to a C question with nearly identical circumstances but the original question I answered was merged with this one. I am updating my answer to include an answer specific to the new question and to the C++ draft standard.

b has not be initialized and therefore it's value is indeterminate but you used indirection on b which is undefined behavior.

One possible simple fix would be to assign b to the address of an existing variable, for example:

int a ;
int* b = &a;

Another option would have been to use dynamic allocation via new.

For completeness sake we can see this is undefined behavior by going to the draft C++ standard section 5.3.1 Unary operators paragraph 1 which says(emphasis mine):

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.[...]

and if we then go to section 3.10 Lvalues and rvalues paragraph 1 says(emphasis mine):

An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [...]

but b does not point to a valid object.

Original Answer

You did not allocate any memory to f nor b but you used indirection on both which is undefined behavior.

Update

It is worth noting that cranking up the warning levels should have indicated this was a problem, for example using gcc -Wall gives me the following warning for this code:

warning: 'f' is used uninitialized in this function [-Wuninitialized]

The simplest fix would be to assign f to point to a valid object like so:

char a ;
char *f = &a ;

Another options would be to use dynamic allocation, if you don't have a handy reference the C FAQ is not a bad place to start.

for completeness sake, if we look at the C99 draft standard Annex J.2 Undefined behavior paragraph 1 says:

The behavior is undefined in the following circumstances:

and includes the following bullet:

The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.8, 6.8).

The value of f and b are both automatic variables and are indeterminate since they are not initialized.

It is not clear from reading the referenced sections which statement makes it undefined but section 6.5.2.5 Compound literals paragraph 17 which is part of normative text has an example with the following text which uses the same language and says:

[...]next time around p would have an indeterminate value, which would result in undefined behavior.

In the C11 draft standard the paragraph is 16.

Hohenlohe answered 8/10, 2013 at 19:50 Comment(6)
To be pedantic, that last sentence isn't relevant, as the pointers haven't been assigned any value at all. Their values are indeterminate.Rothwell
@OliCharlesworth Their values are indeterminate, let me strike that for now and rework it when I have the chance. I would consider that invalid but perhaps you are correct.Hohenlohe
Yeah, it's nitpicking. It's the word "assigned" that's the issue here.Rothwell
@ShafikYaghmour, by this do you mean that they haven't been assigned a variable? But rather just directly given a value?Perambulator
@Link I have updated the answer with a lot more details, but basically the pointers do not have a known value so by doing *f you would be accessing some indeterminate area of memory. Most likely memory your process does not have access to which in a unix like system will generate a seg fault.Hohenlohe
@OliCharlesworth you were indeed correct, the indeterminate value is stored not assigned.Hohenlohe
T
3

The pointer is valid in as much it's got a value. But the memory is probably not. It's your OS telling you that you are touching memory which isn't yours.

I'm frankly surprised it doesn't crash earlier than that.


Here's why:

int* b; // b is uninitialized.
*b = 27;

Where does b point? It might be somewhere valid, or somewhere totally off-limits. You can usually bet on the latter.

Here's a better way to do what you want.

int b1 = 27;
int *b = &b1;

Now b points to the location on the stack where b1s value is stored.

Trotter answered 22/5, 2011 at 1:48 Comment(6)
You're just telling him what a seg fault is, not really solving the problem.Superabound
@Dhaivat Pandya - he just answered the OP answer. the solution is pretty clear.Dante
Ok. So is the solution that I need to use new to make the int* hold a valid address?Submediant
Wait, so, why doesn't the second last line work? (sorry for being a thickhead)Superabound
There's probably a good reason, but it doesn't really matter. This is an undefined behavior.Dante
@magus pwnsen: I added a solution, you could use new as well, but make sure you use delete when you are done with the pointer.Trotter
I
1

This is because f is a pointer and it need to be allocated some memory for it.

Idiomatic answered 8/10, 2013 at 19:50 Comment(1)
Note the question was merged with a similar question. You probably want to update your answer to fit the new question.Hohenlohe
S
1

General rule: initialize variable before using it

char* f; is a variable. *f is usage of this variable. Like any variable, f must be initialized before usage.

Simons answered 8/10, 2013 at 20:13 Comment(1)
Note the question was merged with a similar question. You probably want to update your answer to fit the new question.Hohenlohe

© 2022 - 2024 — McMap. All rights reserved.