Can anyone explain how the following code is working and does not crash the application?
int main() {
char *tempStr = new char[5];
tempStr[0] = '\0';
string stemp = "helloworld";
stringstream sstream;
sstream.str(stemp);
cout << "len before = " << strlen(tempStr);
sstream >> tempStr;
cout << "len after = " << strlen(tempStr) << endl;
cout << tempStr << endl;
delete[] tempStr;
return 1;
}
I am getting the output as
len before = 0
len after = 10
helloworld
Did stringstream allocate memory for the extra characters in the char pointer?
Also want to know the correct way to copy data from stringstream to char* array, without exceeding the memory allocated for char*?
Did stringstream allocate memory for the extra characters in the char pointer?
No. Your code invokes undefined behavior.
Also want to know the correct way to copy data from stringstream to char* array, without exceeding the memory allocated for char*?
It is not a good idea to read into char*. Use std::string to read input from stream. But then if you still want to know for the sake of knowledge, use std::istream::read().
if ( sstream.read(tempStr, 5 ) )
{
//read succeeded
}
By the way, you can merge these two lines:
stringstream sstream;
sstream.str(stemp);
into one:
stringstream sstream(stemp);
or simply this:
stringstream sstream("helloworld"); //no need of stemp!
Hope that helps.
No. You overwrote memory, invoking undefined behavior, but nothing obvious happened, so the error went unnoticed. There is no requirement that doing something like this should trigger any kind of human-visible error or special action, thus the wording undefined behavior.
You're going to have to do it chunk by chunk, and re-allocate the char array if it runs out of space. In C++, there's little point in doing this manually. Just use std::string and be done.
Related
This question already has answers here:
How to write std::string to file?
(4 answers)
Closed 2 months ago.
I am trying to get strings from cin and than write it to binary file.
I've read that writing pure string won't work, so I tried to convert it to char*.
The following code writes it ok (...probably), but only the first 8 chars, so the output in file is incomplete.
std::string nick, ip, port;
std::cout << "IP: ";
std::cin >> ip;
std::cout << "port: ";
std::cin >> port;
ofstream file1("lastServers.bin", ios::out | ios::binary);
if (file1.good())
{
const char* p_IP = ip.c_str();
const char* p_PORT = port.c_str();
int length = sizeof(&p_IP)+sizeof(&p_PORT);
char* tmp1 = new char[length];
int index = 0;
memcpy((tmp1 + index), p_IP, sizeof(&p_IP));
index = index + sizeof(&p_IP);
memcpy((tmp1 + index), p_PORT, sizeof(&p_PORT));
file1.write(tmp1, length);
file1.close();
delete[] tmp1;
}
else
{
std::cout << "file error write" << endl;
}
Thanks in advance for any help :)
Your code can be written as
ofstream file1("lastServers.bin", ios::out | ios::binary);
if (file1.good()) {
file1.write(ip.c_str(), ip.size());
file1.write(port.c_str(), port.size());
file1.close();
}
else {
std::cout << "file error write" << endl;
}
string::c_str() returns a const pointer to the text in the string.
string::size() returns the number of characters in the string.
You don't need to concatenate the data before writing to the file, writing one then the other has the same result.
If you wanted to write C type code rather than C++, you can use strlen(p_IP) to get the length of the IP string rather than using sizeof.
The sizeof operator gives you the size of the class instance, i.e. the size of the object BUT the string object's size is never affected by the size of the string it manages.
In C++, objects that manage something (think strings managing characters, containers managing their contents, etc.) usually have a method to determine the size of what they're managing. For std::string and other STL containers that method is size().
Note that writing these strings in this format means you can't tell where one string ends and another one starts. Two options to consider are using a terminating character that you know won't appear in any strings, or writing the length of the string to the file before the text of the string itself. I won't elaborate here as it was not asked in the original question.
sizeof returns you the size of the string object in the memory, not the length of the string itself. Specifically, sizeof(&p_IP) returns the size of the pointer to p_IP, which is always 4 bytes on a 32-bit system. Your variable length simply does not compute to the correct value. To get the length of a char*, use strlen.
I'm sure this is an easy question for most but I'm having trouble trying to figure out why I can't manipulate this sting and better yet how I should go about doing it. So for example we have:
char *str1="Hello World";
All I want to do is manipulate the string that is being pointed to by 'str1'. For example, as shown below, I could output the string and see the original. Then I could add a null character in there and shorten it.
cout << str1 << '\n';
str1[5] = '\0';
cout << str1;
I've also tried:
cout << str1 << '\n';
*(str1+4) = '\0';
cout << str1;
Either way I'm hoping to see something like this:
Hello World
Hello
The error I'm getting in both cases is when I try to alter the string. I know it would be easier to just declare str1 as an array (char str1[] = ....) but I'm given the constraint of having to use the dreaded char *
String literals are stored in read-only memory. You cannot modify them. In fact, in modern C++, attempting to initialise str1 the way you did will give an error. It should be a const char*:
const char* str1 = "Hello World";
This makes it clear that you shouldn't be modifying the chars.
If you want a copy of the string that you can manipulate, you should make str1 an array:
char str1[] = "Hello World";
When you initialise an array with a string literal, the characters are copied into the array.
So after all of the help I've received from you all I went with first determining the length of the strings, initializing an array of the same size+1, and then iterating through the original to save it into an array. Then I was able to manipulate it as i pleased.
int someFunc(char *inpStr){
int counter = 0;
//Find the length of the input string
while(inpStr[counter]!='\0'){counter++;}
//Input initialize an array of same size
char strArray[counter+1];
//Copy whats in the char * to the array and make sure it ends with null
for(int i=0;i<=counter;i++){strArray[i]=*(inpStr+i);}
strArray[counter]='\0';
.....
return 0;
}
Thanks for all the help!
Why you cannot change the str1 has been explained aptly by Joseph. But still if you want to modify it you can use something like this:
char *str = "hello";
char *ptr = new char[strlen(str)+1];
strcpy(ptr,str);
ptr[2] = 'd';
str = ptr;
I hope this solves your problem.
So given:
struct MemoryStruct {
char *memory;
size_t size;
};
char* memory holds a curl return, XML doc.
I am doing:
if(chunk.memory) {
std::cout << "char size is " << sizeof(chunk.memory) << std::endl;
std::string s = "";
for (int c = 0; c<sizeof(chunk.memory); c++) {
s.push_back(chunk.memory[c]);
}
std::cout << "s: " << s.c_str() << std::endl;
}
I am only getting back <?xm
So sizeof() I think is return the total bytes in the char*
How do I get what the actual value is a char*. So basically the whole curl return. Which is 5 lines of XML?
sizeof(chunk.memory) will give always you size of a pointer which in your case seems to be 4. That's why you see only 4 characters in your std::string.
If your curl return or whatever else is terminated by \0, then you can directly do the following
std::string s(chunk.memory);
If your char * is not terminated by \0, then you need to know the length of the string - you cannot use sizeof(chunk.memory) for this. If your chunk.size contains the correct size, then you can use
std::string s(chunk.memory, chunk.size);
std::string constructor can accept char* and data length (see the docs); Example:
std::string s(chunk.memory, chunk.size);
So container will pre-allocate need space for your string and initialize with it.
In MemoryStruct memory is the pointer to the first returned character and size is the number of characters returned. You want to initialize a string with this data so you will need to do:
s.assign(chunk.memory, chunk.size);
everybody I have problem with string concatenation in C++, here is my code
map<double, string> fracs;
for(int d=1; d<=N; d++)
for(int n=0; n<=d; n++)
if(gcd(n, d)==1){
string s = n+"/"+d;// this does not work in C++ but works in Java
fracs.insert(make_pair((double)(n/d), s));
}
How can I fix my code?
Try like this.
stringstream os;
os << n << "/" << d;
string s =os.str();
In C++ you have to convert an int to a string before you can concatenate it with another string using the + operator.
See Easiest way to convert int to string in C++.
Use streams, in your case, a stringstream:
#include <sstream>
...
std::stringstream ss;
ss << n << '/' << d;
Later, when done with your work, you can store it as an ordinary string:
const std::string s = ss.str();
Important (side-) note: Never do
const char *s = ss.str().c_str();
stringstream::str() produces a temporary std::string, and according to the standard, temporaries live until the end of the expression. Then, std::string::c_str() gives you a pointer to a null-terminated string, but according to The Holy Law, that C-style-string becomes invalid once the std::string (from which you receved it) changes.
It might work this time, and next time, and even on QA, but explodes right in the face of your most valuable customer.
The std::string must survive until the battle is over:
const std::string s = ss.str(); // must exist as long as sz is being used
const char *sz = s.c_str();
n and d are integers. Here is how you can convert integer to string:
std::string s;
std::stringstream out;
out << n << "/" << d;
s = out.str();
You could use a stringstream.
stringstream s;
s << n << "/" << d;
fracs.insert(make_pair((double)n/d, s.str()));
No one has suggested it yet but you can also take a look at boost::lexical_cast<>.
While this method is sometimes criticized because of performance issues, it might be ok in your situation, and it surely makes the code more readable.
Unlike in Java, in C++ there is no operator+ that explicitly converts a number to a string. What is usually done in C++ in cases like this is...
#include <sstream>
stringstream ss;
ss << n << '/' << d; // Just like you'd do with cout
string s = ss.str(); // Convert the stringstream to a string
I think sprintf(), which is a function used to send formatted data to strings, would be a much clearer way to do it. Just the way you would use printf, but with the c-style string type char* as a first(additional) argument:
char* temp;
sprint(temp, "%d/%d", n, d);
std::string g(temp);
You could check it out at http://www.cplusplus.com/reference/cstdio/sprintf/
How would you get the size input string to console or size of valid characters in buffer?
char buffer[100];
cin >> buffer;
I'm looking to put the '\0' where the input ends.
Prefer using std::string, instead of char* or char[]. That makes such things easy! The problem with char buffer[100] is that if the size of input string is more than 100, then your cin >> buffer would invoke undefined behavior, as it would attempt to write beyond the array. This problem can easily be avoided if you use std::string.
std::string input;
cin >> input; //this can read string of any unknown size!
cout << "length of input string : " << input.size()<< endl;
You can also use input.length() instead of input.size(). They return the same value.
Online Demo : http://www.ideone.com/Wdo31
The question is moot. When the user types more than 100 characters, you have a buffer overrun. You may crash. If not, you got a security issue at best. You shouldn't do this. Read the input a character at a time, or use a safer string library. gets_s comes to mind if it's supported on your platform.
But in answer to your question, this might be what you need:
char buffer[100] = {}; // zero-init the entire array
int length = 0;
cin >> buffer;
length = strlen(buffer); // length is the length of the string
You don't need to (and quite possibly, can't). Instead, use a std::string instead of a char buffer.