简体   繁体   中英

Why does cout << *s << endl produce a segfault?

I have this question on a practice exam for my C++ class, we're supposed to write what the output is or if it produces an error. Running this code produces a segmentation fault, but can someone explain why? It looks fine to me.

    string *s;
    s = (string *) "This is my house. I have to defend it.";
    cout << *s << endl;

Indirecting through a pointer of type std::string* when it doesn't point to an object of type std::string has undefined behaviour.

A string literal is not an object of type std::string . String literal is an array of characters. std::string is a class defined in the header <string> .

Running this code produces a segmentation fault, but can someone explain why?

You indirect through a pointer that doesn't point to an object of compatible type. The behaviour of your program is undefined.


PS It is never necessary to use C-style cast (such as (type)expression ). It can easily suppress helpful compilation errors and replace them with undefined behaviour. It should be avoided.

If you hadn't used a C-style cast here, then the type system would have alerted you to the mistake before getting to run the program. In this case, you might have seen an error message similar to:

error: cannot convert 'const char [39]' to 'std::string*' {aka 'std::basic_string<char>*'} in assignment

helping you realise that the types do not match.

You need to learn the difference between a string literal and class std::string .

Casting a string literal to std::string* is undefined behaviour. Which manifests itself here as a segmentation fault when the code does *s because s is invalid.

Without that C-style cast (string *) in s = (string *) "T..."; the compiler would emit an error.

Always question those C-style casts in C++.

The likely problem (or at least one of the problems) is the fact that s has no memory allocated to it. You need to use the new keyword and try something like this:

string *s;
s = new string("This is my house. I have to defend it.");
cout << *s << endl;

Of course, in theory you'd need to use delete too.

std::string tends to boil down to something that looks like this:

struct string
{
  char* _begin;
  char* _end;
  char* _capacity;
};

The text string you have defined would look like this:

const char* const text = "This is my house. I have to defend it."

So you are casting from type (char*), to type (string*). This now means that _begin will store the memory location "This is " , and _end will store the memory location "my house"

When printing the string to std::cout, it will dereference the pointer to s, and try to find the string size, usually implemented like so:

size_t string::size() const { return _end - _begin; }

Given that _begin and _end aren't storing pointer values (they are just random bits of text), this will result in cout trying to print a very wrong number of characters _(because the memory locations in _begin and end are a nonsense)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM