I want to create my own string storage (class) and I know something about const char * and char *.
This is a part of my source:
class str_n
{
private:
char * _str;
public:
str_n(const char * str)
{
std::size_t Read_len = strlen(str);
_str = (char *) malloc(Read_len + 1);
memcpy(_str, str, Read_len + 1);
}
};
I used char * and const char * for my _str and I know if I use const char * I need to copy it to char * whlie I want to use some other functions inside of my class and also using const char * is faster (very faster (about 2x)) than char * to save the const char * param content.
Now my question: If you want to create new string storage, you use const char * or char *?
Use char *, if your str_n is mutable. You're wrong on the part that const content is modifiable. For example, this:
const char *foo = "foo";
foo[0] = 'a';
won't compile. Trying to circumvent it with const_cast is not a viable option:
const_cast<char *>(foo)[0] = 'a';
as it is undefined behavior, and usually crashes, as foo is put in read-only memory.
So, if your string is mutable, you must copy the contents of str (the parameter for the constructor) in your example (you don't have the option of using const char * as storage, and omitting the copy to make your program faster -- I suppose you meant "2x faster" because you omitted the copy).
A note: you should use new instead of malloc, it is more c++-ish (you won't need to cast to char * the result of new char[...])
Just use std::string
class str_n {
public:
str_n(const char * str_in) : str{str_in} {}
private:
std::string str;
};
you can fetch the c string from a C++ string with the .c_str() method
Related
#include <iostream>
#include <cstring>
using namespace std;
class String {
private :
const char * str; // declaration "char str[30];" is appropriate
public :
String(const char * _str) {
str = new char[30];
strcpy(str, _str);
}
};
int main() {
const char* sz = "Hello!";
String s("Hi!");
s = sz;
return 0;
}
I have a question for the types const char * and char array.
What I know is that "the name of a char array" has the same type as "the const char * variable".
So, as what i wrote in the above code, I thought it would be compiled properly.
But the compiler rejects my code, because the function strcpy() doesn't support conversion from the type const char * to the type char*.
What's wrong with this situation? Am I having wrong C++ grammatical knowledge?
The result of new char[30] is of type char* and you would have no problems copying something to the allocation using strcpy (although it's definitely not something you should be doing, since it's an open invitation to buffer overflow). The problem is that you immediately assign that pointer to str and str has type const char*. const is constant; you can't assign to a const, which is what strcpy will do.
In fact, assigning the pointer to a const char* member doesn't magically change the nature of the memory pointed to. If you were able to call strcpy, for example by const_casting the first argument, then nothing would break. The memory is writable. But the compiler won't let you write to it through a const char* because declaring a pointer to be const char* is a promise that you won't try to write to the memory. And it's a promise which you immediately break.
Anyway, you can do the following, at no extra cost:
class String {
private :
const char * str; // declaration "char str[30];" is appropriate
public :
String(const char * _str) {
char * cpy = new char[strlen(_str) + 1];
str = strcpy(cpy, _str);
}
};
I am trying to write code that will assign a const char array to a dynamically allocated const char array.
I tried to do it like
const char staticArray[4] = "abc";
const char * ptrDynamicArray;
ptrDynamicArray = new const char[4](staticArray);
But I get an error ("parenthesized initializer in array new [-fpermissive]").
I have two questions:
How could I solve it - like turn it off (I am using Code::Blocks 16.01)?
Can I initialize a dynamically allocated const char array somehow else?
Overloading new operator will do your job.
void * operator new[](size_t n, const char *s) {
void *p = malloc(n);
strcpy((char *)p, s);
return p;
}
Now new operator can be called like :
const char staticArray[4] = "abc";
const char * ptrDynamicArray;
ptrDynamicArray = new (staticArray) char[4];
You cannot copy-initialize an array from another array directly, hence the error. You either need to manually copy the elements (or use std::copy), or, better, if you want a "copy"-able array use std::array<char, 4> instead.
But, as mentioned in the comments, the best probably is to use an std::string here, and use its std::string::c_str() member function in case you need to pass around const char* pointers to old C-like interfaces.
For reading complex pointer declarations there is the right-left rule.
But this rule does not mention how to read const modifiers.
For example in a simple pointer declaration, const can be applied in several ways:
char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory
Now what about the use of const with a pointer of pointer declaration?
char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;
And what is an easy rule to read those declarations?
Which declarations make sense?
Is the Clockwise/Spiral Rule applicable?
Two real world examples
The method ASTUnit::LoadFromCommandLine uses const char ** to supply command line arguments (in the llvm clang source).
The argument vector parameter of getopt() is declared like this:
int getopt(int argc, char * const argv[], const char *optstring);
Where char * const argv[] is equivalent to char * const * argv in that context.
Since both functions use the same concept (a vector of pointers to strings to supply the arguments) and the declarations differ - the obvious questions are: Why do they differ? Makes one more sense than the other?
The intend should be: The const modifier should specify that the function does not manipulate strings of this vector and does not change the structure of the vector.
The const modifier is trivial: it modifies what precedes it, unless
nothing precedes it. So:
char const* buffer; // const modifies char
char* const buffer; // const modifies *
, etc. Generally, It's best to avoid the forms where nothing precedes
the const, but in practice, you're going to see them, so you have to
remember that when no type precedes the const, you have to logically
move it behind the first type. So:
const char** buffer;
is in fact:
char const** buffer;
, i.e. pointer to pointer to const char.
Finally, in a function declaration, a [] after reads as a * before.
(Again, it's probably better to avoid this misleading notation, but
you're going to see it, so you have to deal with it.) So:
char * const argv[], // As function argument
is:
char *const * argv,
a pointer to a const pointer to a char.
(Trying to focus on other aspects of the question)
The rule of thumb for const declarations is to read them from right to left and const modifies the next token. Exception: At the beginning of a declaration const modifies the previous token.
There is a rationale behind this exception - for elementary declarations const char c looks for some people more natural than char const c - and it is reported that a precursor form of const char c predates the final const rule.
getopt
int getopt(int argc, char * const argv[], const char *optstring);
or
int getopt(int argc, char * const * argv, const char *optstring);
Which means that argv is a pointer to const vector of pointers to non-const strings.
But one would expect following declaration:
int getopt(int argc, char const * const * argv, const char *optstring);
(pointer to const vector to const strings)
Because getopt() is not supposed to change the strings referenced via argv.
At least char ** (as used in main()) automatically converts to char * const * argv.
Clang
ASTUnit::LoadFromCommandLine(..., const char **argv, ...);
Which means that argv is a pointer to a non-const array of pointers to const strings.
Again one would expect const char * const *argv for the same reason as above.
But this is more noticeable because char ** does not convert to const char **, e.g.
int main(int argc, char **argv) {
const char **x = argv; // Compile error!
return 0;
}
yields a compile error, where
int main(int argc, char **argv) {
char * const *x = argv;
return 0;
}
and
int main(int argc, char **argv) {
const char * const *x = argv;
return 0;
}
do not.
My problem is this:
I have a constant pointer to a constant char pointer (2D char array where both dimensions are const). I need to assign C-strings to this array. I have a std::vector of std::strings which I used c_str() on to create a vector of c_strings. Now I'm assigning those C-string pointers to this array, but I'm getting
src/rshell.cpp:45:44: error: assignment of read-only location ‘*(c_arr
((sizetype)(((long unsigned int)i) * 8ul)))’
for (int i = 0; i < size1; i++) c_arr[i] = commands.at(i);
Here's the code with the error
/* Confusing as heck, let me explain!
* char const* means pointer to a constant char
* so char const* const means a const pointer to a const char
* and char const* const* means a const pointer to a const char pointer!
* (Read declarations from right to left to make it make sense -
* char const* = POINTER (*) to a CONST CHAR)
*/
char const* const* c_arr = new char*[size1];
for (int i = 0; i < size1; i++)
c_arr[i] = commands.at(i); // line 38
And here's the vector of string to C-string part if it helps.
for (tokenizer::iterator it = parse.begin(); it != parse.end(); it++)
words.push_back(*it);
vector<const char*> commands;
// add string to c_string equiv return vector
for (vector<string>::iterator it = words.begin(); it != words.end(); it++) {
commands.push_back(it->c_str());
}
Since commands is a std::vector<const char *>, the expression &commands[0] will yield a const char ** (also known as char const **) which you can happily assign to a char const * const *. So unless you really need a copy, you could go with
char const * const *c_arr = &commands[0];
Note that this means that c_arr is really only useful as long as commands exists (which in turn is really only useful as long as the std::string objects in words exist).
I am not able to concat two const char*.
I do the following:
const char* p = new char[strlen(metadata.getRoot())+strlen(metadata.getPath())];
strcat(const_cast<char*>(p),metadata.getRoot());
strcat(const_cast<char*>(p),metadata.getPath());
strcpy(const_cast<char*>(args2->fileOrFolderPath),p);
function(args2->fileOrFolderPath);
Now when I print the variable args2->fileOrFolderPath on the console then the correct output appears... But when I call a method with the variable as parameter, and work with the variable then I got a segmentation fault. What is the problem?
I did not declare them like this but i know they have this information
So, I have this:
const char* ruta1 = "C:\\Users\\Deivid\\Desktop\\";
const char* ruta2 = "lenaGris.xls";
Then I used this for concatenation:
char * RutaFinal = new char[strlen(ruta1) + strlen(ruta2) + 1];
strcpy(RutaFinal, ruta1);
strcat(RutaFinal, ruta2);
printf(RutaFinal);
This worked for me.
I would prefer using std::string for this, but if you like char* and the str... functions, at least initialize p before using strcat:
*p = 0;
BTW:
using std::string, this would be:
std::string p = std::string(metadata.getRoot()) + metadata.getPath();
strcpy(const_cast<char*>(args2->fileOrFolderPath), p.c_str());
function(args2->fileOrFolderPath);
And you don't have to deallocate p somewhere.
1.
const char* p=new char[strlen(metadata.getRoot())+strlen(metadata.getPath())+1];
the length plus 1 to store '\0'.
2.
strcpy(const_cast<char*>(args2->fileOrFolderPath),p);
You can not guarantee args2->fileOrFolderPath 's length is longger than strlen(p).
This works well
#include <iostream>
using namespace std;
void foo(const char*s){
cout<<s<<endl;
}
int main(int argc,char*argv[]){
const char* s1 = "hello ";
const char* s2 = "world!";
const char* p = new char [strlen(s1)+strlen(s2)+1];
const char* s = new char [strlen(s1)+strlen(s2)+1];
strcat(const_cast<char*>(p),s1);
strcat(const_cast<char*>(p),s2);
strcpy(const_cast<char*>(s),p);
cout<<s<<endl;
foo(s);
return 0;
}
You have char pointers, pointing to char constants which can't be modified . What you can do is to copy your const char array to some char array and do like this to concate const strings :
char result[MAX];
strcpy(result,some_char_array); // copy to result array
strcat(result,another_char_array); // concat to result array
I believe you need to include space for the null terminator, and the first parameter to strcat shouldn't be const as you're trying to modify the memory being pointed to.
You want to do something like this:
char * str1 = "Hello, ";
char * str2 = "World!\n";
char * buffer = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(buffer, str1);
strcat(buffer, str2);
printf(buffer);
Which prints out "Hello, World!" as expected.
As for the error you're seeing when using a parameter, I've wrote some tests to see why it doesn't break when using a const local variable. While compiling using a const char * for the pointer I'm using as the target I get this warning:
./strings.c:10: warning: passing argument 1 of ‘strcat’ discards qualifiers from pointer target type
As it states, const is discarded and it works as expected. However, if I pass a parameter which is a const char * pointer, then I get a bus error when trying to modify the buffer it writes to. I suspect what is happening is that it ignores the const on the argument, but it can't then modify the buffer because it's defined as const elsewhere in the code.