I just started learning C++, and during compilation my code I get an error:
main.cpp:59:50: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
Encryption delta("dragons.txt", "output1.txt");
I don't know what this error means, or how to make it work, so if somebody could explain to me why this is happening and how to fix that, I would be very grateful :)
#include <iostream>
#include <fstream>
using namespace std;
class Encryption
{
fstream file1; //source file
fstream file2; //destination file
public:
Encryption::Encryption(char *filename1, char *filename2)
{
file1.open(filename1, ios::in | ios::out | ios::binary);
file2.open(filename2, ios::out | ios::binary);
}
//encrypts the file
void Encrypt(void)
{
char currentByte;
bool currentBit;
int index = 0;
//sets the pointers to the beginning of the file
file1.seekg(0, ios::beg);
file2.seekp(0, ios::beg);
//reads the first value
file1.read(¤tByte, 1);
while (file1.good())
{
//loop for four bits
for (int c = 0; c < 4; c++)
{
//finds out if the first bit is a one
currentBit = (int)((unsigned char)currentByte / 128);
//shifts the byte over
currentByte <<= 1;
//if the first bit was a one then we add it to the end
if (currentBit)
{
currentByte += 1;
}
}
//writes the character
file2.write(¤tByte, 1);
//increments the pointer
file1.seekg(++index);
file2.seekp(index);
//reads the next value
file1.read(¤tByte, 1);
}
}
//closes both of the files
void close(void)
{
file1.close();
file2.close();
}
};
int main(void)
{
cout << "Welcome to the S.A.S encryption program.";
Encryption delta("dragons.txt", "output1.txt");
delta.Encrypt();
delta.close();
Encryption gamma("output1.txt", "output2.txt");
gamma.Encrypt();
gamma.close();
return 0;
}
To quote what is a literal type
Literal types are the types of constexpr variables and they can be constructed, manipulated, and returned from constexpr functions.
Essentially these are entities that can be used at compile time. Since they are constexpr, so for one thing, these are const, therefore, read-only. To fix that, you need to change to
Encryption(char const* filename1, char const *filename2)
Also, you don't need to scope the constructor of Encryption class with Encryption:: since it's defined within the class itself, so just remove that. Else your program won't compile.
Encryption::Encryption(char *filename1, char *filename2)
{
// ...
}
Since you don't intend to modify the characters which filename1, filename2 point to, you should declare them as const char *. Otherwise, informally speaking, the compiler is worried that you might do so, which would not be allowed for a string literal.
Also, since you are defining this function inside the definition of the class Encryption, you don't need to restate that with Encryption::. So change this line to
Encryption(const char *filename1, const char *filename2)
{
// ...
}
String literals are const char[] types in C++. Since C++11 onwards, string literals cannot be assigned to non-const char* pointers. Doing so would allow code to mutate a string literal's data, which is undefined behavior. This assignment was allowed prior to C++11, for backwards compatibility with C, but it was always discouraged.
If you want to pass string literals to Encryption(), you need to change the types of its parameters to const char* (or char const *) instead:
Encryption::Encryption(const char *filename1, const char *filename2)
{
file1.open(filename1, ios::in | ios::out | ios::binary);
file2.open(filename2, ios::out | ios::binary);
}
Especially since that is what fstream::open() takes in anyway, and you are not altering that parameter in any way:
void open( const char *filename,
ios_base::openmode mode = ios_base::in|ios_base::out );
As the warning tells you, converting a string constant to char* - which is not a constant - is not allowed.
The reason for this is that you can theoretically change the contents of a char*. But string constants (literals) are read-only.
Therefore you should use const char* as parameter type in your method.
Related
I set up a class to read the file.
Pass a pointer of type char * to the function, which writes the file to the memory unit that the pointer points to.
Finally, I look forward to reading the contents of the file through the pointer outside the function.
But the result didn't live up to expectations.
Inside the program, there is a result output.
But on the outside, there are no results. I don't know why.
#include <fstream>
#include <stdlib.h>
namespace my
{
class File
{
File() = default;
~File() = default;
bool ReadTo(char * _out, const char * _path);
}
}
bool my::File::ReadTo(char * _out, const char * _path)
{
std::ifstream fs;
//infs lengfsh;
fs.open(_path);
fs.seekg(0, std::ios::end);
long len = fs.tellg();
//goes well at this,output normally
printf("my::File::ReadTo >> len:%d\n",len);
fs.seekg(0, std::ios::beg);
_out = (char *)malloc(sizeof(char) * len);
fs.read(_out, len);
//goes well at this,output normally
printf("my::File::ReadTo >> out:%s\n",_out);
fs.close();
return true;
}
int main()
{
char * txt;
my::File mf;
mf.ReadTo(txt,"x:\\xxxx\\demo.txt");
// result shows : NULL
debug("demo.txt >> \n %s\n",txt);
}
The argument char * _out will be a copy of what is passed, so modifying that won't affect what is passed.
You should add & to that (both declaration and definition) like char * &_out to make it a reference so that modification to that will be refrected to what is specified as the argument in caller.
Also make sure what is read is a C-style string (a sequence of character terminated by a null-character). In other words, don't test your program with a file that doesn't contain any byte having value 0x00. Otherwise, the printf() will go reading out-of-range and something dangerous may happen.
Here is a part of the code that seeks to display the names of people that have blood group as a+ or ab+.
//class definition
class bloodbank
{
int idno;
char doname[30];
char group[3];
//the function i am talking about
void blood()
{
bloodbank b;
int count =0;
ifstream fin("donor.dat",ios::binary);
if( (strcmp(b.retgroup(),'A+')==0) ||(strcmp(b.retgroup(),'AB+')==0 ) )
{
b.display();
count++;
fin.read((char*)&b,sizeof(b));
}
fin.close();
cout<<"No of records"<<" "<<count;
}
}
i am confused whether i have to put "A+" or just 'A+'.
if i put "A+", i get count as 0.
'A+' is a multicharacter literal in C++. It has an int type, but the value is implementation-defined, although 'A' * 256 + '+' is common.
As such they are rarely used.
You want "A+". That is a const char[3] type that decays to a const char* pointer which strcmp can use.
Finally, you're using C++. Why not use std::string rather than those char[] types? Then you could write b.retgroup() == "A+" and so on rather than those strcmp calls. Or if you need to retain the char[] for some reason, you could use, from C++14 onwards, the flashy Yoda-expression
"A+"s == b.retgroup()
FYI: the answer provided was wrong, I have found an answer, they are written below.
In an exam question, was given a function prototype
void store(double *ptr, unsigned int length, char filename[]);
we are asked to call this function in order to do stuff... (not relevant to my question now).
but we need to pass a filename for reading. and it must be received by this filename[] char array.
below is the answer that is provided. (it's a previous years' exam).
#include <iostream>
using namespace std;
#define SIZE 10
int main(void)
{
const char *filename = "array.dat";
double a[SIZE];
for ( unsigned n = 0; n < SIZE; n++ )
a[n] = 0.0;
store(a, SIZE, filename); // if simply send "array.dat" as parameter it works.
return 0;
}
however, this does not compile to me. in my mind it doesn't compile either, because I can't assign a c-style string like this to a char array, in this way, or so i believed. I've searched a fair bit, i just need some clarity on this. thanks.
The line
const char *filename = "array.dat";
defines filename to be of type const char*. It cannot be used as an argument to store since store expects char [] type.
Change the declaration of filename to:
char filename[] = "array.dat";
If the store function doesn't need to change the filename content then it should be a const. The function prototype is not well and you have to do some workaround. Copy the string to a non-const array and pass it instead, or just use a non-const string.
char filename[] = "array.dat";
I'm porting my game from GNU/Linux to Windows, using Visual C++.
Here is the problem:
std::stringstream sstm;
/// *working on stringstream*
const int size = sstm.str().size();
char buffer[size];
std::ofstream outfile("options", std::ofstream::binary);
for(int i = 0; i < size; i++)
buffer[i] = sstm.str().at(i);
outfile.write(buffer, size);
outfile.close();
It says: "expression must have a constant value" in declaration of buffer.
I have changed it to this:
std::vector<char>buffer(size);
And then VC says: "cannot convert parameter 1 from 'std::vector<_Ty>' to 'const char *'" at outfile.write().
const int size = sstm.str().size();
char buffer[size];
buffer is a variable length array (VLA) here. That's illegal code per C++ standard - size of an array needs to be known at compile time. VLA'a are allowed in C99 and G++ allows it as an extension in C++.
const int can be a compile time constant if it's initialiized with a literal or by a ˙constexpr. In your case, it's not.
You're almost there - vector<char> is a proper way to do it. To pass it to ostream::write() you can say buffer.data() or &buffer[0]-
You do know that sstm.str() creates a new string for each call? That will be a lot of strings, if the buffer is large.
You could get away with creating just one copy of the string:
std::stringstream sstm;
/// *working on stringstream*
std::string buffer = sstm.str();
std::ofstream outfile("options", std::ofstream::binary);
outfile.write(buffer.c_str(), buffer.size());
outfile.close();
I have followed the code example here
toupper c++ example
And implemented it in my own code as follows
void CharString::MakeUpper()
{
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
char* c;
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
}
But this gives me the following compiler error
CharString.cpp: In member function 'void CharString::MakeUpper()':
CharString.cpp:276: error: invalid conversion from 'char*' to 'int'
CharString.cpp:276: error: initializing argument 1of 'int toupper(int)'
CharString.cpp: In member function 'void CharString::MakeLower()':
This is line 276
putchar (toupper(c));
I understand that toupper is looking for int as a parameter and returns an int also, is that the problem? If so how does the example work?
Also,
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
is not valid C++ - arrays must be dimensioned using compile time constants - this is a C99 feature. And I really don't think the code would do what you want it to, even if it were legal, as you seem to be accessing one past the end of the array. It would be handy if you posted the complete class definition.
I don't think your code does what you want it to do and in fact if it compiled it would explode.
char* str[strlen(m_pString)]; // you've made an array of X C strings where
// X is the length of your original string.
int i=0;
str[strlen(m_pString)]=m_pString; // You've attempted to assign the C string in your array
// at location X to point at you m_pString. X is the
// same X as before and so is 1 past the end of the array
// This is a buffer overrun.
I think what you actually wanted to do was to copy the content of m_pString into str. You'd do that like so:
char * str = new char[strlen(m_pString)];
memcpy(str, m_pString); // I may have the operands reversed, see the docs.
The easier way to do this though is to stop using C strings and to use C++ strings:
std::string str = m_pString;
There are more issues, but this should get you steer you more toward the right direction.
You need to feed toupper() an int (or a char) instead of a char *, which is how you've declared c.
try:
char c;
Also,
char* str[strlen(m_pString)];
is an an array of pointers to characters, not just a single string.
This line:
str[strlen(m_pString)]=m_pString;
is an assignment to a bad pointer then, since there was no allocation.
I'm going to go with the assumption that m_pString is a C style string (char *). You're doing way more fiddling than you need to be doing.
void CharString::MakeUpper()
{
char* str = m_pString; // Since you're not modifying the string, there's no need to make a local copy, just get a pointer to the existing string.
while (*str) // You can use the string pointer as an iterator over the individual chars
{
putchar (toupper(*str)); // Dereference the pointer to get each char.
str++; // Move to the next char (you can merge this into the previous line if so desired, but there's no need.
}
}
In the example you cite, the reason it works is because of how the variables are declared.
int main ()
{
int i=0;
char str[]="Test String.\n"; // This is a compile time string literal, so it's ok to initialize the array with it. Also, it's an array of `char`s not `char*`s.
char c; // Note that this is also a `char`, not a `char *`
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
return 0;
}
Because of the error-prone ways of using C strings, your best bet is std::string:
void CharString::MakeUpper()
{
string str(m_pString);
transform(str.begin(), str.end(), ostream_iterator<char>(cout), &toupper);
}
There is not a built-in conversion from char * to int, which is why the error occurs. Since you're trying to capitalize a character, you need to dereference the pointer.
putchar(toupper(*c));