How can I convert const char* to char[256] - c++

How do I convert const char* to char[256]?
const char *s = std::string("x").c_str();
char c[256] = /* ??? */

You cannot initialise an array with a character pointer. But you can copy the string. For example:
const char *s = get_the_string();
char c[256]{};
auto n = std::strlen(s);
if (std::size(c) <= n)
throw std::runtime_error(
"The buffer is too small. Contact your local C++ maintainer");
std::memcpy(c, s, n);
The obvious problem with using an array of constant size is that you need to consider how to handle situation where the input string doesn't fit. Here, I've used an exception, but you can use error handling of your choice, if this is not an option for you.
You cannot copy from a const char *s = std::string("x").c_str(); though, because the pointer is dangling, and attempting to access the pointed data would have undefined behaviour.

Copying the contents from the const type to an editable one is really your only recourse for dropping the const. I'm guessing you are given a const because something has marked it "not ok for you to change" ie read only.
The trouble with a pure * though is you need to know how long it is. For null-terminated strings, strlen can get you that size (and so it works with strncpy).
strncpy(c,s,256);
If the const char * were just bytes though, you'd need another way.

There are many different ways to copy a const char* into a char[]:
#include <cstring>
const char *s = "x";
char c[256]{};
std::strncpy(c, s, 255);
#include <algorithm>
#include <cstring>
const char *s = "x";
char c[256]{};
std::copy_n(s, std::min(std::strlen(s), 255), c);
#include <string>
const char *s = "x";
char c[256]{};
std::string(s).copy(c, 255);
#include <sstream>
const char *s = "x";
char c[256]{};
std::istringstream iss(s);
iss.read(c, 255);
//or: iss.get(c, 256, '\0');

strncpy(c, s, 256);
it work for me

As others have pointed out
const char *s = std::string("x").c_str();
Is bad code. It effectively creates a new string, puts "x" in it, returns a pointer to "x", frees the string. So now what s points to is undefined
If you were not creating the string in that line it would be safe. For example
const auto t = std::string("x");
const char *s = t.c_str();
Now t will be valid until the current scope exits and so will s
As for the copy to an array of 256 characters the arguably optimal solution is
char c[256];
std::strncpy(c, s, 255);
c[255] = '\0';
Why?
This line
char c[256];
allocates space on the stack for 256 bytes and does nothing else.
This line
std::strncpy(c, s, 255);
if s is less than 255 characters it copies those characters into c then writes out zeros to pad out the buffer to the 254th element
if s is 255 characters or more it just copies the first 255 characters
This line puts a null terminating zero at the end
c[255] = '\0';
Let's compare to other solutions
This one
char c[256];
std::strncpy(c, s, 256);
Problem with this answer is if s is more than 255 characters there will be no terminating 0 at the end of c. Whether that's important or not is really up to you but 999 times out of 1000 it probably is important.
This one
char c[256]{};
std::strncpy(c, s, 255);
Is safe but slower. The difference is the {} at the end of char c[256]{}. Without that {} the c array is only allocated. With it c is not only allocated but also initialized to 0 for all 256 characters. That means for every character copied from s to c there was a wasted effort clearing the character to zero at the beginning. That's potentially double the work
const char *s = get_the_string();
char c[256]{};
auto n = std::strlen(s);
if (std::size(c) <= n)
throw std::runtime_error(
"The buffer is too small. Contact your local C++ maintainer");
std::memcpy(c, s, n);
Same as above, does double the work though it is good to point out that you must choose how to handle s being too big to fit in c.
All of the examples using char c[256]{} instead of char c[256] are potentially doing double the work. Doing double the work is not necessarily bad but given the optimal version is simple there's no reason not to use it.
One other issue is using magic numbers. Unfortunately C++ didn't add an array size function until C++ 17 (std::size) so we're left to make our own
template<class T, size_t N>
constexpr size_t array_size(T (&)[N]) { return N; }
so then we can do this
char c[256];
std::strncpy(c, s, array_size(c) - 1);
c[array_size(c) - 1] = '\0';
so now if we change the size of c the code will still work.
The standard version for getting the number of elements in an array is std::size added in C++ 17 but C++ 17 is apparently still rare, none of the online C++ compilers I tried (first several hits in Google) supported it.

Related

Filling char pointer correctly

I have a char pointer:
char* s = new char[150];
Now how do i fill it? This:
s="abcdef";
Gives warning about deprecation of conversion between string literal and char*, but generally works.
This:
char* s = new[150]("abcdef");
Does not work, gives an error.
How to do this properly? Note that I want the memory allocation to have 150*sizeof(char) bytes and contain "abcdef". I know about malloc, but is it possible to do with new?
Its for an assignment where i cant use the standard library.
This sequence of statements
char* s = new char[150];
s="abcdef";
results in a memory leak because at first a memory was allocated and its address was assigned to the pointer s and then the pointer was reassigned with the address of the string literal "abcdef". And moreover string literals in C++ (opposite to C) have types of constant character arrays.
If you allocated a memory for a string then you should copy a string in the memory either by using the C standard function strcpy or C standard function strncpy.
For example
char* s = new char[150];
std::strcpy( s, "abcdef" );
Or
const size_t N = 150;
char* s = new char[N];
std::strncpy( s, "abcdef", N );
s[N-1] = '\0';
Or even the following way
#include <iostream>
#include <cstring>
int main()
{
const size_t N = 150;
char *s = new char[N]{ '\0' };
std::strncpy( s, "abcdef", N - 1 );
std::cout << s << '\n';
delete []s;
}
In any case it is better just to use the standard class std::string.
std::string s( "abcdef" );
or for example
std::string s;
s.assign( "abcdef" );
The basic procedure for creating a memory area for a string and then filling it without using the Standard Library in C++ is as follows:
create the appropriate sized memory area with new
use a loop to copy characters from a string into the new area
So the source code would look like:
// function to copy a zero terminated char string to a new char string.
// loop requires a zero terminated char string as the source.
char *strcpyX (char *dest, const char *source)
{
char *destSave = dest; // save copy of the destination address to return
while (*dest++ = *source++); // copy characters up to and including zero terminator.
return destSave; // return destination pointer per standard library strcpy()
}
// somewhere in your code
char *s1 = new char [150];
strcpyX (s1, "abcdef");
Given a character array:
char * s = new char [256];
Here's how to fill the pointer:
std::fill(&s, &s + sizeof(s), 0);
Here's how to fill the array:
std::fill(s, s+256, '\0');
Here's how to assign or copy text into the array:
std::strcpy(s, "Hello");
You could also use std::copy:
static const char text[] = "World";
std::copy(text, text + sizeof(text), s);
Remember that a pointer, array and C-Style string are different concepts and objects.
Edit 1: Prefer std::string
In C++, prefer to use std::string for text rather than character arrays.
std::string s;
s = "abcdef";
std::cout << s << "\n";
Once you've allocated the memory for this string, you could use strcpy to populate it:
strcpy(s, "abcdef");

Building / Merging character array pointers in C++

I'm very new to C++ (coming from C#) and it's giving me puzzles :S
I have a very basic question about arrays and it's pointers.
So if I have the following code:
char * test1 = "com";
char * test2 = "ment";
I found similar code in some files already. I don't exactly understand how a string can fit in one character.. but ok...
However, how could I connect these arrays so that I get "comment" ?
I'm pretty sure this char * result = test1 + test2; would only increase the pointer which would then point to something in the memory, which I dont intend to use.
So is it possible to get an array like char array[] = {'c', 'o', 'm', 'm', 'e', 'n', 't'}; back from this?
or can I at least get a pointer which points to something like comment\NUL in the memory?
As you pointed out, pointer arithmetic can't solve this.
If you want to have a C-string as the result, allocating space for the whole new string is required, then copying over the characters, typically using strcat / strncat, but they are C-style string operations.
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Dynamic allocation of memory for result string
char *result = new char[strlen(test1) + strlen(test2) + 1];
// Start with the empty string
*result = '\0';
// Concatenate both input strings (use strncat if you don't know
// for sure that they will fit into the result array!)
strcat(result, test1);
strcat(result, test2);
// (use result pointer)
// Free the memory after last usage
delete[] result;
In C++, you typically try to avoid them and use std::string instead. Even if you want a C-string as the result, you can use a temporary std::string for allocation and management of the required memory as well as for performing the concatenation:
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Wrap in temporary C++ strings and concatenate:
std::string result = std::string(test1) + std::string(test2);
// Get the pointer (only valid as long as result is in scope!)
const char *ptr = result.c_str();
Furthermore, please note that you should not assign a string literal to a non-const char * pointer, use a const char* pointer instead. And try to avoid dealing with raw C-strings as long as possible; of course when you use C libraries you have to use them a lot.
Note also that above mentioned methods are performed at runtime; you can't get a compile-time solution for concatenating two string literals, even though the compiler could know what you want to have. I don't know your context, but maybe you only want to have a multi-line string literal, then simply drop the + and write "com" "ment".
A c style solution can be found in the following link:
http://www.cplusplus.com/forum/beginner/5681/:
int len = strlen(test1)+strlen(test2);
char* result = new char[len +1]; // +1 for null terminated string
snprintf(result,len +1, "%s%s",test1,test2);
result[len] = NULL;
// use result
delete(result);
You can utilize std::string:
#include <iostream>
int main() {
// Note: the character literals are const (non const is deprecated)!
const char * test1 = "com";
const char * test2 = "ment";
// This gives a compiler error (there is no way to add pointers)
// const char * concat = test1 + test2;
// A std::string has an overload for the operator +:
std::string comment = std::string(test1) + test2;
// The dynamically allocated string.
// Note: as soon as the comment string gets altered or destroyed the
// pointer s to the internal string data (may) become invalid.
const char* s = comment.c_str();
std::cout << s << '\n';
}

char array to uint8_t array

this is one area of C/C++ that i have never been good at.
my problem is that i have a string that will need to eventually contain some null characters. treating everything as a char array (or string) won't work, as things tend to crap out when they find the first null. so i thought, ok, i'll switch over to uint8_t, so everything is just a number. i can move things around as needed, and cast it back to a char when i'm ready.
my main question right now is: how can i copy a portion of a string to an uint8_t buffer?
effectively, i'd like to do something like:
std::string s = "abcdefghi";
uint8_t *val = (uint8_t*)malloc(s.length() + 1);
memset(val, 0, s.length() + 1);
// Assume offset is just some number
memcpy(val + offset, s.substr(1, 5).c_str(), 5);
obviously, i get an error when i try this. there is probably some sort of trickery that can be done in the first argument of the memcpy (i see stuff like (*(uint8_t*)) online, and have no clue what that means).
any help on what to do?
and while i am here, how can i easily cast this back to a char array? just static_cast the uint8_t pointer to a char pointer?
thanks a lot.
i thought, ok, i'll switch over to uint8_t, so everything is just a number.
That's not going to make algorithms that look for a '\0' suddenly stop doing it, nor do algorithms that use char have to pay attention to '\0'. Signaling the end with a null character is a convention of C strings, not char arrays. uint8_t might just be a typedef for char anyway.
As Nicol Bolas points out std::string is already capable of storing strings that contain the null character without treating the null character specially.
As for your question, I'm not sure what error you're referring to, as the following works just fine:
#include <iostream>
#include <string>
#include <cstdint>
#include <cstring>
int main() {
std::string s = "abcdefghi";
std::uint8_t *val = (std::uint8_t*)std::malloc(s.length() + 1);
std::memset(val, 0, s.length() + 1);
int offset = 2;
std::memcpy(val + offset, s.substr(1, 5).c_str(), 5);
std::cout << (val+offset) << '\n';
}
The memcpy line takes the second through sixth characters from the string s and copies them into val. The line with cout then prints "bcdef".
Of course this is C++, so if you want to manually allocate some memory and zero it out you can do so like:
std::unique_ptr<uint8_t[]> val(new uint8_t[s.length()+1]());
or use a vector:
std::vector<uint8_t> val(s.length()+1,0);
To cast from an array of uint8_t you could (but typically shouldn't) do the following:
char *c = reinterpret_cast<uint8_t*>(val);
Well, the code works ok, it copies the substring in val. However, you will have 0s on all the positions until the offset.
e.g. for offset=2 val would be {0, 0, b, c, d, e, f, 0, 0, 0}
If you print this, it will show nothing because the string is null terminated on the first position (I guess this is the error you were talking about...).

strncpy equivalent for std::string?

Is there an exact equivalent to strncpy in the C++ Standard Library? I mean a function, that copies a string from one buffer to another until it hits the terminating 0? For instance when I have to parse strings from an unsafe source, such as TCP packets, so I'm able to perform checks in length while coping the data.
I already searched a lot regarding this topic and I also found some interesting topics, but all of those people were happy with std::string::assign, which is also able to take a size of characters to copy as a parameter. My problem with this function is, that it doesn't perform any checks if a terminating null was already hit - it takes the given size serious and copies the data just like memcpy would do it into the string's buffer. This way there is much more memory allocated and copied than it had to be done, if there were such a check while coping.
That's the way I'm working around this problem currently, but there is some overhead I'd wish to avoid:
// Get RVA of export name
const ExportDirectory_t *pED = (const ExportDirectory_t*)rva2ptr(exportRVA);
sSRA nameSra = rva2sra(pED->Name);
// Copy it into my buffer
char *szExportName = new char[nameSra.numBytesToSectionsEnd];
strncpy(szExportName,
nameSra.pSection->pRawData->constPtr<char>(nameSra.offset),
nameSra.numBytesToSectionsEnd);
szExportName[nameSra.numBytesToSectionsEnd - 1] = 0;
m_exportName = szExportName;
delete [] szExportName;
This piece of code is part of my parser for PE-binaries (of the routine parsing the export table, to be exact). rva2sra converts a relative virtual address into a PE-section relative address. The ExportDirectory_t structure contains the RVA to the export name of the binary, which should be a zero-terminated string. But that doesn't always have to be the case - if someone would like it, it would be able to omit the terminating zero which would make my program run into memory which doesn't belong to the section, where it would finally crash (in the best case...).
It wouldn't be a big problem to implement such a function by myself, but I'd prefer it if there were a solution for this implemented in the C++ Standard Library.
If you know that the buffer you want to make a string out of has at least one NUL in it then you can just pass it to the constructor:
const char[] buffer = "hello\0there";
std::string s(buffer);
// s contains "hello"
If you're not sure, then you just have to search the string for the first null, and tell the constructor of string to make a copy of that much data:
int len_of_buffer = something;
const char* buffer = somethingelse;
const char* copyupto = std::find(buffer, buffer + len_of_buffer, 0); // find the first NUL
std::string s(buffer, copyupto);
// s now contains all the characters up to the first NUL from buffer, or if there
// was no NUL, it contains the entire contents of buffer
You can wrap the second version (which always works, even if there isn't a NUL in the buffer) up into a tidy little function:
std::string string_ncopy(const char* buffer, std::size_t buffer_size) {
const char* copyupto = std::find(buffer, buffer + buffer_size, 0);
return std::string(buffer, copyupto);
}
But one thing to note: if you hand the single-argument constructor a const char* by itself, it will go until it finds a NUL. It is important that you know there is at least one NUL in the buffer if you use the single-argument constructor of std::string.
Unfortunately (or fortunately), there is no built in perfect equivalent of strncpy for std::string.
The std::string class in STL can contain null characters within the string ("xxx\0yyy" is a perfectly valid string of length 7). This means that it doesn't know anything about null termination (well almost, there are conversions from/to C strings). In other words, there's no alternative in the STL for strncpy.
There are a few ways to still accomplish your goal with a shorter code:
const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset);
m_exportName.assign(ptr, strnlen(ptr, nameSra.numBytesToSectionsEnd));
or
const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset);
m_exportName.reserve(nameSra.numBytesToSectionsEnd);
for (int i = 0; i < nameSra.numBytesToSectionsEnd && ptr[i]; i++)
m_exportName += ptr[i];
Is there an exact equivalent to strncpy in the C++ Standard Library?
I certainly hope not!
I mean a function, that copies a string from one buffer to another until it hits the terminating 0?
Ah, but that's not what strncpy() does -- or at least it's not all it does.
strncpy() lets you specify the size, n, of the destination buffer, and copies at most n characters. That's fine as far as it goes. If the length of the source string ("length" defined as the number of characters preceding the terminating '\0') exceeds n, the destination buffer is padded with additional \0's, something that's rarely useful. And if the length if the source string exceeds n, then the terminating '\0' is not copied.
The strncpy() function was designed for the way early Unix systems stored file names in directory entries: as a 14-byte fixed-size buffer that can hold up to a 14-character name. (EDIT: I'm not 100% sure that was the actual motivation for its design.) It's arguably not a string function, and it's not just a "safer" variant of strcpy().
You can achieve the equivalent of what one might assume strncpy() does (given the name) using strncat():
char dest[SOME_SIZE];
dest[0] = '\0';
strncat(dest, source_string, SOME_SIZE);
This will always '\0'-terminate the destination buffer, and it won't needlessly pad it with extra '\0' bytes.
Are you really looking for a std::string equivalent of that?
EDIT : After I wrote the above, I posted this rant on my blog.
There is no built-in equivalent. You have to roll your own strncpy.
#include <cstring>
#include <string>
std::string strncpy(const char* str, const size_t n)
{
if (str == NULL || n == 0)
{
return std::string();
}
return std::string(str, std::min(std::strlen(str), n));
}
The string's substring constructor can do what you want, although it's not an exact equivalent of strncpy (see my notes at the end):
std::string( const std::string& other,
size_type pos,
size_type count = std::string::npos,
const Allocator& alloc = Allocator() );
Constructs the string with a substring [pos, pos+count) of other. If count == npos or if the requested substring lasts past the end of the string, the resulting substring is [pos, size()).
Source: http://www.cplusplus.com/reference/string/string/string/
Example:
#include <iostream>
#include <string>
#include <cstring>
int main ()
{
std::string s0 ("Initial string");
std::string s1 (s0, 0, 40); // count is bigger than s0's length
std::string s2 (40, 'a'); // the 'a' characters will be overwritten
strncpy(&s2[0], s0.c_str(), s2.size());
std::cout << "s1: '" << s1 << "' (size=" << s1.size() << ")" << std::endl;
std::cout << "s2: '" << s2 << "' (size=" << s2.size() << ")" << std::endl;
return 0;
}
Output:
s1: 'Initial string' (size=14)
s2: 'Initial string' (size=40)
Differences with strncpy:
the string constructor always appends a null-terminating character to the result, strncpy does not;
the string constructor does not pad the result with 0s if a null-terminating character is reached before the requested count, strncpy does.
Use the class' constructor:
string::string str1("Hello world!");
string::string str2(str1);
This will yield an exact copy, as per this documentation: http://www.cplusplus.com/reference/string/string/string/
std::string has a constructor with next signature that can be used :
string ( const char * s, size_t n );
with next description:
Content is initialized to a copy of the string formed by the first n characters in the array of characters pointed by s.

C++ how to count correctly the characters in a const char?

I have got a const char which is made by concatenation like this:
const char *fileName = "background1";
std::stringstream sstm;
sstm << fileName << "-hd.png";
fileName = sstm.str().c_str();
My problem is that the following instruction:
printf("const char = %s size = %d", fileName, sizeof(fileName));
returns:
"const char = background1-hd.png size = 4"
whereas I would expect that it returns:
"const char = background1-hd.png size = 19"
For example, the following gives the convenient result (as there is no concatenation):
const char *fileName2 = "background1-hd";
printf("const char = %s size = %d", fileName2, sizeof(fileName2));
returns:
"const char = background1-hd.png size = 19"
How to avoid this issue and guarantee that the characters will be correctly counted in my concatenated char ?
Thanks !!
sizeof() returns the number of bytes the variable occupies in memory (in this case returns the size of the pointer fileName).
strlen() returns the length of the string (which is what you need).
You could as well try something like:
#include <iostream>
#include <cstdio>
int main()
{
std::string fileName("background1");
fileName.append("-hd.png");
printf("const char = %s size = %d", fileName.c_str(), fileName.length());
return 0;
}
sizeof returns the size of the variable you give to it; it's evaluated at compile time. The "4" is the size of a pointer on your system. You want to use strlen() to determine the length of a string.
The result of sizeof(fileName) is related to fileName being a pointer, not an array. It literally returns the size of a pointer to a constant character string, and on a 32-bit system, all pointers are 32 bits (so sizeof == 4).
What you should use instead is strlen or similar, which will count the characters in the string, up to the trailing null, and return that. The results with strlen in place of sizeof will be about what you expect.
Side-related, with const char strings there is only ever one character per "cell" (actually byte). There are character sets which make for multiple bytes per character, but packing multiple characters into a single byte is quite rare, at least in C-family languages.
sizeof calculates the size of the data type in bytes and not the size of its contents (what it points to). In your example you are calculating the sizeof char* which is 4 bytes on your system. To get the length of a C string use strlen.
There is a distinction in the language between arrays and pointers, even if this distinction seems diluted both by implicit conversions (arrays tend to decay into pointers quite easily), and common statements that they are the same.
How does this even relate to your code?
Well, a string literal is actually an array of constant characters, not a pointer to character(s). In the initialization const char *fileName = "background1"; you are creating a pointer variable that points to the first element of the array ("background1" is decaying into a pointer to the first element), and from there on the variable you are managing is pointer and not the literal.
If you mix this with the fact that sizeof will tell you the size of the variable, you get that in a platform with 32bit pointers and 8 bit chars, sizeof( const char* ) is always 4, regardless of the object that is pointed by that pointer (if there is even one).
Now, if you were treating the literal as what it actually is you would be having a bit more luck there:
const char filename[] = "background1";
assert( sizeof filename == 12 ); // note: NUL character is counted!
const char *fname = filename;
assert( sizeof filename == sizeof( void* ) );
In real code, you are not a so lucky and in many cases the literals have decayed into pointers well before you get a chance of getting the compile time size of the literal, so you cannot ask the compiler to tell you the size. In that case you need to calculate the length of the C style string, which can be done by calling strlen.
strlen has been suggested a number of times already, and for this case it's probably perfectly reasonable.
There is an alternative that will let you use sizeof though:
char fileName[] = "background1";
std::cout << sizeof(fileName) << "\n";
Since you're making fileName an array, it has all the characteristics of an array -- including the fact that your later attempt at assigning to it:
fileName = sstm.str().c_str();
...would fail (won't even compile when fileName is defined as an array). I should add, however, that it seems to me that you'd be better off just using std::string throughout:
std::string fileName("background1");
std::stringstream sstm;
sstm << fileName << "-hd.png";
fileName = sstm.str();
In this case, you can use string's size() or length() member.