C++ SegFault when dereferencing a pointer for cout

2019-01-15 15:04发布

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.

5条回答
Bombasti
2楼-- · 2019-01-15 15:30

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.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-01-15 15:33

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.

查看更多
孤傲高冷的网名
4楼-- · 2019-01-15 15:40

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;
查看更多
家丑人穷心不美
5楼-- · 2019-01-15 15:43

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

查看更多
相关推荐>>
6楼-- · 2019-01-15 15:47

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.

查看更多
登录 后发表回答