I am trying to improve my plain text reader performance by using nmap to map file to memory.
Currently I have a function that receives const char * and length of that array. And I need to perform search on this char array.
This is what I currenly have
void parseVertex(
const char * line,
unsigned int length,
std::vector<glm::vec3> & vertices)
{
if(length == 0)
{
return;
}
char space = ' ';
char * pos = std::find(line, line + length, space);
}
std::find produces error : a value of type const char * cannot be used to initialize an entity of type char *
What is the correct way to use std::find ?
std::find return-type depends on what you pass to it.
line is const char*, so std::find will return const char*, NOT char*. So write this:
const char * pos = std::find(line, line + length, space);
Likewise, if you pass char*, you will get char*.
Hope that helps.
Make it
const char* pos = std::find(...);
you are working on const char* so you can't bind the result to char*, it must respect the const keyword.
therefore the correct way to achieve this is:
const char* pos = std::find(line, line + length, space);
^
Igor and Nawaz answered your question, I'll just add that if your compiler allows C++11, you'd take a good habit by using std::begin and std::end for standard library containers and arrays (and not a pointer like this as I originally wrote).
const char line[] = "whatever accessible char array";
const char * pos = std::find(std::begin(line), std::end(line), space);
Related
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 converting a project written in C++ for windows. Everything is going fine (meaning I clearly see what needs to be changed to make things proper C++) until I hit this, which is my own little routine to find a keyword in along string of keyword=value pairs:
bool GetParameter(const char * haystack, const char *needle) {
char *search, *start;
int len;
len = strlen(needle) + 4; // make my own copy so I can upper case it...
search = (char *) calloc(1,len);
if (search == NULL) return false;
strcpy(search,needle);
strupr(search);
strcat(search,"="); // now it is 'KEYWORD='
start = strstr(haystack,search); <---- ERROR from compiler
g++ is telling me "Invalid conversion from const char * to char * "
(the precise location of the complaint is the argument variable 'search' )
But it would appear that g++ is dyslexic. Because I am actually going the other way. I am passing in a char * to a const char *
(so the conversion is "from char * to const char *" )
The strstr prototype is char * strstr(const char *, const char *)
There is no danger here. Nothing in any const char * is being modified.
Why is it telling me this?
What can I do to fix it?
Thanks for any help.
The background to the problem is that C defines the function strstr as:
char* strstr(const char*, const char*);
This is because C doesn't allow overloaded functions, so to allow you to use strstr with both const and non-const strings it accepts const strings and returns non-const. This introduces a weakness in C's already fragile type-system, because it removes const-ness from a string. It is the C programmer's job to not attempt to write via a pointer returned from strstr if you pased in non-modifiable strings.
In C++ the function is replaced by a pair of overloaded functions, the standard says:
7. The function signature strstr(const char*, const char*) shall be replaced by the two declarations:
const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);
both of which shall have the same behavior as the original declaration.
This is type-safe, if you pass in a const string you get back a const string. Your code passes in a const string, so G++ is following the standard by returning a const string. You get what you asked for.
Your code compiles on Windows because apparently the standard library you were using on Windows doesn't provide the overloads and only provides the C version. That allows you to pass in const strings and get back a non-const string. G++ provides the C++ versions, as required by the standard. The error is telling you that you're trying to convert the const return value to a non-const char*. The solution is the assign the return value to a const char* instead, which is portable and compiles everywhere.
Error is not regarding the arguments to stsrtr. Compiler is complaining about the conversion of the 'const char *' returned by strstr. You can't assign it to *start which is just char *
You can try one of these:
const char *start;
or
string start(strstr(haystack,search));
Although declaring start as const char* might suffice, what seems more appropriate to me is to use std::string objects instead:
#include <string>
#include <cctype>
#include <algorithm>
bool GetParameter(const char * haystack, const char *needle) {
std::string hstr(haystack), nstr(needle);
std::transform(nstr.begin(), nstr.end(),nstr.begin(), ::toupper);
nstr += "=";
std::size_t found = hstr.find(nstr);
if (found != std::string::npos) {
... // "NEEDLE=" found
}
else {
...
}
...
}
The conversion it is complaining about is from strstr(...) to start. Change the declaration of start to const char* start;
you can use such like:
start = const_cast<char *>(strstr( haystack, static_cast<const char *>(search) ));
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.
Visual Studio c++ 2005
I am getting an error on the last line of this code.
int Utils::GetLengthDiff ( const char * input, int & num_subst )
{
int num_wide = 0, diff = 0 ;
const char * start_ptr = input ;
num_subst = 0 ;
while ( ( start_ptr = strstr ( start_ptr, enc_start ) ) != NULL )
{
char * end_ptr = strstr ( start_ptr, enc_end ); // Error
So I changed the line to this and it worked ok
const char * end_ptr = strstr ( start_ptr, enc_end );
So why would I need to declare end_ptr as a const as well?
Many thanks,
C++ has two overloaded versions of this function. http://www.cplusplus.com/reference/clibrary/cstring/strstr/
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
Since your start_ptr is const char * the C++ compiler resolves to call the version that takes a const char * as the first parameter, that version also returns a const char *, so you have to change your return value to match.
So why would I need to declare end_ptr as a const as well?
For the same reason that start_ptr needs to be const char*: strstr returns the type const char* (= char const*) because it searches inside a constant string (the parameter you pass to strstr is also const char*). In particular, it’s not the pointer that is const, it’s the memory it points to. Think of it as a pointer to an immutable (i.e. constant) string. You can change what it points to but not the individual characters inside the string.
This is different from an unchangeable pointer which points to a mutable string, i.e. a string where you can change individual characters.
Suppose that the return value from strstr were char*, with a const char* first parameter, as it is in C. Then you could write:
const char *s = "hello, world";
strstr(s, "hello")[0] = 'j';
The code would compile and run (with undefined behavior), but it's the kind of error which const was specifically designed to avoid. You've converted a const char* to char* without a cast.
C can't really do anything about it: if strstr returned const char* then you'd have to cast back to non-const explicitly in the case where the input is non-const and you want to modify the string. Because C++ has function overloading it can (and does) plug the loophole and make both cases work correctly. Hence in C++, the above code fails to compile, and so does your example code.
can any body tell me how to conver const char* to char*?
get_error_from_header(void *ptr, size_t size, size_t nmemb, void *data) {
ErrorMsg *error = (ErrorMsg *)data;
char* err = strstr((const char *)ptr,"550");
//error cannot convert const char** to char*
if(err) {
strncpy(error->data,(char*)ptr,LENGTH_ERROR_MESSAGE-1);
error->data[LENGTH_ERROR_MESSAGE-1] = '\0';
error->ret = true;
}
return size*nmemb;
}
There are a few things I don't understand here. I see that this is tagged for C++/CLI, but what I describe below should be the same as Standard C++.
Doesn't compile
The code you give doesn't compile; get_error_from_header does not specify a return type. In my experiments I made the return type size_t.
Signature of C++ strstr()
The signature for strstr() in the standard C library is:
char *
strstr(const char *s1, const char *s2);
but the signature for strstr() in the C++ library, depending on the overload, is one of:
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
I would choose the first overload, because you don't want to modify the string, you only want to read it. Therefore you can change your code to:
const char* err = strstr((const char *)ptr, "550");
if (err != NULL) {
...
}
Also, I'm assuming your comment reporting the error:
//error cannot convert const char** to char*
is a typo: there's no const char** to be seen.
Assignment to err unnecessary
As is pointed out in a previous answer, the use of err to store the result of strstr is unnecessary if all it's used for is checking NULL. Therefore you could use:
if (strstr((const char *)ptr, "550") != NULL) {
...
}
Use of reinterpret_cast<> encouraged
As is pointed out in another answer you should be using reinterpret_cast<> instead of C-style casts:
if (strstr(reinterpret_cast<const char *>(ptr), "550") != NULL) {
...
}
Use of const_cast<> to strip const
Given the example in the question, I don't see where this is necessary, but if you had a variable that you need to strip of const-ness, you should use the const_cast<> operator. As in:
const char * p1;
char * p2;
p2 = const_cast<char *>(p1);
As is pointed out in a comment, the reason to use const_cast<> operator is so that the author's intention is clear, and also to make it easy to search for the use of const_cast<>; usually stripping const is the source of bugs or a design flaw.
You don't appear to use err in the rest of that function, so why bother creating it?
if (NULL != strstr((const char *)ptr, "550"))
{
If you do need it, will you really need to modify whatever it points to? If not, then declare it as const also:
const char* err = strstr((const char *)ptr, "550");
Finally, as casts are such nasty things, it is best to use a specific modern-style cast for the operation you want to perform. In this case:
if (NULL != strstr(reinterpret_cast<const char *>(ptr), "550"))
{
Can't you just do:
char* err = strstr((char *)ptr,"550");
The error is because if you pass in a const char* to strstr you get one out (because of the overload).
//try this instead:
const char* mstr="";
char* str=const_cast<char*>(mstr);
Well is ptr (which you passed in as void*) actually const or not? (In other words, is the memory under your control?) If it's not, then cast it to char* instead of const char* when calling strstr. If it is, however, you'll get a const char* out (pointing to a location inside of the string pointed to by ptr), and will then need to strncpy out to another string which you are responsible for managing.
According to my deep research I have found numerous forums that have no direct solution or a reference answer to this question, I then delve into the GCC online documentation giving a brief read for their compiler properly docs and this is what I can provide.
In GNU C, pointers to arrays with qualifiers work similar to pointers to other qualified types. For example, a value of type int ()[5] can be used to initialize a variable of type const int ()[5]. These types however aren't compatible in ISO C because the const qualifier is formally attached to the element type of the array and not the array itself.
This description might be better understood if we take this
extern void
transpose (int N, int M, double out[M][N], const double in[N][M]);
double x[3][2];
double y[2][3];
…
transpose(3, 2, y, x);
Observing the above is that if you had an
s1=createStudent(s1, 123, "Poli");
s2=createStudent(s2, 456, "Rola);
Whereas the const char[5] for both "Poli" and "Rola" have correlation to a char a[]. It is strictly not permitted as each element has the qualifier attached and not the entire array as a const.