How do I concatenate Strings with C/C++?
I tried the following ways:
PS: errorInfo is a char * I should return it.
errorInfo = strcat("Workflow: ", strcat(
workflowToString(workflow).utf8(), strcat(" ERROR: ",
errorCode.utf8)));
sprintf(errorInfo, "Workflow %s ERROR: %s",
workflowToString(workflow).utf8(), errorCode.utf8());
errorInfo = "Workflow: " + workflowToString(workflow).utf8() + " ERROR: " + errorCode.utf8;
Just the sprintf compiles but when running my application crash.
PS: I'm using NDK from Android
There ISN'T such a language as C/C++. There is C, and there is C++.
In C++ you concatenate std::string's by using operator+
In C, you use strcat
I know this doesn't quite answer your question, this is just an outcry :)
According to this page strcat does the following:
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a new null-character is appended at the end of the new string formed by the concatenation of both in destination.
In your implementation, however, "Workflow: " is a constant string. You cannot modify that string, which is what strcat would do. In order to do that, create a string like:
char message[1000];
strcpy(message, "Workflow: ");
strcat(message, "other string");
....
However, be careful about the utf8 character encoding because one utf8 code point could be multiple chars long.
Concatenation is almost always the wrong idiom for string building, especially in C. It's error-prone, clutters your code, and has extremely bad asymptotic performance (i.e. O(n^2) instead of O(n) for building a string of length n).
Instead you should use the snprintf function, as in:
snprintf(buf, sizeof buf, "Workflow: %s ERROR: %s", workflow, error);
or if you're writing to a file/socket/etc. and don't need to keep the resulting string in memory, simply use fprintf to begin with.
With string literals you can simple use:
char str[] = "foo" " bar";
const char *s = " 1 " " 2 ";
s = " 3 " " 4 ";
By using strcat(), you are working in c, not c++.
c is not going to automatically manage memory for you.
c can be confusing since sometimes it seems like it has a string data type when all it is doing is providing you a string interface to arrays of characters.
For one thing, the first argument to strcat() has to be writable and have enough room to add the second string.
char *out = strcat("This", "nThat");
is asking c to stomp on string literal memory.
In general, you should NEVER use strcat()/sprintf, as in the above "chosen" answer. You can overwrite memory that way. Use strncat()/snprintf() instead to avoid buffer overruns. If you don't know the size to pass to "n" in strncat(), you're likely doing something wrong.
One way to do this in c would be:
#define ERROR_BUF_SIZE 2048 // or something big enough, you have to know in c
char errorInfo[ERROR_BUF_SIZE];
snprintf(errorInfo, ERROR_BUF_SIZE, "Workflow %s ERROR: %s",
workflowToString(workflow).utf8(), errorCode.utf8());
or similarly using strncpy/strncat
There are many ways you can concatenate in C while using Android NDK:
Two ways I used are:
strcat
sprintf
here is example:
enter code here
strcat
char* buffer1=(char*)malloc(250000);
char* buffer2=(char*)malloc(250000);
char* buffer3=(char*)malloc(250000);
buffer1 = strcat(buffer1, buffer2);
sprintf
sprintf(buffer3,"this is buffer1: %s and this is buffer2:%s",buffer1,buffer2);`
sprintf returns length of your string
strcat is not recommended as its use more memory..
you can use sprintf or others like strcpy.
Hope it helps.
Related
If I want to construct a std::string with a line like:
std::string my_string("a\0b");
Where i want to have three characters in the resulting string (a, null, b), I only get one. What is the proper syntax?
Since C++14
we have been able to create literal std::string
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
Before C++14
The problem is the std::string constructor that takes a const char* assumes the input is a C-string. C-strings are \0 terminated and thus parsing stops when it reaches the \0 character.
To compensate for this, you need to use the constructor that builds the string from a char array (not a C-String). This takes two parameters - a pointer to the array and a length:
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
Note: C++ std::string is NOT \0-terminated (as suggested in other posts). However, you can extract a pointer to an internal buffer that contains a C-String with the method c_str().
Also check out Doug T's answer below about using a vector<char>.
Also check out RiaD for a C++14 solution.
If you are doing manipulation like you would with a c-style string (array of chars) consider using
std::vector<char>
You have more freedom to treat it like an array in the same manner you would treat a c-string. You can use copy() to copy into a string:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
and you can use it in many of the same places you can use c-strings
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Naturally, however, you suffer from the same problems as c-strings. You may forget your null terminal or write past the allocated space.
I have no idea why you'd want to do such a thing, but try this:
std::string my_string("a\0b", 3);
What new capabilities do user-defined literals add to C++? presents an elegant answer: Define
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
then you can create your string this way:
std::string my_string("a\0b"_s);
or even so:
auto my_string = "a\0b"_s;
There's an "old style" way:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
then you can define
std::string my_string(S("a\0b"));
The following will work...
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
You'll have to be careful with this. If you replace 'b' with any numeric character, you will silently create the wrong string using most methods. See: Rules for C++ string literals escape character.
For example, I dropped this innocent looking snippet in the middle of a program
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
Here is what this program output for me:
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
That was my first print statement twice, several non-printing characters, followed by a newline, followed by something in internal memory, which I just overwrote (and then printed, showing that it has been overwritten). Worst of all, even compiling this with thorough and verbose gcc warnings gave me no indication of something being wrong, and running the program through valgrind didn't complain about any improper memory access patterns. In other words, it's completely undetectable by modern tools.
You can get this same problem with the much simpler std::string("0", 100);, but the example above is a little trickier, and thus harder to see what's wrong.
Fortunately, C++11 gives us a good solution to the problem using initializer list syntax. This saves you from having to specify the number of characters (which, as I showed above, you can do incorrectly), and avoids combining escaped numbers. std::string str({'a', '\0', 'b'}) is safe for any string content, unlike versions that take an array of char and a size.
In C++14 you now may use literals
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Better to use std::vector<char> if this question isn't just for educational purposes.
anonym's answer is excellent, but there's a non-macro solution in C++98 as well:
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
With this function, RawString(/* literal */) will produce the same string as S(/* literal */):
std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
Additionally, there's an issue with the macro: the expression is not actually a std::string as written, and therefore can't be used e.g. for simple assignment-initialization:
std::string s = S("a\0b"); // ERROR!
...so it might be preferable to use:
#define std::string(s, sizeof s - 1)
Obviously you should only use one or the other solution in your project and call it whatever you think is appropriate.
I know it is a long time this question has been asked. But for anyone who is having a similar problem might be interested in the following code.
CComBSTR(20,"mystring1\0mystring2\0")
Almost all implementations of std::strings are null-terminated, so you probably shouldn't do this. Note that "a\0b" is actually four characters long because of the automatic null terminator (a, null, b, null). If you really want to do this and break std::string's contract, you can do:
std::string s("aab");
s.at(1) = '\0';
but if you do, all your friends will laugh at you, you will never find true happiness.
This question already has answers here:
How to construct a std::string with embedded values, i.e. "string interpolation"?
(8 answers)
Closed 2 years ago.
I am currently learning C++ and I cannot find how to create a string with a formatter to take multiple parameters such as using sprintf but for an unknown string length.
What I want do is something like
string myString = string.format("Hello, here is %s %s and another %s", par1, par2, par3);
I know in C there is the asprintf function where it works out how long the string will be and it malloc's the memory and you need to free it when finished, however, this doesn't seem to be available for C++, although sprintf is. Everything I've seen on google about asprintf seems to mostly focus on Linux, whereas I need cross platform.
Everything I've seen about C++ and string formatting you need to define a char array of fixed length and use sprintf, but I am not going to know the length of the string so I can't do this.
In addition to the existing excellent answer, you may consider the Boost Format library.
Example:
std::string myString = str(boost::format("Hello, here is %s %s an another %s") % par1 % par2 % par3);
Get the book The Standard C++ Library by Josuttis. It will give you the complete string interface and much, much more. You appear to be thinking C, not C++. You could of course use a C interface like sprintf() to load a
char[] and then copy that to a C++ string. That is usually a bad idea.
Two ways to do what you ask:
string myString("Hello, here is ");
myString += par1;
myString += " ";
myString += par2;
myString += " and another ";
myString += par3;
stringstream foo;
foo << "Hello, here is " << par1 << " " << par2 << " and another " << par3;
string myString(foo.str());
There are lots of answers.
As C++ strings get very long, you want to use the std::stringstream to build them. This allows you to write to a string as though it were a file in memory, and it is written to handle very large strings efficiently. The C function snprintf() returns the number of characters it would have written if passed a null pointer. So you need to call it twice, once to get the size, then allocate the buffer and call again to format. It's a good solution for strings which are expected to be quite short and with a defined format, but might get arbitrarily long, like a string containing someone's name.
Note that printf() formats are convenient and easy to use for basic output of integers, string, and reals, but they don't scale up to user-defined objects because there's no accepted way of writing a toString() method and destroying the string after the call. They also can't handle arrays of objects. There is an accepted convention that overloading << writes a text representation of an object to a stream.
I'm trying to open a file whose name is composed by constant and variable parts.
My actual code is
char filename[100];
char extension1[] = ".pdb";
vector<string> id;
//code to find the ids(it works)
sprintf(filename, "/home/giovanni/Scrivania/enzimi/ligan/%s", id[1].c_str());
sprintf(filename, "%s%s", filename,extension1);
The problem is that filenames becomes
.pdbe/giovanni/Scrivania/enzimi/ligan/102M
instead of
/home/giovanni/Scrivania/enzimi/ligan/102M.pdb
Simply use std::string:
string filename = "/home/giovanni/Scrivania/enzimi/ligan/" + id[1] + ".pdb";
...
std::ifstream file(filename.c_str());
Simply using this code would do (sprintf takes variable number of arguments):
sprintf(filename,"/home/giovanni/Scrivania/enzimi/ligan/%s%s", id[1].c_str(), extension1);
But, as you are using C++, Doing it in C style is not preferable. sprintf() can cuase buffer overflows and you can you safer version snprintf(). Best option would be to use std::string
C99 and POSIX.1-2001 specify that the results are undefined if a call to sprintf()/snprintf would cause copying to take place between objects that overlap (e.g., if the target string array and one of the supplied input arguments refer to the same buffer).
So line sprintf(filename, "%s%s", filename,extension1) is illegal.
You can try other options like std::string.
Watch Out For Buffer Overflow!
You need to append to the existing string; you need to know the number of characters in it, then offset the pointer you pass in to the second call to sprintf:
int len = sprintf(filename, "/home/giovanni/Scrivania/enzimi/ligan/%s", id[1].c_str());
sprintf(filename + len, "%s", extension1);
(sprintf returns the number of characters written into the buffer, but does not include the NUL terminator.)
Note that the second call to sprintf only has one "%s".
In my code, I have a string variable named ChannelPacket.
when I print Channelpacket in gdb, it gives following string :
"\020\000B\001\237\246&\b\000\016\000\002\064\001\000\000\005\000\021\002\000\000\006\000\f\001\001\000\000sZK"
But if i print Channelpacket.c_str(), it gives just "\020 output.
Please help me.
c_str() returns a pointer to char that's understood to be terminated by a NUL character ('\0').
Since your string contains an embedded '\0', it's seen as the end of the string when viewed as a pointer to char.
When viewed as an actual std::string, the string's length is known, so the whole thing is written out, regardless of the embedded NUL characters.
The second byte is a zero, which means the end of the string. If you want to output the raw bytes, rather than treating them as a null-terminated string, you can't use cout << Channelpacket.c_str() - use cout << Channelpacket instead.
Why does the C++ standard allow the following?
#include <iostream>
#include <string>
int main()
{
std::string s(10, '\0'); // s.length() now is 10
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
s.append(5, '\0'); // s.length() now is 15
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
// the same with += char and push_back
// but:
s += "hello"; // s.length() returns 20 string is "hello"
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
return 0;
}
Why does it add 0 and count it?
It looks like broken integrity of string, doesn't it? But I checked standard and it is correct behavior.
Why does standard allows following?
Because the people designing C++ strings decided that such things should be allowed. I'm not sure if anyone that was part of the team that designed C++ strings are on SO... But since you yourself say that the standard allows it, that's the way it is, and I doubt it's about to change.
It's sometimes quite practical to have a string that can contain "anything". I can think of a few instances when I've had to work around the fact that C style strings can't contain zero-bytes. Along with the fact that long C style strings take a long time to find the length of, the main benefit of C++ strings is that they are not restricted to "what you can put in them" - that's a good thing in my book.
Not sure what is problem here.
Adding '\0' in the middle of the std::string changes nothing - null character is treated like any other. The only thing that can change is if you use .c_str() with function that accepts null-terminated strings. But then it's not problem of .c_str(), only with the function that treats '\0' specially.
If you want to know how many characters has this string as if treated like null-terminated string, use
size_t len = strlen(s.c_str());
Note that it's O(n) operation, because that's how strlen works.
If you ask why += operator doesn't add the implicit null character of string literal "hello" to the string, I say the reverse (adding it) is unclear and definitely not what you want 99% of the time. On the other hand, if you want to add '\0' to your string, just append it like a buffer:
char buffer[] = "Hello";
s.append(buffer, sizeof(buffer));
or (even better) drop the char arrays and null-terminated strings altogether and use C++-style replacements like std::string as NTS-replacement, std::vector<char> as contiguous buffer, std::vector as dynamic array with pointers replacement, and std::array (C++11) as standard C array replacement.
Also, (as mentioned by #AdamRosenfield in comments), your string after adding "hello" does have in fact 20 characters, it's probably only that your terminal doesn't print nulls.
NUL char '\0' is the ending character for c style string, not std::strings. However, it supports this character to get values from a const char pointer so that it can find the end of a c-style string. Otherwise, it is treated just like other characters
std::string is more of a container for characters than anything else and \0 is a character. As a real world example, take a look at the CreateProcess function in Windows. The lpEnvironment parameter takes a null-terminated block of null-terminated strings (i.e. A=1\0B=2\0C=3\0\0). If you're building a block it's convenient to use an std::string.