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().
Related
I want to initialize a std::string with a single character. The following code doesn't work:
int main()
{
string s = 'c';
cout<<s;
return 0;
}
Error:
error: conversion from ‘char’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
string s = 'c';
But the following does work. Why is it so?
int main()
{
string s;
s = 'c';
cout<<s;
return 0;
}
Output:
c[Finished in 0.8s]
When you do
string s = 'c';
you are basically invoking constructor initialisation rather than an assignment operation. But there isn’t any constructor for std::string that takes only a single char as input. There is however one std::string(n, c), where n is the number of characters c in the string.
When you do
s = 'c'
you do an assignment operation, invoking the overloaded string::operator= (string& operator= (char c);) for std::string. Now this method is overloaded to accept a single char as input as well, as you can see from the code snippet at this reference as well as at this one.
std::string str1;
// ...
// (4) operator=( CharT );
str1 = '!';
Additionally, std::string::assign doesn’t accept a single char, similar to the constructor.
I'm trying to have an object named PReader (with a function named Execute(), taking no arguments) have a filename passed in through the constructor so Execute() can access it. The way I'm trying to set it up involves having the constructor allocate the memory for a string, then copy it over, and setting up a destructor for it. I know it's awkward, but I know this setup will make future additions to my project easier.
Here's how my object is currently set up:
#include <PReader.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
PReader::PReader(const char *f)
{
filename = new char[strlen(f)+1];
strcpy(filename, f);
}
PReader::~PReader()
{
delete [] filename;
}
void PReader::Execute(void)
{
FILE *f = fopen(this->filename, "rb");
...
}
This is giving me the error:
PReader.C: In constructor ‘PReader::PReader(char*)’:
PReader.C:10:20: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
strcpy(filename, f);
^
In file included from /usr/include/stdlib.h:11:0,
from PReader.C:2:
/usr/include/string.h:30:8: error: initializing argument 1 of ‘char* strcpy(char*, const char*)’ [-fpermissive]
char *_EXFUN(strcpy,(char *__restrict, const char *__restrict));
For so few lines of code, I'm kind of surprised I'm missing something here. What can I do to ensure that conversion succeeds how I want it?
EDIT: PReader.h:
#include "source.h"
#ifndef PREADER_H
#define PREADER_H
class PReader : public Source
{
public:
const char* filename;
PReader(const char *filename);
virtual ~PReader();
virtual void Execute();
};
#endif
It looks like you defined filename to be a const char*. Make it a char* instead, so you can actually modify it (using strcpy) :
char* filename;
Or better yet, since this is C++, why not make use of std::string ?
There is a difference between these two declarations
const char * filename;
and
char * const filename;
The first one declares a pointer to a constant object of type const char. The pointer itself can be changed for example as ++filename but the object that pointed by the pointer may not be changed as for example ++*filename. So you may not use such a pointer in function std::strcpy as the first argument.
The second one declares a constant pointer to a non-constant object. So the pointer itself may not be changed. For example the compiler will issue an error for expression ++filename. But you may change the object pointed to by the pointer. For example ++*filename; Such a pointer you may use as the first argument in function std::strcpy.
And at last you can define non-constant pointer that points to a non-constant object
char * filename;
In this case you can change the pointer itself and change the object pointed by the pointer.
So in your class ypu should define filename either as
char * const filename;
or as
char * filename;
Take into account that pointers can be defined as
const char * const filename = "String Literal";
that is this statement defines a constant pointer to a constant object. You may change neither the pointer itself nor the object pointed by the pointer.
The equivalent declaration is
const char * constexpr filename = "String Literal";
In your header, you have
const char* filename;
and you are trying to strcpy into it. This is not allowed. Change that to
char* filename;
I'm trying to use the function with the following declaration:
extern int stem(struct stemmer * z, char * b, int k)1
I'm trying to pass a C++ string to it, so I thought I'd use the c_str() function. It returns const char *. When I try to pass it to the stem() function, I get this error: error: invalid conversion from 'const char*' to 'char*' [-fpermissive].
How can I store the result of c_str() such that I can use it with the stem function?
Here is the code I'm running:
struct stemmer * z = create_stemmer();
char * b = s.c_str();
int res = stem(z, b, s.length()); //this doesn't work
free_stemmer(z);
return s.substr(0,res);
The problem you are having is that c_str() returns a buffer that can not be modified (const), while stem() may modify the buffer you pass in (not const). You should make a copy of the result of c_str() to get a modifiable buffer.
The page http://www.cplusplus.com/reference/string/string/c_str/ has more information on the C++ 98 and 11 versions. They suggest replacing char * b = s.c_str(); with the following:
char * b = new char [s.length()+1];
std::strcpy (b, s.c_str());
You shouldn't try to remove constness of a string returned by c_str():
char * b = s.c_str();
but you can pass an address of std::string's internal buffer directly:
int res = stem(z, static_cast<char*>(&s[0]), s.length());
If stem() is going to modify the string, then make a copy of it:
char * scpy= strdup( s.c_str()) ;
int res = stem(z, scpy, strlen( scpy));
free( scpy) ;
Use const_cast:
int res = stem(z, const_cast<char*>(s.c_str()), s.length()+1);
free_stemmer(z);
return s.substr(0,res);
Note the length+1 expression which might (or might not) be needed. C-style strings (char*) have an additional null terminator (zero byte, equivalent "\0") at the end. Your stem function may (or may not) expect a null terminator at the end of the string - try both variants.
Note also that "stem" function should not try to modify the string, otherwise bad things may happen (warning based on #David Heffernan's comment)
.c_str()
Just returns a pointer to the data, I would update the stem function to accept a 'const char*' unless you are wanting to modify the data in the string, in that case you should pass it as a new string object.
If you can't edit the stem function you can cast it:
int res = stem(z, const_cast<char*>(s.c_str()), s.length());
It's not good to do this, but nothing stops you:
#include <iostream>
#include <string>
using namespace std;
void foo(char *ch)
{
ch[0] = 'B';
}
int main()
{
string str = "helo world";
char *ch = const_cast<char *>(str.c_str());
foo(ch);
// Belo world
cout << str << endl;
return 0;
}
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) ));
The function char* strrchr(const char *str, int ch) returns a pointer (char*) within str (const char *) where the last occurrence of ch is located.
So we can write the following code without any cast:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *ptr = strrchr (CONSTSTR, '/');
*ptr++ = 'B';
*ptr++ = 'A';
*ptr++ = 'D';
}
What is the advantage to return char* instead of const char* ?
EDIT:
As a Shafik Yaghmour pointed out, there are very good answers to How does strchr implementation work?
As my code is in C++, I will use <cstring> instead of <string.h>. Thanks for your answers ;-)
However, the Mike Seymour's answer fits best the question. I have even added a more detailed answer below to clearly say as strrchr() is a C function (overload not permitted), the declaration fits both const and non-const strings. Because strrchr() can be called with a non-const string, the returned string should also be non-const.
You're looking at the legacy function from the C standard library (<string.h>). The C++ library (<cstring>) introduces appropriate const and non-const overloads, so you should use that wherever possible.
In C, the function must either be like this, or force the user to use dodgy casts in many situations:
If it took a non-const pointer, you couldn't search a const string;
If it returned a const pointer, you couldn't use it to modify a non-const string.
In C++, you should include <cstring> rather than the deprecated C-only header. That will give you two const-correct overloads, which couldn't be done in C:
const char* strchr(const char* s, int c);
char* strchr( char* s, int c);
const char *str means strrchr guarantees not to modify str.
Returning const char * means strrchr forbids you to modify the returned value.
strrchr() from <string.h> is a C function. As C does not permit function overloading, strrchr() has been designed to fit both const and non-const strings.
char* strrchr( const char *str, int ch );
strrchr() may be called with a non-const string, and therefore the returned string should also be non-const as explained in the following examples.
const context without compilation error:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
const char *basename = strrchr (CONSTSTR, '/');
// basename points to "foobar.txt"
}
non-const context without compilation error:
#include <string.h>
int main()
{
char nonconst[] = "foo/bar/foobar.txt";
char *basename = strrchr (nonconst, '/');
basename[0] = 'G';
basename[3] = 'D';
// basename points to "GooDar.txt"
}
Bad usage also without compilation error:
#include <string.h>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *nonconst = strrchr (CONSTSTR, '/');
*nonconst++ = 'B';
*nonconst++ = 'A'; // drawback of the unique declaration:
*nonconst++ = 'D'; // no compilation error
}
In C++, there are two overloaded functions:
const char* strrchr( const char* str, int ch ); //1st
char* strrchr( char* str, int ch ); //2nd
const context uses the 1st one:
#include <cstring>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
const char *basename = std::strrchr (CONSTSTR, '/');
// basename points to "foobar.txt"
}
non-const context uses the 2nd one:
#include <cstring>
int main()
{
char nonconst[] = "foo/bar/foobar.txt";
char *basename = std::strrchr (nonconst, '/');
basename[0] = 'G';
basename[3] = 'D';
// basename points to "GooDar.txt"
}
Bad usage should produce compilation error:
#include <cstring>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *nonconst = std::strrchr (CONSTSTR, '/');
// Visual C++ v10 (2010)
// error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
*nonconst++ = 'B';
*nonconst++ = 'A';
*nonconst++ = 'D';
}
But this last example does not produce any compilation error using g++ -Wall file.cpp. Tested using GCC versions 4.1.2 (RedHat) and 4.7.2 (MinGW).
Why would you forbid the code from modifying a returned variable? Mind that const char * is not char * const, you would be allowed to modify the character in any case, but you won't have control on the returned value itself, which doesn't make much sense since you could want to change it and edit the underlying string in a different position for your purpose.