try to understand the pointers maintained by a string object - c++

Ran a simple program to test the pointer in string object, got
0x1875028
Hello
0x1875058 0x1875028
Hello world!!!
0x1875028
I am trying to understand why would s.c_str() change value after erase() call but not st.c_str().
Here is the simple code:
#include <vector>
#include <unordered_map>
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
string st;
void dum() {
string s("Hello world!!!");
printf("%p\n", s.c_str());
st = s;
s.erase(6);
cout << s << endl;
printf("%p %p\n", s.c_str(), st.c_str());
}
int main(int argc,char *argv[]) {
dum();
cout << st << endl;
st.erase(6);
printf("%p\n", st.c_str());
return 0;
}

This actually depends on the version you're using. See, for example Is std::string refcounted in GCC 4.x / C++11?. When you write for two strings, a, and b
a = b;
Then there's a question of whether they're internally pointing to the same object (up until one of them is modified). So either behavior your program exhibits is not very surprising.

First of all, I think this goes under the implementation details umbrella.
I tried that with VS2013.
After you call erase(), the string pointer returned by c_str() is not changed because I think the internal string implementation just updates the end of string (changing some internal data member), instead of doing a new heap reallocation for the internal string buffer (such an operation would likely return a new pointer value).
This is a behavior that I noted both for your local s string and the global st string.
Note that the STL implementation that comes with VS2013 doesn't use COW (COW seems to be non-standard C++11 compliant), so when you copy the strings with st = s, you are doing a deep copy, so the two strings are completely independent and they point to different memory buffers storing their respective string contents. So, when you erase something from one string, this operation is in no way reflected to the other copied string.
Sample Code
#include <iostream>
#include <string>
using namespace std;
// Helper function to print string's c_str() pointer using cout
inline const void * StringPtr(const string& str)
{
// We need a const void* to make cout print a pointer value;
// since const char* is interpreted as string.
//
// See for example:
// How to simulate printf's %p format when using std::cout?
// http://stackoverflow.com/q/5657123/1629821
//
return static_cast<const void *>(str.c_str());
}
string st;
void f() {
string s{"Hello world!!!"};
cout << "s.c_str() = " << StringPtr(s) << '\n';
st = s;
s.erase(6);
cout << s << '\n';
cout << "s.c_str() = " << StringPtr(s)
<< "; st.c_str() = " << StringPtr(st) << '\n';
}
int main() {
f();
cout << st << endl;
st.erase(6);
cout << "st.c_str() = " << StringPtr(st) << '\n';
}
Output
C:\Temp\CppTests>cl /EHsc /W4 /nologo test.cpp
test.cpp
C:\Temp\CppTests>test.exe
s.c_str() = 0036FE18
Hello
s.c_str() = 0036FE18; st.c_str() = 01009A40
Hello world!!!
st.c_str() = 01009A40

Related

why pointer to a string is is giving me blank output

i am running this in vs code.
its just taking input and then it terminates.
the output is blank.
this is the output
///
PS D:\c++\string> cd "d:\c++\string" ; if ($?) { g++ chararray.cpp -o chararray } ; if ($?) { .\chararray }
uu uugg gg
///
heres the code.
#include <iostream>
using namespace std;
int main()
{
char *u;
cin.getline(u, 19);
cout << "well " << u;
}
The local buffer char *u; hasn't been initialized, it may cause a SEGV crash, since calling getline will lead to writing into the address stored in u, and it's a random value now.
It would be better to use the alternative std::getline and std::string as the target string type, then we read an arbitrary length of the string (We void buffer overflow and other kinds of memory issues):
#include <iostream>
int main() {
std::string line;
std::getline(std::cin, line);
std::cout << "well " << line;
return 0;
}
A better way would be to do some allocation of mem before you store some data there.
#include <iostream>
using namespace std;
int main()
{
char *u = new char[20];
// char u[20] = { "\0" }; // with this you do not need to delete the mem
cin.getline(u, 19);
cout << "well " << u;
delete [] u; // do not forget to free your heap memory
}

Accessing elements in a std::string with pointers

How can I access individual elements in a std::string with pointers? Is it possible without type casting to a const char *?
#include <iostream>
#include <string>
using namespace std;
int main() {
// I'm trying to do this...
string str = "This is a string";
cout << str[2] << endl;
// ...but by doing this instead
string *p_str = &str;
cout << /* access 3rd element of str with p_str */ << endl;
return 0;
}
There are two ways:
Call the operator[] function explicitly:
std::cout << p_str->operator[](2) << '\n';
Or use the at function
std::cout << p_str->at(2) << '\n';
Both of these are almost equivalent.
Or dereference the pointer to get the object, and use normal indexing:
std::cout << (*p_str)[2] << '\n';
Either way, you need to dereference the pointer. Through the "arrow" operator -> or with the direct dereference operator * doesn't matter.

STL vector containing vector causing segfault

The following code causes a segfault when I try to issue my push_back call. What am I doing wrong?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
std::string * foo = new std::string("hello world");
cout << *foo << endl;
std::vector<std::vector<std::string *> > my_vecs;
my_vecs[0].push_back(foo); // segfaults
cout << "trying to print my_vecs size of " << my_vecs.size() << " but we never reach that point due to segfault " << endl;
return 0;
}
I'm pretty sure I'm violating one of the contracts for using vector, as the problem is surely not with the STL implementation.
When you create my_vecs it has 0 elements, hence my_vecs[0] does not exists and gives segfault. You have to first reserve at least one element of my_vecs and then you can insert in the vector my_vecs[0] your pointer:
std::vector<std::vector<std::string *> > my_vecs(1);
my_vecs[0].push_back(&foo);
The outer vector must first be explicitly grown, before one can push to its elements.
This may be a little surprising since STL map's automatically insert their keys. But, it's certainly the way it is.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
const int DESIRED_VECTOR_SIZE = 1;
std::string * foo = new std::string("hello world");
cout << *foo << endl;
std::vector<std::vector<std::string *> > my_vecs;
for (int i = 0; i < DESIRED_VECTOR_SIZE; ++i) {
std::vector<std::string *> tmp;
my_vecs.push_back(tmp); // will invoke copy constructor, which seems unfortunate but meh
}
my_vecs[0].push_back(foo); // segfaults
cout << "now able to print my_vecs size of " << my_vecs.size() << endl;
return 0;
}

how to read a const char* from keyboard input and perform strlen() on it?

So I have been trying for 1.30 hour to get this to work. I am new indeed, but I have searched all over the place and couldn't find an exact answer. I do not wish to do this another way, as it would take away the entire purpose of learning to code. I have to find why this thing isn't working. I tried dozens if not hunderds of syntaxes, but nothing works.
I want to read in a const char* name, than count the number of elements in it, so I thought had to be strlen(), and than output the name and the number of elements. If that works I can write the rest of the code.
#include <iostream>
using namespace std;
int main()
{
//writing your name, and counting the characters including \0
int a;
const char* name;
a = int strlen(name);
cin.getline(name);
cout << name;
cout >> a;
return 0;
}
There are a lot of problems with your code.
You are not allocating any memory for cin.getline() to read into. const char* name; is declaring an uninitialized pointer to nothing. You have to allocate memory for name before you can then read any data into it.
cin.getline() expects two input parameters (a pointer to an allocated buffer, and the max number of characters the buffer can hold), but you are only passing in one value.
You are calling strlen() before you have read anything into name (and there is a syntax error on your strlen() statement anyway).
You are passing a to std::cout using >>, but std::ostream does not implement the >> operator. You have to use << instead.
And lastly, don't use using namespace std;.
Try this instead:
#include <iostream>
#include <cstring>
int main()
{
//writing your name, and counting the characters including \0
int a;
char name[32];
std::cin.getline(name, 32);
a = std::strlen(name);
std::cout << "You entered: " << name << std::endl;
std::cout << "It is << a << " chars in length" << std::endl;
return 0;
}
Or, if you really don't like using std:: everywhere, at least use using <identifier>; instead of using namespace std;:
#include <iostream>
#include <cstring>
using std::cin;
using std::strlen;
using std::cout;
using std::endl;
int main()
{
//writing your name, and counting the characters including \0
int a;
char name[32];
cin.getline(name, 32);
a = strlen(name);
cout << "You entered: " << name << endl;
cout << "It is " << a << " chars in length" << endl;
return 0;
}
Now, that being said, the preferred solution is to use std::getline() instead of cin.getline():
#include <iostream>
#include <string>
int main()
{
int a;
std::string name;
std::getline(std::cin, name);
a = name.length();
std::cout << "You entered: " << name << std::endl;
std::cout << "It is " << a << " chars in length" << std::endl;
return 0;
}
I found a working solution, although I don't see where I had gone wrong. But this does exactly what I want using const char* and strlen() without using std::string.
Thanks for all your help, you have all pointed me to the correct direction.
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main ()
{
const char *name;
int len;
name = "stephane";
len = strlen(name);
cout << name;
cout << len;
return(0);
}
As another user has pointed out, I think it's a good idea for you to take a few steps back and read the basics until you understand how pointers work.
A const char* is that: const. It could be used usually while doing things like this:
const char* cpName = "Stephane"; //expected not to change through the program's lifetime
char* pName = "Stephane"; //can be changed to point to something else
char *pOther = "Vada";
pName = pOther; //pName now points to the string "Vada"
cpName = pOther; //this won't compile as cpName is const

how to store the content of variable into const char*?

i have a pointer or variable which stores the address like 0xb72b218 now i have to store this value in to const char*. how i can store it. Thanks in advance.
I tried following:
suppose i have a pointer variable "ptr" which contains 0xb72b218 value
ostringstream oss;
oss << ptr;
string buf = oss.str();
const char* value = buf.c_str();
but it is more complicated any one know easy way.
Well... if you really want the address of something in a string, this will do:
#include <stdio.h>
#include <iostream>
int main(){
char buf[30];
void* ptr = /*your pointer here*/;
snprintf(buf,sizeof(buf),"%p",ptr);
std::cout << "pointer as string: " << buf << "\n";
std::cout << "pointer as value: " << ptr << "\n";
}
Or if you don't like magic numbers and want your code to work even when 256bit pointers are nothing special anymore, try this:
#include <limits> // for numeric_limits<T>
#include <stdint.h> // for intptr_t
#include <stdio.h> // for snprintf
#include <iostream>
int main(){
int i;
int* ptr = &i; // replace with your pointer
const int N = std::numeric_limits<intptr_t>::digits;
char buf[N+1]; // +1 for '\0' terminator
snprintf(buf,N,"%p",ptr);
std::cout << "pointer as string: " << buf << "\n";
std::cout << "pointer as value: " << static_cast<void*>(ptr) << "\n";
}
Example on Ideone.
OK, presumably there must some additional parameter that tells the function what type of data is actually being passed, but you can do it like this:
extern void afunc(const char *p, int type);
int value = 1234;
afunc((const char *)&value, TYPE_INT);
Have you looked at const_cast? It is a means of adding/removing const-ness from a variable in C++. Take a look here.