Pass a “char *“ pointer to a function - c++

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.

Related

warning: ISO C++ forbids converting a string constant to 'char*'

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(&currentByte, 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(&currentByte, 1);
//increments the pointer
file1.seekg(++index);
file2.seekp(index);
//reads the next value
file1.read(&currentByte, 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.

How to convert string to char* using stringstream?

I have a function like this:
template <typename T>
void parse_to_T(const std::string& str, T* result) {
std::stringstream ss;
ss << str;
ss >> *result;
}
this function is mean to convert the string to the specified type.
it is work to parse the string to int, float or char.
parse_to_T<int>(...);
parse_to_T<float>(...);
parse_to_T<char>(...);
but when meet char*, segment fault ...
I use the function like this:
int int_val;
string m = "1";
parse_to_T<int>(m, &int_val); // works
char* str_val = NULL;
parse_to_T<char*>(m, &str_val); // segmentfault
How to imply this function to make it work?
(convert the string to specified type like int, double, char, char*)?
Hey, I don't know how to explain my use case, but I will try:
To simple, the question is, given a file, for each line, data may have these types :
int
float
char
char*
an array T[num] (T is int, float, char or char*, or any build_in type.)
imple a parse function to parse this file.
and this problem is an exam ...
thanks and I found the error now.
char* str_val = NULL;
parse_to_T<char*>(m, &str_val); // segmentfault;
char* str_val;
parse_to_T<char*>(m, &str_val); // segmentfault;
char* str_val = new char[256];
parse_to_T<char*>(m, &str_val); // works !!
then the error is I didn't allocate memory to the ptr...
This segfault is because stringstream does not allocate memory to hold the result of the operation when extracting values into a char* array. It tries to put the values into the memory pointed at by the lhs operand. You must allocate memory yourself.
Here is a simple example:
#include <string>
#include <sstream>
#include <iostream>
template <typename T>
void parse_to_T(const std::string& str, T* result) {
std::stringstream ss;
ss << str;
std::cout << ss.str() << std::endl;
ss >> *result;
std::cout << *result << std::endl;
}
int main() {
char* buffer = new char[256];
/* Don't do this in real code. If the input is larger than
the size of the buffer it will end very, very badly.
always have a way of allocating the correct amount
of memory.
*/
int int_val;
std::string m = "1";
parse_to_T<int>(m, &int_val);
char* str_val = NULL;
parse_to_T<char*>(m, &buffer);
delete[] buffer;
return 0;
}
You could include a template specialization for the char* datatype that does the allocation based on the amount of data in the stream (calling stringstream.str().size() should work) but the user would have to free the returned memory.
First, your destination variable str_val has no allocated memory, so it is normal you have a segmentation fault.
On the other hand, it would be better if you use std::string instead. If you need the raw pointer const char* then you can use std::string::c_str for so. If you have to modify it then just create a copy.

return char array from function that passes parameters

I'm working with a piece of C++ code that reads lines from a txt file and then assign each line to to an array called lines. Then it calls a function that converts each element in the lines array to a char array and then return the resulted char array. This step is where I stuck. How could I return a char array from the function toChar and assign the returned array to another array so I can use it as I need? (the rest of the code should use each returned char array to write it in a pipe, this not important right now but just to clarify why I need to learn to return an array from a function)
Here is the code I'm using:
#include <fstream>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <cstdlib>
using namespace std;
char * toChar(string line);
int main()
{
string lines[0] = "line1";
char* a = toChar(lines[0]);
return 0;
}
char * toChar(string line)
{
char a[1024];
strcpy(a, line.c_str());
return a;
}
Please note that in this code I'm trying to shrink the code so I'm assigning a simple string value to the array
when I try to compile this code, the error below appears:
warning: address of local variable 'a' returned
any help or suggestion is greatly appreciated..
First use a const & in passing the string to the function to avoid the unnecessary copying, and be able to use temporaries, e.g. toChar("I am temp");
The are the following alternatives:
(1) Return std::string
std::string toChar(std::string const & line)
{
char a[1024];
strcpy(a, line.c_str());
return a;
}
Of course it is assumed that line is smaller than 1024 chars with the null termination symbol
(2) Return an allocated array the
char * toChar(std::string const & line)
{
char * a = new char[1024];
strcpy(a, line.c_str());
return a;
}
but you will have to actually manage it and delete it later.
(3) Allocate the array and pass it to the function
void toChar(string const & line, char a[])
{
strcpy(a, line.c_str());
}
I imagine that you actually want to extract a C-string from an std::string , or some part of it. The proper way to do it is (3).
The warning is correct and practically is an error. You're declaring the char array locally so it will be deleted after going out of scope of that function and its address will be no more valid.
Since you're using c++ avoid char array and use a std::string.
If you want to access to the internal storage of your string you can call line.c_str() which returns a const char *.
Hence you won't need you function toChar that creates a local array that will go out of scope at the end of your function.
You could simply do :
int main()
{
string lines[0] = "line1";
const char* a = lines[0].c_str();
return 0;
}
But I advise you to keep manipulating std::string as they will handle string better than a simple char *.
And if you want a copy, just do it : std::string mycopy = lines[0].

Simple serialization example in c++

I have the following struct:
typedef struct{
int test;
std::string name;
} test_struct;
Then, I have the following code in the main function:
int main(int argc, char *argv[]){
test_struct tstruct;
tstruct.test = 1;
tstruct.name = "asdfasdf";
char *testout;
int len;
testout = new char[sizeof(test_struct)];
memcpy(testout, &tstruct, sizeof(test_struct) );
std::cout<< testout;
}
However, nothing gets printed. What's wrong?
sizeof(std::string) yeilds same value always. It will not give you the runtime length of the string. To serialize using memcpy, either change the struct to contain char arrray such as char buffer[20] or compute the size of the required serialized buffer by defining a method on the struct which gives the runtime length of the bytes.
If you want to use members like std::string, you need to go through each member of the struct and serialize.
memcpy(testout, (void *)&tstruct.test, sizeof(int) );
memcpy(testout+sizeof(int), tstruct.name.c_str(),tstruct.name.length() );
memcpy against the entire struct will not work in such scenarios.
Try NULL-terminating the string and also emitting a newline:
testout = new char[sizeof(test_struct) + 1];
memcpy(testout, &tstruct, sizeof(test_struct));
testout[sizeof(test_struct)] = '\0';
std::cout<< testout << std::endl;
However, as user3543576 points out, the serialization you get from this process won't be too useful, as it will contain a memory address of a character buffer, and not the actual string itself.

C++ char* array

When I create something like
char* t = new char[44];
t = strcpy(s,t);
then strlen(t); return some wrong results. how I can change this?
Both strcpy and strlen expect to find the special character NUL or '\0' in the array. An uninitialized array, as the one you've created, may contain anything at all, which means the behavior of your program is undefined when it is passed to strcpy as the source argument.
Assuming the goal was to copy s into t, to make the program behave as expected, try this:
#include <iostream>
#include <cstring>
int main()
{
const char* s = "test string";
char* t = new char[44];
// std::strcpy(t, s); // t is the destination, s is the source!
std::strncpy(t, s, 44); // you know the size of the target, use it
std::cout << "length of the C-string in t is " << std::strlen(t) << '\n';
delete[] t;
}
But keep in mind that in C++, strings are handled as objects of type std::string.
#include <iostream>
#include <string>
int main()
{
const std::string s = "test string";
std::string t = s;
std::cout << "length of the string in t is " << t.size() << '\n';
}
What are you trying to do? Do you want to copy from s to t? If so, the arguments to strcpy are reversed.
char* t = new char[44]; // allocate a buffer
strcpy(t,s); // populate it
Such C-style string processing is a red flag, but that's all I can say given this little information.
This code might be helpful:
char * strcpy (char * destination, const char * source);
t = strcpy(t, s);
You have to initialize the variable t
Do something like this:
char *t = new char[44];
memset(t, 0, 44);
// strlen(t) = 0
The strcpy function is described thus:
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest.
So, if you are trying to fill in your newly allocated array, you should be doing:
strcpy(t, s);
Not the other way around.