Dynamic Structure in C++ - c++

struct testing
{
char lastname[20];
};
testing *pt = new testing;
pt->lastname = "McLove";
and I got
56 C:\Users\Daniel\Documents\Untitled2.cpp incompatible types in
assignment of 'const char[7]' to 'char[20]'
Why ?
Thanks in advance.

Because compile time arrays are constant. In your struct testing, you have an array of 20 chars, and you're trying to assign a pointer ("McLove", a compile time string, e.g., a const char*) to an array (a char[]), which won't work.
To copy the data "McLove" into the array, you need to use strncpy:
strncpy(pt->lastname, "McLove", 20); // 20 is the size of the array, change it when your array size changes, or better yet, use a constant for both
Or better yet, use std::string:
struct testing {
string lastname;
};
testing* pt = new testing;
pt->lastname = "McLove";
And now that will work, because std::string has an operator= that works with const char*.
As a side note, don't needlessly allocate objects on the free store (using new); allocate them on the stack:
testing pt; // not: testing* pt = new testing;
testing.lastname = "McLove"; // with std::string

The type of a string literal is pointer to const char. You can use that to initialize an array of char, but you can't assign to an array of char (from that or anything else).
Since you're apparently doing C++, you probably want:
struct testing {
std::string lastname;
};
testing pt;
pt.lastname = "McLove";
Allocating an object like testing dynamically is fairly unusual.

You can't assign one array to another. You're going to need to use strcpy (or better, strncpy).

Because string literals in C++ have the type const char[N] where N is the length of the literal, including the NULL character. So you're trying to assign a const char[7] to a array of type char[20], exactly what the compiler told you. Since arrays are not assignable this is invalid.
Use strcpy instead
strcpy( p-lastname, "McLove" );
Of course, you should also check if the destination is large enough to hold the source, or use some variant of strcpy that does this.

Related

C++ How to populate a static array of strings with new strings in different locations?

Say I got this
char* MapIds[5000] = { "Northeast Asia","Hanyang","Pusan","Pyongyang","Shanghai","Beijing","Hong Kong", /*...5000 values etc../* };
I tried
strcpy(MapIds[0], "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");
But it crashes
How Do I keep changing them around without messing up the strings in other elements.
I dont want to use std::string or vector those cause crazy slow compile times.
Because you try to copy into a literal string ("Northeast Asia").
In C++ a literal string is really a constant array of characters, any attempt to modify such an array will lead to undefined behavior (which can sometimes express themselves as crashes).
If you want to make MapIds[0] point to a new string, then you simply use assignment:
MapIds[0] = "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg";
Because literal strings are constant arrays of characters, C++ doesn't really allow you to have a char* to point to them, you must use const char*:
const char* MapIds[] = { ... };
However, a much better solution is to not use C-style strings and char pointers (const or not) at all, but only use std::string:
std::string MapIds[] = { ... };
Then you can modify the strings in the array itself, using plain assignment as shown above.

A value of type "*const char *" cannot be assigned to an entity of type "char *"

So I am trying to avoid using strings for this. I am basically trying to make a string array.
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
(*hourtimes) = (char*)malloc((100 * sizeof(char)));
}
So I made a string array basically here
Now, I want to make hourtimes[0] = "twelve";
I tried doing *hourtimes = "twelve";
but I get the same error, I think this works in c, but I'm using c++
hourtimes[0][0] = 't';
hourtimes[0][1] = 'w';
etc works just fine but that would be too cumbersome
*hourtimes = "twelve" is setting *hourtimes to point to an immutable string literal. You are then trying to modify that immutable string. What you want to do is copy "twelve" into *hourtimes.
strcpy(hourtimes[0],"twelve");
Note: This answer was written at a time when the question was tagged for C. C++ will have different preferred ways of doing this kind of thing.
The error message tells you exactly what's wrong: You can't assign a const char * to a char *. What does that mean, though?
Both const char * and char * are types. They are, in fact, very nearly the same type; one is a pointer to a character, and the other is a pointer to a constant character. That means that the latter can't be changed1; that's, after all, what "constant" means. So when you try to tell the compiler to treat a pointer to a constant type as a pointer to a non-const type, it'll give you an error -- because otherwise it'd have no way to guarantee that the string isn't modified.
"whatever" is always a const char *, not a char *, because that's stored in memory that's generally not meant to be modified, and the compiler can make some really neat optimizations if it can safely assume that it's unchanged (which, because it's const, it can).
I won't tell you how to "properly" write the code you're going for, because if you're using C++, you should be using std::vector and std::string instead of anything with pointers whenever possible, and that probably includes here. If, for whatever reason, you need to use pointers, the comments have covered that well enough.
1: Okay, yes, it can -- but that's outside the scope of this answer, and I don't want to confuse any beginners.
In your allocation loop, (*hourtimes) is the same as hourtimes[0], so you are assigning your allocated sub-arrays to the same slot in the main array on each loop iteration, causing memory leaks and uninitialized slots. You need to use hourtimes[i] instead:
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
hourtimes[i] = (char*)malloc(100 * sizeof(char));
}
And don't forget to deallocate the arrays when you are done with them:
for (int i = 0; i < 100; i++) {
free(hourtimes[i]);
}
free(hourtimes);
Now, a string literal has type const char[N], where N is the number of characters in the literal, + 1 for the null terminator. So "twelve" would be a const char[7].
Your arrays only allow char* pointers to be stored, but a const char[N] decays into a const char* pointer to the first char. You can't assign a const char* to a char*, thus the compiler error.
Even if it were possible to do (which it is, but only with a type-cast), you shouldn't do it, because doing so would cause a memory leak as you would lose your original pointer to the allocated array, and worse free() can't deallocate a string literal anyway.
What you really want to do is copy the content of the string literal into the allocated array storage. You can use strncpy() for that:
strncpy(hourtimes[0], "twelve", 100);
Now, with all of that said, this is the C way of handling arrays of strings. The C++ way is to use std::vector and std::string instead:
#include <string>
#include <vector>
std::vector<std::string> hourtimes(100);
...
hourtimes[0] = "twelve";
This is a string literal, which can be used as a pointer to a constant char, but not as a pointer to a non-const char.
"twelve"
You do however attempt to assign it to a pointer to non-const char.
hourtimes[0] = "twelve";
That is what the compiler does not like.

How to initialize the dynamic array of chars with a string literal in C++?

I want to do the following:
std::unique_ptr<char[]> buffer = new char[ /* ... */ ] { "/tmp/file-XXXXXX" };
Obviously, it doesn't work because I haven't specified the size of a new array. What is an appropriate way to achieve my goal without counting symbols in a string literal?
Usage of std::array is also welcome.
Update #1: even if I put the size of array, it won't work either.
Update #2: it's vital to have a non-const access to the array as a simple char* pointer.
Here's a solution based on std::array:
std::array<char, sizeof("/tmp/file-XXXXXX")> arr{ "/tmp/file-XXXXXX" };
You can reduce the boilerplate using a macro:
#define DECLARE_LITERAL_ARRAY(name, str) std::array<char, sizeof(str)> name{ str }
DECLARE_LITERAL_ARRAY(arr, "/tmp/file-XXXXXX");
The sizeof is evaluated at compile-time, so there is no runtime scanning of the literal string to find its length. The resulting array is null-terminated, which you probably want anyway.
Since you requested a dynamic array and not wanting to count the length, that rules out std::array<char,N>. What you're asking for is really just std::string - it's dynamic (if need be), and initializes just fine from a char* without counting the length. Internally, it stores the string in a flat array, so you can use it as such, via the c_str() call.
I don't get why you're not using std::string; you can do str.empty() ? NULL : &str[0] to get a non-const pointer, so the constness of str.c_str() is not going to pose a problem.
However, note that this is not null-terminated.

How to cast a std::stringbuf into an array of char?

What I'm trying to do here is to cast a stringbuf object into an array of char.
I do this to send the array of char to a C interface which doesn't understand the type std::stringbuf.
Here's a part of my code to illustrate the problem :
std::stringbuf buffer;
char * data;
//here i fill my buffer with an object
buffer >> Myobject;
//here is the function I want to create but I don't know if it's possible
data = convertToCharArray(buffer);
//here I send my buffer of char to my C interface
sendToCInterface(data);
If you don't have a strict zero-copy/high performance requirement then:
std::string tmp = buffer.str();
// call C-interface, it is expected to not save the pointer
sendToCharInterface(tmp.data(), tmp.size());
// call C-interface giving it unique dynamically allocated copy, note strdup(...)
sendToCharInterface(strndup(tmp.data(), tmp.size()), tmp.size());
If you do need it to be fast (yet still have stringbuf on the way) then you can look in the direction of stringbuf::pubsetbuf().
As Kiroxas suggests in the first comment, try to avoid intermediate variables:
sendToCInterface(buffer.str().c_str());
...the less variables the less confusion ;-)
If you would like to convert a std::stringbuf into a char pointer, I think you could just do
std::string bufstring = buffer.str();
to get a string, and convert this into a c-style string using
bufstring.c_str()
to pass a character pointer to a function

Returning a constant char pointer yields an error

I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.