Does "&S[0]" Point to Contiguous Characters in a Std::String

Does &s[0] point to contiguous characters in a std::string?

A std::string's allocation is not guaranteed to be contiguous under the C++98/03 standard, but C++11 forces it to be. In practice, neither I nor Herb Sutter know of an implementation that does not use contiguous storage.

Notice that the &s[0] thing is always guaranteed to work by the C++11 standard, even in the 0-length string case. It would not be guaranteed if you did str.begin() or &*str.begin(), but for &s[0] the standard defines operator[] as:

Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type T with value charT(); the referenced value shall not be modified

Continuing on, data() is defined as:

Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].

(notice the square brackets at both ends of the range)


Notice: pre-standardization C++0x did not guarantee &s[0] to work with zero-length strings (actually, it was explicitly undefined behavior), and an older revision of this answer explained this; this has been fixed in later standard drafts, so the answer has been updated accordingly.

Does std::string need to store its character in a contiguous piece of memory?

The C++11 standard, basic_string 21.4.1.5,

The char-like objects in a basic_string object shall be stored
contiguously. That is, for any basic_string object s, the identity
&*(s.begin() + n) == &*s.begin() + n shall hold for all values of n
such that 0 <= n < s.size().

How to convert a std::string to const char* or char*

If you just want to pass a std::string to a function that needs const char* you can use

std::string str;
const char * c = str.c_str();

If you want to get a writable copy, like char *, you can do that with this:

std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0

// don't forget to free the string after finished using it
delete[] writable;

Edit: Notice that the above is not exception safe. If anything between the new call and the delete call throws, you will leak memory, as nothing will call delete for you automatically. There are two immediate ways to solve this.

boost::scoped_array

boost::scoped_array will delete the memory for you upon going out of scope:

std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = '\0'; // don't forget the terminating 0

// get the char* using writable.get()

// memory is automatically freed if the smart pointer goes
// out of scope

std::vector

This is the standard way (does not require any external library). You use std::vector, which completely manages the memory for you.

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()

std::string to char*

It won't automatically convert (thank god). You'll have to use the method c_str() to get the C string version.

std::string str = "string";
const char *cstr = str.c_str();

Note that it returns a const char *; you aren't allowed to change the C-style string returned by c_str(). If you want to process it you'll have to copy it first:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

Or in modern C++:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);

Get all N consecutive characters in string using stringstream in C++

With C++17 you can do it like this, which is way more readable:

void update(std::string_view s, int size) {
const int iterations = s.size() - size;
for (int i = 0; i <= iterations; i++) {
std::cout << s.substr(i, size) << "\n";
}
}

string_view is made exactly for this purpose, for fast read access to a string. string_view::substr is const complexity while string::substr is linear.

As a side note, besides what Nick mentioned, your code has few other small problems:

  • std::endl fflushes the stream, it heavily impacts performance. Here you could just use '\n' to make a newline.
  • the return at the end is absolutely redundant, void functions do not require returns
  • what is the purpose of templating this? This will easily bloat your code without any measurable performance increase. Just pass the N as a parameter.
  • also your main is declared as void and should be int (even more so as you do return a value at the end)

how does one securely clear std::string?

Based on the answer given here, I wrote an allocator to securely zero memory.

#include <string>
#include <windows.h>

namespace secure
{
template <class T> class allocator : public std::allocator<T>
{
public:

template<class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator &) throw() {}
template <class U> allocator(const allocator<U>&) throw() {}

void deallocate(pointer p, size_type num)
{
SecureZeroMemory((void *)p, num);
std::allocator<T>::deallocate(p, num);
}
};

typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;
}

int main()
{
{
secure::string bar("bar");
secure::string longbar("bDoes "&S[0]" Point to Contiguous Characters in a Std::StringDoes "&S[0]" Point to Contiguous Characters in a Std::StringDoes "&S[0]" Point to Contiguous Characters in a Std::StringDoes "&S[0]" Point to Contiguous Characters in a Std::Stringaaaaar");
}
}

However, it turns out, depending on how std::string is implemented, it is possible that the allocator isn't even invoked for small values. In my code, for example, the deallocate doesn't even get called for the string bar (on Visual Studio).

The answer, then, is that we cannot use std::string to store sensitive data. Of course, we have the option to write a new class that handles the use case, but I was specifically interested in using std::string as defined.

Thanks everyone for your help!

How to get the real and total length of char * (char array)?

You can't. Not with 100% accuracy, anyway. The pointer has no length/size but its own. All it does is point to a particular place in memory that holds a char. If that char is part of a string, then you can use strlen to determine what chars follow the one currently being pointed to, but that doesn't mean the array in your case is that big.

Basically:

A pointer is not an array, so it doesn't need to know what the size of the array is. A pointer can point to a single value, so a pointer can exist without there even being an array. It doesn't even care where the memory it points to is situated (Read only, heap or stack... doesn't matter). A pointer doesn't have a length other than itself. A pointer just is...

Consider this:

char beep = '\a';
void alert_user(const char *msg, char *signal); //for some reason
alert_user("Hear my super-awsome noise!", &beep); //passing pointer to single char!

void alert_user(const char *msg, char *signal)
{
printf("%s%c\n", msg, *signal);
}

A pointer can be a single char, as well as the beginning, end or middle of an array...

Think of chars as structs. You sometimes allocate a single struct on the heap. That, too, creates a pointer without an array.

Using only a pointer, to determine how big an array it is pointing to is impossible. The closest you can get to it is using calloc and counting the number of consecutive \0 chars you can find through the pointer. Of course, that doesn't work once you've assigned/reassigned stuff to that array's keys and it also fails if the memory just outside of the array happens to hold \0, too. So using this method is unreliable, dangerous and just generally silly. Don't. Do. It.

Another analogy:

Think of a pointer as a road sign, it points to Town X. The sign doesn't know what that town looks like, and it doesn't know or care (or can care) who lives there. It's job is to tell you where to find Town X. It can only tell you how far that town is, but not how big it is. That information is deemed irrelevant for road-signs. That's something that you can only find out by looking at the town itself, not at the road-signs that are pointing you in its direction

So, using a pointer the only thing you can do is:

char a_str[] = "hello";//{h,e,l,l,o,\0}
char *arr_ptr = &a_str[0];
printf("Get length of string -> %d\n", strlen(arr_ptr));

But this, of course, only works if the array/string is \0-terminated.

As an aside:

int length = sizeof(a)/sizeof(char);//sizeof char is guaranteed 1, so sizeof(a) is enough

is actually assigning size_t (the return type of sizeof) to an int, best write:

size_t length = sizeof(a)/sizeof(*a);//best use ptr's type -> good habit

Since size_t is an unsigned type, if sizeof returns bigger values, the value of length might be something you didn't expect...



Related Topics



Leave a reply



Submit