I have this structure:
struct student {
int id;
string name;
string surname;
};
What I need to do is to make function with this declaration:
char* surname_name (student Student)
which will format every Student that I put in format like this "surname, name" and it will bring back pointer on it.
What I've done so far is this:
char* surname_name (student Student){
char *pointer= (char*) malloc (sizeof(char)*(Student.name.length + Student.surname.length + 2)); // + 2 because of space and comma
string::iterator it;
int i=0;
for (it= Student.surname.begin(); it != Student.surname.end(); it++){
(*pointer)[i] = it; // here it gives me error
}
... // here still should be added code for comma, space and name
return pointer;
}
I can't make it anyhow else, because it's in the task that function needs to have this declaration. How to make this properly?
This should do the trick:
char * surname_name (student Student){
return strdup((Student.surname + ", " + Student.name).c_str());
}
(*pointer)[i] = it;
should be
*(pointer+i) = *it; //assigning the current char to correct position
you should also increase i properly.
You can also do it with std::string which can do simple concatenation.
I prefer to use std::string::c_str:
string surname_name (const student &Student)
{
return Student.name + " " + Student.surname;
}
// ...
do_something( surname_name(student).c_str() );
If you really want to return a pointer, you can do it as below:
char *surname_name (const student &Student)
{
string s = Student.name + " " + Student.surname;
char *p = new char [s.length()+1];
strcpy(p, s.c_str());
return p;
}
Don't forget to delete the returned pointer.
Related
Here is a problem. When I try to convert it by using strncpy_s, array has some type of "trash data" from memory in the end of it. Even when I fill buffer with "\0". How to convert it clear?
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
strncpy_s(text, strin.c_str(), sizeof(text) - 1);
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
The idea to use c_str() function to convert the std::string to a a-string. Then we can simply call strcpy() function to copu the c-string into char array
std::string s = "Hello World!";
char cstr[s.size() + 1];
strcpy(cstr, s.c_str()); // or pass &s[0]
std::cout << cstr << '\n';
return 0;
When using the strncpy_s function you tell it to copy as many chars as will fit into your buffer "text". Since the string you create the "example" instance with is shorter, the copy function will keep going after the end of the actual string.
That is where your garbage comes from. Even worse you risk a Segmentation Fault this way. Your code might access parts of the RAM it is not allowed to read from. That will cause it to crash.
You are right though to copy the data pointed to by the return of c_str(). The pointer returned by c_str() points to data that belongs to the std::string object and might be changed or even invalidated by that object. (Read more here)
Here's a modified version of your code that should avoid the garbage:
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
if(strin.length()+1 <= sizeof(text)) {
strncpy_s(text, strin.c_str(), strin.length()+1);
} else {
//some error handling needed since our buffer is too small
}
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
Can I get some advise?
Instead of returning the vector from the function as a pointer or a reference, I am returning it as a string which contains the address. (I had good reason for this).
^That part was successful, the part I can't seem to figure out is, how to take that returned string(which holds an address of a vector) and make a new vector with it.
This is the vector (of type struct) that was passed from the function in a string containing its memory address:
vector<intructor> intruct;
Converting vector's address to a string: successful
string address;
stringstream ss;
ss << &depart;
ss >> address;
return address;
My attempt to convert it back in a new vector: failed
vector<intructor> getIntructorVector(string filePath)
{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor> intruct;
ss << address;
ss >> &intruct;
return intruct;
}
If you need to know, this is what the vector holds:
struct intructor {
string name;
string dept;
int id;
};
I'll give the traditional StackOverflow caveat of "you probably don't actually want to do this" -- manually manipulating pointers at all is generally discouraged in modern C++, and there are a lot of Bad Things that can happen between allocating your object and passing the string around containing its address. That being said, here's your problem:
&intruct, the address of intruct, is an rvalue -- you can't write to it. Your current code is essentially doing the following:
{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor> intruct;
vector<intructor>* intructPtr = &intruct;
ss << address;
ss >> intructPtr; // intruct has not been changed
return intruct;
}
Since your function is returning a vector (and not a reference or pointer to a vector), it seems that you want to create a copy of the vector being pointed to. In that case, you'll want to split it into two steps:
{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor>* intructPtr;
ss << address;
ss >> intructPtr; // intructPtr now points to the resource from VectorCreator
return *intructPtr; // returns a copy of the resource from VectorCreator
}
If you don't want to make a copy, then your function should return a reference vector<intructor>& or pointer vector<intructor>* -- though everything that you're doing is pretty dangerous and could easily end up referencing or pointing to an invalid location, segfaulting your program.
If you can't make VectorCreator return a smart pointer or the vector itself, be very careful that the vector doesn't get deleted or grow (potentially causing reallocation) before you've made a copy.
This all seems a little unorthodox tbh. It can work but only if you are sure the original vector will remain valid throughout the procedure. The address inside the string only points to the original vector after all.
struct intructor {
std::string name;
std::string dept;
int id;
};
std::string vec_to_address(std::vector<intructor> const& v)
{
std::ostringstream oss;
oss << &v;
return oss.str();
}
std::vector<intructor>* address_to_vec_ptr(std::string const& s)
{
void* vp;
std::istringstream(s) >> vp;
return reinterpret_cast<std::vector<intructor>*>(vp);
}
int main()
{
std::vector<intructor> v;
v.push_back({"Name A", "Dept A", 1});
v.push_back({"Name B", "Dept B", 2});
v.push_back({"Name C", "Dept C", 3});
auto address = vec_to_address(v);
auto pointer = address_to_vec_ptr(address);
for(auto const& i: *pointer)
std::cout << i.name << '\n';
// if you want a copy of the original vector you can do that
// like this:
auto copy_of_original = *pointer;
}
Output:
Name A
Name B
Name C
Try something like this instead:
std::vector<intructor> getIntructorVector(std::string filePath)
{
std::string address = VectorCreator(filePath);
std::istringstream iss(address);
void *intruct;
ss >> intruct;
return *static_cast<std::vector<intructor>*>(intruct);
}
Assuming:
you are NOT passing the std::string across process boundaries. A memory address owed by one process is NOT valid in another process.
the original std::vector is still alive in memory when getIntructorVector() is called, otherwise you will have a dangling pointer so dereferencing it will be undefined behavior.
If either of these assumptions is NOT true, then what you are attempting to do CANNOT be done this way. You will have to serialize the entire vector data to a string, and then deserialize the string to a new vector, for example:
std::ostream& quoted(std::ostream &out, const std::string &s)
{
out << '"';
for(size_t x = 0; x < s.size(); ++x)
{
char c = s[x];
if ((c == '"') || (c == '\\'))
out << '\\';
out << c;
}
out << '"';
return out;
}
...
size_t size = intruct.size();
std::ostringstream oss;
oss << size;
for(size_t x = 0; x < size; ++x)
{
intructor &i = intruct[x];
out << ' '; quoted(out, i.name);
out << ' '; quoted(out, i.dept);
out << ' ' << i.id;
}
return oss.str();
std::istream& unquoted(std::istream &in, std::string &s)
{
if (in >> std::ws)
{
if (in.peek() == '"')
{
in.ignore();
s.clear();
char c;
while (in.get(c))
{
if (c == '\\')
{
if (!in.get(c))
break;
}
else if (c == '"')
break;
s += c;
}
}
else
in >> s;
}
return in;
}
vector<intructor> getIntructorVector(string filePath)
{
string data = VectorCreator(filePath);
istringstream iss(data);
string s;
size_t size = 0;
iss >> size;
vector<intructor> intruct;
intruct.reserve(size);
for(size_t x = 0; x < size; ++x)
{
intructor i;
unquoted(iss, i.name);
unquoted(iss, i.dept);
iss >> i.id;
if (!iss) break;
intruct.push_back(i);
}
return intruct;
}
Hi I'm trying to copy char * to std::string, the char * variable allocated with malloc, after the copy I want to free char * cause I'm pretty sure std::string won't free it. I want to do that without affecting the newly created std::string.
typedef struct {
std::string name;
} st;
st fst;
name = (char *) malloc(len + 1);
for (i = 0; i<len; i++)
name[i] = name_orig[offset + i]; //name_orig is const unsigned char *
name[i] = 0;
fst.name.assign(name,len);
free(name);
cout << fst.name << endl; // prints "wiped"
The malloc'd string and the copy are unnecessary. You can just do
typedef struct {
std::string name;
} st;
st fst;
fst.name.assign(reinterpret_cast<const char*>(&name_orig[offset]), len);
I am doing this
char *draw_line(int n, char ch)
{
char *line = new char[50];
for(int i = 0; i <= n; i++)
line[i] = ch;
return line;
}
and while calling the function I am writing this:
char *res_line = draw_line(50, '=');
cout<<*res_line;
but instead of getting = printed 50 times in the console window, it just show = sign one time. My main aim is to return the = or any character as many times I want and output
the same to a text file. That's it.
cout<<*res_line;
is printing one char because *res_line is char, not char*.
Write:
cout<<res_line;
But wait — that is not going to work either because res_line is NOT null-terminated.
Use std::string or std::vector<char> — avoid explicit memory allocation, use RAII idiom instead:
std::string draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
So simple!
Or if you use std::vector:
std::vector<char> draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
which is almost same.
In C++03, however, you've to write:
return std::string(n, ch); //in the first case
return std::vector<char>(n, ch); //in the second case
That is, invoke the constructor explicitly.
The valid code will look as
char* draw_line( int n, char ch )
{
char *ch2= new char[n + 1]();
std::memset( ch2, ch, n );
return ch2;
}
//...
char *ch50 = draw_line(50,'=');
cout << ch50;
//...
delete []ch50;
Take into account this statement
char *ch2= new char[n + 1]();
But it would be much better to write simply
std::cout << std::string( 50, '=' );
char* draw_line(int n, char ch)
{
char *ch2= (char *) malloc(sizeof(char)*(n+1)); // (n+1) here
for(int i=0;i<n;i++) // < instead of <=
ch2[i]=ch;
ch2[n] = 0; // terminator
return ch2;
}
char *ch50 = draw_line(50,'=');
cout<< ch50; // changed from *ch50 to ch50
ADDON: look at string-fill constructor
cout << string(50, '=');
`I am trying to write a program that reverses two strings, I though I had it done pretty well but when I run it, the program runs till line 26, then I get a segmentation fault error. The program compiles fine. I am wondering if there is a simple or obvious problem in my functions that I am not seeing, Any help would be appreciated!!
Thanks in advance
#include <iostream>
#include <string>
using namespace std;
// Reversing the characters in strings.
void reverse(string str);
void swap(char * first, char *last);
int main() {
// declarations and initialization
string str1;
string str2;
cout << "Please enter the first string of characters:\n";
cin >> str1;
cout << "Please enter the second string of characters:\n";
cin >> str2;
cout << "The strings before reversing are:" << endl;
cout << str1 << " " << str2 << endl;
// reverse str1
reverse(str1);
// reverse str2
reverse(str2);
// output
cout << "The strings after reversing: " << endl;
cout << str1 << " " << str2 << endl;
return 0;
}
void reverse(string str) {
int length = str.size();
char *first = NULL;
char *last = NULL;
first = &str[0];
last = &str[length - 1];
for (int i = 0; first < last; i++) {
swap(first, last);
first++;
last--;
}
}
void swap(char *first, char *last) {
char * temp;
*temp = *first;
*first = *last;
*last = *temp;
}
I don't know where line 26 is, but
char * temp;
*temp = ...
is not valid. temp should be pointed at a char, or (better yet) rewrite the function to where temp is a char.
Seth Carnegie observes that you'll have to pass the strings by reference if you want to modify the originals.
void reverse(string& str) { //pass by reference, so origional is modified
In your swap function, you are assigning a value to *temp when temp is not pointing to anything (it's uninitialized). Thus, your segmentation fault.
You want this:
void swap(char* first, char* last)
{
char temp = *first;
*first = *last;
*last = temp;
}
The other answers are valid in regards to the segfault cause.
I just think you may be interested in knowing that you can reverse a string easily using std::string's reverse_iterator:
std::string reverse(std::string str) {
std::string out;
for (std::string::reverse_iterator it = str.rbegin(); it != str.rend(); it++) {
out += *it;
}
return out;
}
So, calling:
reverse("foo");
...will return oof.
You're passing the strings by value, which means only a local copy of the string will be reversed in the reverse function. You should pass them by reference.
Also, don't alter the string's memory directly. Use operator[] like this:
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
So all together:
void reverse(string& str); // prototype
....
void reverse(string& str) { // note the & which is pass by reference
int length = str.size();
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
}
And as stated by Mooing Duck, the place you're probably crashing from is dereferencing a pointer which has a garbage value here:
char * temp;
*temp = ...
You're trying to assign some random memory a value, which is probably segfaulting you.
Again, others have pointed out the what the problem is and would like to show you this:
void reverse(std::string & str) {
for (int i = 0, last = str.size() - 1, lim = str.size() / 2 ; i < lim;) {
std::swap(str[i++], str[last--]);
}
}
I have not tested it thoroughly though.