strncpy to already created char [] - c++

There is class
class Cow{
char name[20];
char* hobby;
double weight;
public:
[..]
Cow & operator=(const Cow &c);
[..]
};
and I'm wondering how to write definition of operator= method.
I wrote definition that equal to -
Cow & Cow::operator=(const Cow &c){
if(this==&c)
return *this;
delete [] hobby;
hobby=new char [strlen(c.hobby)+1];
weight=c.weight;
strncpy(name,c.name,20);
return *this;
}
but what if there is already created name[20] with like "Philip Maciejowsky" and I strncpy to it "Adam". After operator=(...) will name equal to "adamlip Maciejowsky"?
How to fix it if it overwrites like that?

Use strcpy() or add a null terminator after using strncpy(). strncpy() does not add the null terminator (\0), where as strcpy() does.
My advice: use std::string instead of c-styled null terminated string.
when in rome, do the romans!
From http://cplusplus.com
No null-character is implicitly appended at the end of destination if source is longer than >num (thus, in this case, destination may not be a null terminated C string).
Since Adam is lesser in length than Philip Maciejowsky - the strncpy() will NOT pad the remaining destination(that is Philip Maciejowsky) with \0. And hence the output looks like:
Adamip Maciejowsky - strcpy() or doing memset(destination, 0, lengthOfDestination) and then calling strncpy() will result in your output being Adam as well. Multiple ways to do what you're trying to do.

First, if you're using C++ you shouldn't be using C-style strings and should instead be using the class std::string which makes everything easier in every way.
Assuming you're required to use char* strings, strncpy takes care of this. C-style string are null-terminated, meaning that a string such as "test" takes up five bytes. The bytes are, in order, {'t', 'e', 's', t', 0}. The zero (or null) byte serves as a marker that the end of the string has been reached.
From the manpage for strncpy on my system:
The following sets chararray to abc\0\0\0:
char chararray[6];
(void)strncpy(chararray, "abc", sizeof(chararray));
So this means that the string will contain "adam\0\0\0\0\0\0\0[etc.]" where \0 represents the null byte. String functions will stop processing when they read the first null (because, remember, with C-style strings, there's no way to know the length of the string without scanning through it looking for \0).

Related

in the C ++ stl, does the string container actually contain a string with a closing 0? [duplicate]

Will the below string contain the null terminator '\0'?
std::string temp = "hello whats up";
No, but if you say temp.c_str() a null terminator will be included in the return from this method.
It's also worth saying that you can include a null character in a string just like any other character.
string s("hello");
cout << s.size() << ' ';
s[1] = '\0';
cout << s.size() << '\n';
prints
5 5
and not 5 1 as you might expect if null characters had a special meaning for strings.
Not in C++03, and it's not even guaranteed before C++11 that in a C++ std::string is continuous in memory. Only C strings (char arrays which are intended for storing strings) had the null terminator.
In C++11 and later, mystring.c_str() is equivalent to mystring.data() is equivalent to &mystring[0], and mystring[mystring.size()] is guaranteed to be '\0'.
In C++17 and later, mystring.data() also provides an overload that returns a non-const pointer to the string's contents, while mystring.c_str() only provides a const-qualified pointer.
This depends on your definition of 'contain' here. In
std::string temp = "hello whats up";
there are few things to note:
temp.size() will return the number of characters from first h to last p (both inclusive)
But at the same time temp.c_str() or temp.data() will return with a null terminator
Or in other words int(temp[temp.size()]) will be zero
I know, I sound similar to some of the answers here but I want to point out that size of std::string in C++ is maintained separately and it is not like in C where you keep counting unless you find the first null terminator.
To add, the story would be a little different if your string literal contains embedded \0. In this case, the construction of std::string stops at first null character, as following:
std::string s1 = "ab\0\0cd"; // s1 contains "ab", using string literal
std::string s2{"ab\0\0cd", 6}; // s2 contains "ab\0\0cd", using different ctr
std::string s3 = "ab\0\0cd"s; // s3 contains "ab\0\0cd", using ""s operator
References:
https://akrzemi1.wordpress.com/2014/03/20/strings-length/
http://en.cppreference.com/w/cpp/string/basic_string/basic_string
Yes if you call temp.c_str(), then it will return null-terminated c-string.
However, the actual data stored in the object temp may not be null-terminated, but it doesn't matter and shouldn't matter to the programmer, because when then programmer wants const char*, he would call c_str() on the object, which is guaranteed to return null-terminated string.
With C++ strings you don't have to worry about that, and it's possibly dependent of the implementation.
Using temp.c_str() you get a C representation of the string, which will definitely contain the \0 char. Other than that, i don't really see how it would be useful on a C++ string
std::string internally keeps a count of the number of characters. Internally it works using this count. Like others have said, when you need the string for display or whatever reason, you can its c_str() method which will give you the string with the null terminator at the end.

Why does std::string("\x00") report length of 0?

I have a function which needs to encode strings, which needs to be able to accept 0x00 as a valid 'byte'. My program needs to check the length of the string, however if I pass in "\x00" to std::string the length() method returns 0.
How can I get the actual length even if the string is a single null character?
std::string is perfectly capable of storing nulls. However, you have to be wary, as const char* is not, and you very briefly construct a const char*, from which you create the std::string.
std::string a("\x00");
This creates a constant C string containing only the null character, followed by a null terminator. But C strings don't know how long they are; so the string thinks it runs until the first null terminator, which is the first character. Hence, a zero-length string is created.
std::string b("");
b.push_back('\0');
std::string is null-clean. Characters (\0) can be the zero byte freely as well. So, here, there is nothing stopping us from correctly reading the data structure. The length of b will be 1.
In general, you need to avoid constructing C strings containing null characters. If you read the input from a file directly into std::string or make sure to push the characters one at a time, you can get the result you want. If you really need a constant string with null characters, consider using some other sentinel character instead of \0 and then (if you really need it) replace those characters with '\0' after loading into std::string.
You're passing in an empty string. Use std::string(1, '\0') instead.
Or std::string{ '\0' } (thanks, #zett42)
With C++14, you can use a string literal operator to store strings with null bytes:
using namespace std::string_literals;
std::string a = "\0"s;
std::string aa = "\0\0"s; // two null bytes are supported too

Get the length of a string containing Null terminated string

I'm using the XOR encryption so when I'm going to decrypt my string I need to get the length of that string.
I tried in this way:
string to_decode = "abcd\0lom";
int size = to_decode.size();
or in this way:
string to_decode = "abcd\0lom";
int size = to_decode.lenght();
Both are wrong because the string contain \0.
So how can I have the right length of my string?
The problem is with the initialisation, not with the size. If you use the constructor taking a const char *, it interprets that argument as a NUL-terminated string. So your std::string is only initialised with the string abcd.
You need to use a range-based constructor:
const char data[] = "abcd\0lom";
std::string to_decode(data, data + (sizeof data) - 1); // -1 to not include terminating NUL
[Live example]
However, be careful with such strings. While std::string can deal with embedded NULs perfectly fine, the result of c_str() will behave as "truncated" as far as all NUL-terminated APIs are concerned.
When you initialize the std::string, with a \0 in the middle, you loose all data ahead of it. If you think about it, a std::string is just a wrapper for a char*, and that gets terminated by a null termination \0. If the \0, doesn't have any meaning in the string, then you could escape it, like this:
string to_decode = "abcd\\0lom";
and the size would be 9. Otherwise, you could a container (eg: std::vector), of char's for the data storage
As others have said, the problem is that the code uses the constructor that takes const char*, and that only copies up to the \0. But, by a very strange coincidence, std::string has a constructor that can handle that case:
const char text[] = "abcd\0lom";
std::string to_decode(text, sizeof(text) - 1);
int size = to_decode.size();
The constructor will copy as many characters as you tell it to.

Does std::string have a null terminator?

Will the below string contain the null terminator '\0'?
std::string temp = "hello whats up";
No, but if you say temp.c_str() a null terminator will be included in the return from this method.
It's also worth saying that you can include a null character in a string just like any other character.
string s("hello");
cout << s.size() << ' ';
s[1] = '\0';
cout << s.size() << '\n';
prints
5 5
and not 5 1 as you might expect if null characters had a special meaning for strings.
Not in C++03, and it's not even guaranteed before C++11 that in a C++ std::string is continuous in memory. Only C strings (char arrays which are intended for storing strings) had the null terminator.
In C++11 and later, mystring.c_str() is equivalent to mystring.data() is equivalent to &mystring[0], and mystring[mystring.size()] is guaranteed to be '\0'.
In C++17 and later, mystring.data() also provides an overload that returns a non-const pointer to the string's contents, while mystring.c_str() only provides a const-qualified pointer.
This depends on your definition of 'contain' here. In
std::string temp = "hello whats up";
there are few things to note:
temp.size() will return the number of characters from first h to last p (both inclusive)
But at the same time temp.c_str() or temp.data() will return with a null terminator
Or in other words int(temp[temp.size()]) will be zero
I know, I sound similar to some of the answers here but I want to point out that size of std::string in C++ is maintained separately and it is not like in C where you keep counting unless you find the first null terminator.
To add, the story would be a little different if your string literal contains embedded \0. In this case, the construction of std::string stops at first null character, as following:
std::string s1 = "ab\0\0cd"; // s1 contains "ab", using string literal
std::string s2{"ab\0\0cd", 6}; // s2 contains "ab\0\0cd", using different ctr
std::string s3 = "ab\0\0cd"s; // s3 contains "ab\0\0cd", using ""s operator
References:
https://akrzemi1.wordpress.com/2014/03/20/strings-length/
http://en.cppreference.com/w/cpp/string/basic_string/basic_string
Yes if you call temp.c_str(), then it will return null-terminated c-string.
However, the actual data stored in the object temp may not be null-terminated, but it doesn't matter and shouldn't matter to the programmer, because when then programmer wants const char*, he would call c_str() on the object, which is guaranteed to return null-terminated string.
With C++ strings you don't have to worry about that, and it's possibly dependent of the implementation.
Using temp.c_str() you get a C representation of the string, which will definitely contain the \0 char. Other than that, i don't really see how it would be useful on a C++ string
std::string internally keeps a count of the number of characters. Internally it works using this count. Like others have said, when you need the string for display or whatever reason, you can its c_str() method which will give you the string with the null terminator at the end.

Is the: "std::string can hold '\0' character" by design?

The fact that std::string can actually hold '\0' characters comes up all the time. This is of course inconsistent with C-style strings.
So I'm wondering, is this by design, or is it an omission, or is it just the fact that standard doesn't forbid it and compilers allow this to happen?
I'm wondering what your quarrel is. '\0' is just another character. There is no efficient way to forbid it in a general purpose 'char' string.
That the same character has a special meaning in C is unfortunate but has to be dealt with as every restriction that is imposed by legacy code as soon as you interoperate with it.
This shouldn't be an issue as long as you stick to code that uses std::string exclusively.
To address your comment we need to look at the constructor that takes a char* which would be basic_string(const charT* s, const Allocator& a = Allocator()) in 21.4.2 9/10 in n3242. It says that the size of the internal string is determined through traits::length(s) which in the case of std::string is strlen which requires its argument to be null terminated. So yes, if you try to construct a std::string from an const char* it needs to be null terminated.
There is a set of functions that accept 'char *' arguments and assume that the string is terminated by a zero. If you use them carefully, you can certainly have strings with 0's in them.
STL strings, in contrast, intentionally permit zero bytes, since they don't use 0 for termination. So the simple answer to your question is, 'yes, by design.'
The standard doesn't say that in case of an std::string '\0' is any special character. Therefore, any compliant implementation of std::string should not treat '\0' as any special character. Unless of course a const char* is passed to a member function of a string, which is assumed to be null-terminated.
By design.
C also can have not null terminated strings:
char sFoo[4];
strncpy(sFoo,"Test",sizeof(sFoo));
Where sFoo holds non-NULL terminated string.
And it have have Null-Terminated strings that can have 0 like
struct String {
char *str;
size_t length;
size_t capacity;
};
String literals are NUL terminated but this is not always refers to strings.
So having NUL terminated string is practice but it does mean that 0 in invalid character.
strncpy vs. strncat
That said, strncpy and strncat etc. will append a null terminator if there's room.
Actually strncpy and strncat are very different:
strncpy writes a "NUL-filled n-bytes string" to a n-bytes buffer: a string whose length l is at most n, such that the last n - l bytes are filled with NUL. Note the plural: all last bytes are zeroed, note just one. Also note the fact that the maximum allowed value for l is really n, so there can be zero NUL bytes: the buffer may no hold a NUL-terminated string. (GCC has a non-portable function to measure such "NUL-filled n-bytes string": strnlen.)
On the contrary, strncat outputs a NUL-terminated string to a buffer. In both cases, the string is truncated if it is too long, but in the case of strncpy, a n letters string will fit in a n-bytes buffer, whereas in the case of strncat, a result of n letters will only fit in (n+1)-bytes buffer.
This difference causes a lot of confusion to C beginners and even non-beginners. I have even seen lesson and books that teach "safe C programming" that had confused and contradicting informations about these standard functions.
These so-called "safe" C string manipulation functions (the "strn*" family) have been very criticized in the C "secure programming" community, and better designed (but non-standard) alternatives have been invented (notably the "strl*" family: strlcpy...).
Summary:
strncpy will append a null terminator if there's room;
strncat will append a null terminator always.