Given an old-style const char * pointer and a length, is there a way to call std::regex_search() on it without first copying the contents of the buffer into a std::string? Here is a simple example of the problem I have:
#include <regex>
int main()
{
const char *text = "123 foobar 456";
const size_t len = strlen(text);
const std::regex rx(" (.+)bar");
std::smatch what;
std::regex_search( text, text+len, what, rx); // <- problematic line
return 0;
}
I thought the 5th std::regex_search() that takes two iterators is what I need, but I'm not fully understanding how to convert pointers to iterators. When I try to compile the code above, I get this:
g++ -std=c++11 test.cpp
test.cpp:11:45: error: no matching function for call to ‘regex_search(const char*&, const char*, std::smatch&, const regex&)’
/usr/include/c++/4.9/bits/regex.h:2131:5: note: template<class _Bi_iter, class _Alloc, class _Ch_type, class _Rx_traits> bool std::regex_search(_Bi_iter, _Bi_iter, std::match_results<_BiIter, _Alloc>&, const std::basic_regex<_CharT, _TraitsT>&, std::regex_constants::match_flag_type)
regex_search(_Bi_iter __s, _Bi_iter __e,
...and a lot more errors!
Can const char * be converted to the necessary iterator? Did I do it wrong? Am I misunderstanding how this works?
The error in your code is that you're using the wrong match_results type. smatch is supposed to be used when you have an std::string object and you're passing std::string::iterators to the regex function. When you have raw char const *s use cmatch instead.
Change
std::smatch what;
to
std::cmatch what;
Live demo
Related
I have a vector of string constructed using:
vector<string> names;
names.push_back("Gates");
names.push_back("Jones");
names.push_back("Smith");
names.push_back("Gates");
I want to replace "Gates" with "Bill", for every occurrence of "Gates".
For this the easiest solution I know is to use the replace function from algorithm and use it as:
replace(names.begin(), names.end(), "Gates", "Bill");
But I am getting following error:
parameter type mismatch:incompatible types 'const char (&)[6]' and 'const char[5]'.
I can solve it using implicit type casting like this:
replace(names.begin(), names.end(), "Gates", (const char (&)[6]) "Bill");
Can anyone explain what this error is, and better way to solve it or better way to do it. Or why do we need this type casting.
The old/new value parameters in std::replace share the same type.
For example, the function might look like:
template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last, const T& old_value, const T& new_value);
Stolen from here, not that it's that significant.
"gates" is a const char[6] but bill is a const char[5], which is why you get the error about being unable to convert it.
You could either wrap each string literal in std::string() or just use the unary + operator to decay each literal to a const char*.
replace(names.begin(), names.end(), +"Gates", +"Bill"); //shorter
replace(names.begin(), names.end(), std::string("Gates"), std::string("Bill")); //clearer
I'm pretty sure ((const char (&)[6]) "Bill") violates strict aliasing, so I'd avoid casting between array types like that.
I would suggest (assuming some using std;)
replace(names.begin(), names.end(), string{"Gates"}, string{"Bill"});
since the type of "Gates" is char[6] (decayed to char*) and you want to replace std::string-s (not char* !!).
I am new to C++
and I know I shouldn't be using printf in c++ while I have cout but this was for experiment sake.
My Question here is Why we have to convert a string to c_str (c string) while passing to printf in c++ while it works fine without converting in cout.
Below is my code
#include<iostream>
#include<stdio.h>
using namespace std;
class A{
int i;
string str;
public:
A (int value, const string & s) : i(value), str(s){};// constructor
// setters
void setvalue(int value) {i = value;}
void setstr(const string & s) {str = s;}
//geters
int get_value() {return i;}
string get_str() {return str;}
const char *get_str_cstr() {return str.c_str();}// I didn't get why we have to declare constant
};
int main(){
// new code
A obj1 = {11, "Jill"};
cout<<"value is : "<<obj1.get_value()<<" string is "<<obj1.get_str()<<endl;
// Now we wil change the values in A
obj1.setvalue(2);
obj1.setstr("Jack");
cout<<"value after change is : "<<obj1.get_value()<<" string after change is "<<obj1.get_str()<<endl;
// now we will use printf where get_str dosen't not work
//Error: for below commented printf function
/*In function 'int main()':|
error: cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'|
||=== Build finished: 1 errors, 0 warnings (0 minutes, 0 seconds) ===|
*/
//printf("Value is %d and String is %s",obj1.get_value(),obj1.get_str());
// hence we declare a new char * get_str_cstr to make it work in printf;
printf("Value is %d and String is %s",obj1.get_value(),obj1.get_str_cstr());
return 0;}
I have also provided the error in program comments.
Thank you!
printf comes from C library, which predates objects, templates, and function overloading. When you specify %s format, the function takes an address of a null-terminated character sequence, and prints it. printf has no idea where the string comes from. In fact, it has no idea of its parameter types, because it uses variable-length parameter list feature.
std::string is a C++ string. Calling c_str() on it produces a pointer to the beginning of a C string, which is suitable for passing to printf and other functions expecting a C string.
cout, on the other hand, has been built with classes and overloading in mind. There is a special overload for operator << for std::string, which lets cout and other output streams extract characters from a C++ string.
printf is originally from C, which does not have std::string, so the analogous argument type is const char* which is what you get when you call .c_str()
The reason std::cout works with std::string is because operator<< is defined for that class.
Because printf() has no idea what a std::string is. The protypes for printf() are
int printf( const char* format, ... );
int fprintf( std::FILE* stream, const char* format, ... );
int sprintf( char* buffer, const char* format, ... );
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );
The reason std::string works with cout is that std::string provieds operator << which works with cout
string is a class in c++ stl.
c_str() is a member function of class string .
The signature is:
const _CharT* c_str() const { return _M_start; }
now, coming to printf, its signature is:
int printf ( const char * format, ... );
now, as long as you give it an argument that meets const char * format, it accepts it.
I am trying to swap two points on const char with real call-by-reference. But I have problems.
void swap(const char *&str1, const char *&str2) { //swap char pointers
const char *one = str1;
str1 = str2;
str2 = one;
}
int main(void){
const char *str1 = "Apple";
const char *str2 = "Potato";
swap(*str1, *str2);
return 0.0;
}
I keep on getting this error:
invalid conversion from 'char' to 'const char'
You shouldn't be dereferences the pointers when calling swap. You need to call:
swap(str1, str2);
Or, better still, use std::swap.
Also, if you're trying to run the code you've written they you'll need to either prototype swap or swap the functions around:
void swap(const char *&str1, const char *&str2)
{
const char *one = str1;
str1 = str2;
str2 = one;
}
int main(void)
{
const char *str1 = "Apple";
const char *str2 = "Potato";
swap(str1, str2);
return 0;
}
Also, main returns an int, not a float
You should use std::swap (located in either the <algorithm> or <utility> header) instead of rolling your own:
std::swap(str1, str2);
Also, you should consider using std::string instead of const char* in general:
std::string str1 = "Apple";
std::string str2 = "Potato";
of course the std::swap algorithm will still work just fine.
And finally, neither void in the argument list of main nor return 0.0 are necessary in C++.
Here's the code revisited with the advices above:
#include <algorithm>
#include <string>
#include <iostream>
int main() {
std::string str1 = "Apple";
std::string str2 = "Potato";
std::swap(str1, str2);
}
and here's the live example.
In response to Mr. Cthulhu down here, I'll try to answer the question more explicitly.
Your error is caused by the fact that by dereferencing the pointers of type const char* you are actually getting an expression of type const char& which is obviously incompatible with the type expressed in your swap function. Here's the correct call to the function:
swap(str1, str2);
But the again, why replicating the code of std::swap? (this is a rhetorical question, in case you were wondering wether to flag this as "not an answer")
You're defining swap() after you're calling it. In C++, functions should be defined before they are called. Move the definition of swap() to the top of the file, above main(). You will then get this error:
test.cpp:11: warning: converting to ‘int’ from ‘double’
Your main() function should return 0 (an int), not 0.0 which is a double.
Fixing this, you'll finally get this error:
test.cpp: In function ‘int main()’:
test.cpp:10: error: invalid initialization of reference of type ‘const char*&’ from expression of type ‘const char’
test.cpp:1: error: in passing argument 1 of ‘void swap(const char*&, const char*&)’
This is because you're dereferencing your arguments to swap(). Remove the * and the program now works fine.
However, you should simply remove your swap() function altogether, #include <utility>, and use std::swap().
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) ));
Is it possible to do something like:
const char* str = "AaBbCc";
string str_up = boost::to_upper_copy(str); // str_up will be "AABBCC"
Last line doesn't compile.
Of course I can as below, but it less "canonical":
const char* str = "AaBbCc";
string str_up = str;
boost::to_upper(str_up);
The declaration of to_upper_copy is:
template<typename SequenceT>
SequenceT to_upper_copy(const SequenceT &, const std::locale & = std::locale());
From this it should be clear that SequenceT can't be a pointer to char, or even a char array, because there's no (good) way how the returned copy could have the same type.
You can explicitly force the type to be string:
string str_up = boost::to_upper_copy<string>(str);
Here's explanation what SequenceT and RangeT mean in the documentation: String Representation. In short, neither can be a const char*, but RangeT arguments accept arrays (char [X]).
Why not post the right solution as an answer to the question?
const char* str = "AaBbCc";
std::string str_up = boost::to_upper_copy(std::string(str));
Credits to Konrad.
Sure!
inline std::string to_upper_copy(std::string const & src) {
std::string res(src);
boost::to_upper(res);
return res;
}