According to this site, I have done the following program which sorts strings.
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char list[5][4]={"dat","mai","lik","mar","ana"};
int main(int argc, char *argv[])
{
int x;
puts("sortirebamde:");
for (x=0;x>sizeof(list)/sizeof(char);x++)
printf("%s\n",list[x]);
qsort(&list,(sizeof(list)/sizeof(char)),sizeof(list[0]),strcmp);
system("PAUSE");
return EXIT_SUCCESS;
}
Here is the error I get
13 C:\Documents and Settings\LIBRARY\Desktop\string_sortireba.cpp invalid conversion from `int (*)(const char*, const char*)' to `int (*)(const void*, const void*)'
13 C:\Documents and Settings\LIBRARY\Desktop\string_sortireba.cpp initializing argument 4 of `void qsort(void*, size_t, size_t, int (*)(const void*, const void*))'
Please help
Please note: It is unusual to store C strings in two dimensional char arrays. It's more normal to have char *ary[], such as argv. That type cannot be sorted directly using qsort and strcmp, because qsort will pass char ** not char * to the comparison function. This is good for efficiency, the pointers can be swapped instead of the whole strings. The Linux manpage for qsort has some good example code with a correct comparison function.
You can't pass strcmp directly to qsort as its comparison function because qsort expects to pass pointers to void where strcmp expects pointers to const char. Given the required similarity between pointers to void and pointers to char, you could probably do it with a cast (for your code), but the cleaner way would be to write a function that takes the right types:
int cmpstr(void const *a, void const *b) {
char const *aa = (char const *)a;
char const *bb = (char const *)b;
return strcmp(aa, bb);
}
Note, however, that in C++ you'd normally want to use std::sort instead of qsort, and probably use std::string instead of char *, which case the sorting gets a lot simpler (and generally faster as well).
The fourth argument of qsort takes 2 void* pointers as args.So you need to define a compare function for yours.
refer to this link for more details.
You can pass strcmp directly to qsort
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char list[5][4]={"dat","mai","lik","mar","ana"};
int main(int argc, char *argv[]) {
int x;
puts("unsorted:");
for (x=0;x<sizeof(list)/sizeof(list[0]);x++)
printf("%s\n",list[x]);
qsort(list,sizeof(list)/sizeof(list[0]),sizeof(list[0]),strcmp);
puts("sorted:");
for (x=0;x<sizeof(list)/sizeof(list[0]);x++)
printf("%s\n",list[x]);
// system("PAUSE");
return EXIT_SUCCESS;
}
use C, not C++
Beyond why qsort fails, don't use it in C++.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
char const* const raw_data[5] = {"dat", "mai", "lik", "mar", "ana"};
std::vector<std::string> data (raw_data, raw_data + 5);
// would rarely be a global
// see below for code that needs to go here
int main() {
using namespace std;
cout << "before: " << data << "\n";
sort(data.begin(), data.end());
cout << "after: " << data << "\n";
return 0;
}
Boost has stream inserter overloads to output a vector directly, but here's one simple version. This goes into a header, rather than being copied and pasted continually:
template<class Stream, class Iter, class Ch>
void write_sequence(Stream& s, Iter begin, Iter end, Ch const* initial, Ch const* sep, Ch const* final) {
if (initial) {
s << initial;
}
if (begin != end) {
s << *begin;
++begin;
for (; begin != end; ++begin) {
if (sep) {
s << sep;
}
s << *begin;
}
}
if (final) {
s << final;
}
}
template<class T, class A>
std::ostream& operator<<(std::ostream& s, std::vector<T,A> const& value) {
write_sequence(s, value.begin(), value.end(), "[", ", ", "]");
return s;
}
More C++-Style - nowadays - with static_cast:
int scmp(const void * s1, const void * s2)
{
const char* _s1 = *static_cast<const char* const*>(s1);
const char* _s2 = *static_cast<const char* const*>(s2);
return strcmp(_s1, _s2);
}
And in main():
char *str_arr[] = { "one", "two", "three" };
qsort(str_arr, sizeof(str_array)/sizeof(char*), sizeof(char*), scmp);
Much easier is it with vector and std::sort.
Related
How can I pass a char pointer (char*) to the function func()?
#include <iostream>
using namespace std;
void func(char *var)
{
cout << var;
}
int main()
{
char* test = "Hello World";
func(test);
}
The compiler says:
Initialization: const char[12] cannot be converted to char *
A string literal is a const char[N] array in read-only memory (where N is the number of characters in the literal, plus 1 for the null terminator, so in your case 11+1=12). You can't point a char* pointer (ie, a pointer to non-const data) at a string literal, as that would allow for the possibility of altering read-only data, which is undefined behavior.
Simply change your pointer type to const char* instead (ie a pointer to const data), eg.
#include <iostream>
using namespace std;
void func(const char *var)
{
cout << var;
}
int main()
{
const char* test = "Hello World";
func(test);
}
Otherwise, as you say you have no control over the function declaration, then if you really want to pass a string literal to a char* pointer, you should copy the characters into a separate writable char[] buffer first, and then point at that instead, eg:
#include <iostream>
using namespace std;
void func(char *var)
{
cout << var;
}
int main()
{
char test[] = "Hello World";
func(test);
}
Or, if you know for sure that the function will never modify the characters, you can just cast off the const-ness using const_cast (though this is highly NOT recommended, I'm including it for completeness), eg:
#include <iostream>
using namespace std;
void func(char *var)
{
cout << var;
}
int main()
{
char* test = const_cast<char*>("Hello World");
func(test);
/* alternatively:
const char* test = "Hello World";
func(const_cast<char*>(test));
*/
}
This code would print the string "Hello World"
void func(char *var)
{
for( ;*var!='\0'; var++) { //!= from null terminator
cout<<*var;
}
}
int main()
{
char test[] = "Hello World";
func(test);
return 0;
}
I'm currently creating an app to launch external apps.
The signature to launch the external apps is:
int launchApp(int argc, char** argv); // argc = amount of arguments, argv = arguments
To add arguments to a std::vector<char *> structure I use the following lambda:
auto addArgument = [](std::vector<char *> & lArguments,
const std::string & sArgument)
{
auto cstr = new char[sArgument.size() + 1];
std::copy(sArgument.cbegin(), sArgument.cend(), cstr);
cstr[sArgument.size()] = '\0';
lArguments.push_back(cstr);
};
And launching an external app:
std::vector<char *> lArguments;
addArgument(lArguments, "Argument 1");
addArgument(lArguments, "Argument 2");
launchApp(lArguments.size(),static_cast<char**>(lArguments.data());
//... Clean up arguments
How would I do this in a RAII manner instead?
I was thinking of using a std::vector<std::vector<char>> instead. However, how can I then pass the underlying raw data (char**) to launchApp()? static_cast<char**>(lArguments.data()) wouldn't work...
I usually do this in two parts:
Build a std::vector<std::string> containing the actual arguments.
Build a std::vector<const char*> where each element is the .data() of the corresponding element in the vector of strings.
The first vector, and the strings contained within it, handle your allocation, resizing, etc. while the second simply acts as an index into the memory that is being managed by the first. The lifetime of your second vector should be shorter than that of the first, which you can guarantee by wrapping both in a class.
Example:
#include <string>
#include <vector>
#include <unistd.h>
int main() {
std::vector<std::string> args = {"echo", "hello", "world"};
std::vector<const char*> argv;
argv.reserve(args.size());
for (auto& arg : args) {
argv.push_back(arg.data());
}
execvp("echo", const_cast<char**>(argv.data()));
}
(Note the ugly const_cast. Depending on how you look at it, this is either because the exec* family of functions don't follow const correctness, or because std::string::data() does not have a non-const version (prior to C++17)).
Or, with the class to wrap it all up nicely:
#include <string>
#include <vector>
#include <unistd.h>
class ExecArguments {
public:
ExecArguments(std::initializer_list<std::string> arguments)
: args(arguments) {
for (auto& arg : args) {
argv.push_back(const_cast<char*>(arg.data()));
}
}
char** data() {
return const_cast<char**>(argv.data());
}
private:
std::vector<std::string> args;
std::vector<char*> argv;
};
int main() {
ExecArguments args{"echo", "hello", "world"};
execvp(args.data()[0], args.data());
}
Collect your parameters as regular strings.
Use an inner class that:
provides a transparent implicit view to a raw array of pointers, and
takes care of managing this pointer array at the same time.
An instance of this inner class is returned by some access method. Its lifetime spans the invoking statement. See below for an example:
#include <iostream>
#include <vector>
class CollectArgs : public std::vector<std::string> {
// just for providing the raw view and taking care of its memory
class RawArgs {
std::vector<char const*> m_argv;
public:
RawArgs(std::vector<char const*> argv) {
std::swap(argv, m_argv);
}
~RawArgs() {}
public:
operator char const* const*() const { return m_argv.data(); }
};
public:
RawArgs raw_args() const {
std::vector<char const*> argv;
for(std::string const &arg : *this) argv.push_back(arg.c_str());
return argv;
}
};
// the application launcher
void call(unsigned argc, char const *const *argv) {
for(unsigned i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
}
}
int main() {
CollectArgs args;
args.push_back("Arg1");
args.push_back("Arg2");
// create the raw view and have it destroyed immediately after this statement
call(args.size(), args.raw_args());
}
I have written a minimum class to better submit my problem.
I have three files:
1) test.hpp
#include <cstdlib>
#include <stdio.h>
#include <map>
class test {
public:
test () {}
~test () {}
const char *getPin (const char *);
private:
static const std::map<const char *, const char *> pinIndex;
static std::map<const char *, const char *> initializePins ();
};
2) test.cpp
#include "test.hpp"
const std::map<const char *, const char *> test::pinIndex = test::initializePins ();
std::map<const char *, const char *> test::initializePins () {
std::map<const char *, const char *> pins;
pins.insert (
std::pair<const char *, const char *> (
"AAAA", "BBBB"
)
);
return pins;
}
const char *test::getPin (const char *pinNumber) {
if (pinIndex.count (pinNumber) > 0) {
return pinIndex.at (pinNumber);
}
else {
printf ("Undefined pin %s!\n", pinNumber);
exit (EXIT_FAILURE);
}
}
3) main.cpp
#include "test.hpp"
int main () {
test myExample;
const char *a = myExample.getPin ("AAAA");
exit (EXIT_SUCCESS);
}
When I compile and run it I get this error:
Undefined pin AAAA!
If I remove main.cpp and put the main function in test.cpp file, I do not get me any error and GetPin returns the correct value.
Any idea what I'm doing wrong?
Thank you
Your problem is that you're using char* pointers in your map as key values. To find entries in the map, the implementation uses comparison operations (<) for the given key.
If you're going to compare char* pointers those will almost never be the same, and are completely unrelated to their contents, which is what you're actually want to look for.
A simple solution for your problem would be to change your map type to
std::map<std::string, std::string>
Another possible solution is to provide a class that compares two char* pointers based on content as the 3rd template parameter of the map
std::map<char*, char*, MyComparer>
where MyComparer is s.th. like this
struct MyComparer {
bool operator()( const char*& lhs, const char*& rhs ) const {
return strcmp(lhs,rhs) < 0;
}
};
As an explanation why you experience that seemingly inconsistent behavior, when moving your test to a separate compilation unit:
If you have the same string literals (e.g. "AAAA") appearing in the TU multiple times, the compiler can optimize them to be stored just once, and thus you'll have the same address for all of their appearances.
There is no guarantee that "AAAA" will have the same address as "AAAA" used somewhere else in your program. So finding "AAAA" is not guaranteed to work since the map will be comparing pointer values.
Use a std::map<std::string, std::string> instead of std::map<const char *, const char *>, and your issue should be resolved.
Your solution is quite simple:
#include <iostream>
#include <map>
#include <string>
int
main ()
{
std::map<std::string, std::string> pins { { "AAAA" , "BBBB" }, { "CCCC" , "DDDD" } };
auto lookup = pins.find("AAAA");
if (lookup != pins.end())
std::cout << "Pin AAAA found!" << std::endl;
else
std::cerr << "Pin AAAA not found!" << std::endl;
return 0;
}
A couple of suggestions:
Never use c-strings in C++ code. That is not faster but much more heavy to process. The std::string always knows ones length and performs better in comparisons.
Write as few as you can since KISS (keep it simple stupid) in 90% is the best idea.
I am trying to split a string the fastest way possible in C++. I am getting an error here:
#include <bitset>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/timer.hpp>
using namespace std;
size_t const N = 10000000;
template<typename C>
void test_strpbrk(string const& s, char const* delims, C& ret)
{
C output;
char const* p = s.c_str();
char const* q = strpbrk(p + 1, delims);
for (; q != NULL; q = strpbrk(p, delims))
{
output.push_back(typename C::value_type(p, q));
p = q + 1;
}
output.swap(ret);
}
int main()
{
typedef string::const_iterator iter;
typedef boost::iterator_range<iter> string_view;
vector<string_view> vsv;
test_custom(text, delims, vsv);
}
The Visual Studio says: cannot convert from 'const char *' to 'const std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>'
Can you please help me, should I enable any option in visual studio for this to work?
It seems you are trying to convert a char const* to a std::string::const_iterator, e.g., when passing arguments to functions creating a range: although std::string::const_iterator may be a typedef for char const* there is no requirement that this is the case. I don't think your code give enough context to pin-point the exact problem, though. You might want to look for locations where you pass a string literal or take the address of a section of a std::string (i.e. something along the lines of &str[index] or &*it).
Based on you edit, what I suspected above actually got confirmed! You'll need to translate the char const*s your are playing with back to std::string::const_iterators, e.g., by adding suitable offsets:
typename C::value_type(s.begin() + (p - s.c_str()), s.begin() + (q - s.c_str()))
I want to use qsort function to sort the characters in the strings using C++.
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
int compare_str(void const *a,void const *b){
char const *aa=(char const *)a;
char const *bb=(char const *)b;
if(*aa==*bb) return 0;
else if(*aa>*bb) return 1;
else return -1;
}
int main(){
string str="cake";
int len=str.length();
qsort(str,len,sizeof(str[0]),compare_str);
cout<<str;
return 0;
}
But it throws :
20 42 [Error] cannot convert 'std::string {aka std::basic_string<char>}' to 'void*' for argument '1' to 'void qsort(void*, size_t, size_t, int (*)(const void*, const void*))'
It would be great if anyone could provide an efficient way to do this.
I strongly recommend the modern method of
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
std::string s("cake");
std::sort(s.begin(), s.end());
std::cout << s << std::endl; // Prints "acek".
return 0;
}
Plus, using std::sort over qsort allows the compiler to optimize better, so it's a win-win...
Your comparator for qsort expects C strings, not C++ std::strings. You should either declare str to be char str[]
char str[] = "cake";
qsort(str, strlen(cake), sizeof(char), compare_str); // Consider renaming to compare_char
or (better) use std::sort:
string str = "cake";
sort(str.begin(), str.end());
If you really want to do this, just pass a pointer to the string's contents:
qsort(str.c_str(),len,sizeof(str[0]),compare_str);
That said, you really should consider using the functions provided in the STL rather than those from the old C library...
You should use the function sort() under the header <algorithm>. This function is very flexible and you can use it in different manner. For sorting as you wish in question you can just write:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s="cake";
sort(s.begin(), s.end());
cout << s << endl;
return 0;
}
//output: acek
again by using sort() we can implement it in a range. If you want to sort first two element , the code will be
sort(s.begin(), s.begin()+2);
for above code the output will be
//output: acke
so if we want to sort first n element then we can write
sort(s.begin,s.begin()+n);
we can also modify the sort function. In that case we have to pass three parameter instead of two. The third parameter will be a functions which returns a bool value.For example , if we want to sort in descending order then our code will be like this
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
bool desc(char i, char j)
{
return i>j;
}
int main()
{
string s="cake";
sort(s.begin(), s.end(),desc);
cout << s << endl;
return 0;
}
//output: keca
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
int compare_str(void const *a,void const *b){
char const *aa=(char const *)a;
char const *bb=(char const *)b;
if(*aa==*bb) return 0;
else if(*aa>*bb) return 1;
else return -1;
}
int main(){
string str="cake";
int len=str.length();
qsort(const_cast<char*>(str.c_str()),len,sizeof(str[0]),compare_str);
cout<<str<<endl;
return 0;
}