i'm doing an exercise that wants me to use c_str with a vector<char*/>
it seems these two things don't work together, c_str seems to only work with string types but the exercise wants me to use char*. here is the exercise problem:
The program in Exercise •• P7.3 is limited by the fact that it can only handle inputs of 1,000 characters or 100 lines. Remove this limitation as follows. Concatenate the input in one long string object. Use the c_str member function to obtain a char* into the string’s character buffer. Store the beginnings of the lines as a vector<char*>. (Horstmann, 2017-08-12, p. EX7-3)
i will post the P7.3 exercise at the bottom. but here's my code so far (work in progress, not the prettiest looking):
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
usingnamespace std;
int main()
{
char ch;
string buffer = "";
bool run = true;
vector<char*> lines;
while (run)
{
cin.get(ch);
if (ch == '\n')
{
ch = '\0';
}
if (ch == ';')
{
run = false;
}
else
{
buffer = buffer + ch;
}
}
int pos = 0;
cout << buffer.c_str();
buffer.c_str();
lines.push_back(&buffer);
/* for (int i = 0; i < buffer.length(); i++)
{
if (buffer.substr(i, 1) == "\n")
{
pos = i + 1;
cout << pos;
cout << buffer.c_str() + pos;
cout << endl;
}
}*/
return 0;
}
Here is Exercise •• P7.3
Write a program that reads lines of text and appends them to a char buffer[1000]. Read one character at a time by calling cin.get(ch), where ch is a variable of type char. Use input redirection (Special Topic 4.3). Stop after reading 1,000 characters. As you read in the text, replace all newline characters '\n' with '\0' terminators. Establish an array char* lines[100], so that the pointers in that array point to the beginnings of the lines in the text. Consider only 100 input lines if the input has more lines. Then display the lines in reverse order, starting with the last input line. (Horstmann, 2017-08-12, p. EX7-3)
it seems these two things don't work together, c_str seems to only work with string types but the exercise wants me to use char*. here is the exercise problem:
c_str provides a char* (I think it is const char*, but that aside).
so you can say
vector<char*> vcp(100);
vcp[0] = somestring.c_str();
and at most you may need a cast to make it happy about the const problem.
c_str() is only available for string, yes. If you need something else converted to a c-string you can use sprintf for 99% of it. I don't know what it would be, but that would do it.
--- this may test your understanding but this assignment is really pfd / messed up thing to ask someone to do.
** end of line is 2 chars on some systems, 10 and 13, on others just 1. reading one char at a time may make this weird so be warned.
you can also take a char * from a string object:
char* foo = &(stringvar[12])
but be warned: if stringvar changes, the pointers is invalidated.
you can also add 0 char to string objects to make char* into them work nicer. They do not have any 0s naturally, but you can inject them. this isnt something anyone sane would do normally, but I believe it would make your work easier for this problem.
it does still want a line by line via char*.
that is the weird part. it should have him make a vector of string.
even if its a backwards compatible thing, to get a vector of char*, if you stored them as a string to a line (vector of string), you can take c_str() (from each vector now) and populate the line pointers, that would be clean. But it appears to be (maybe its just how I am reading it) wanting him to split the line from ONE string into many via pointer offsets, which sounds like something *I* would do but not anything desirable.
For the first exercise I read it (from the book itself) that you read the lines in from a text file (indirection blah blah). (Reverse order is no sweat, not done here.)
Line count: 13
line: 1 Write a program that reads lines of text and appends them to a
line: 2 char buffer[1000].
line: 3
line: 4 Stop after reading 1,000 characters.
line: 5
line: 6 As you read in the text, replace all newline characters '\n' with '\0'
line: 7 terminators.
line: 8
line: 9 Establish an array char* lines[100], so that the pointers in that array point
line: 10 to the beginnings of the lines in the text. Consider only 100 input lines if
line: 11 the input has more lines.
line: 12
line: 13 Then display the lines in reverse order, starting with the last input line.
buffer[pos] = '0';
//...
for (int i = 0; i < positions.size(); i++)
{
buffer[positions[i]] = '\0';
}
¿what's the point of that? ¿why do you set it from '\0' to '0' and then back to '\0'?
apart from that, it's good, although you may do it without the `positions' vector
one thing to notice, if you insert more characters into `buffer' after filling the `lines' vector, then all the pointers may become invalid.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
int main()
{
// SOURCE TEXT FILE
std::ifstream infile ("p7_14.txt");
if (!infile.is_open())
{
std::cout << "Unable to open file\n";
exit(1);
}
std::string str_continuous;
std::vector<constchar*> lines;
// READ IN LINES
char ch;
while( infile >> std::noskipws >> ch )
{
if(ch == '\n')
{
ch = '\0';
}
str_continuous += ch;
}
constchar* b = str_continuous.c_str();
lines.push_back( &b[0] );
for(int i = 0; i < str_continuous.length(); i++)
{
if(b[i] == '\0')
{
lines.push_back( &b[i + 1] );
}
}
lines.pop_back(); // ADJUSTMENT
// FORWARD LIST
size_t line_count{0};
for (auto i: lines)
{
std::cout
<< "line: "
<< std::setw(2) << std::right << line_count
<< i << '\n';
line_count++;
}
return 0;
}
line: 0 P7.14
line: 1 The program in Exercise P7.13 is limited by the fact that it can only handle
line: 2 inputs of 1,000 characters or 100 lines. Remove this limitation as follows.
line: 3
line: 4 Concatenate the input in one long string object.
line: 5
line: 6 Use the c_str member function to obtain a char* into the string’s character
line: 7 buffer.
line: 8
line: 9 Store the beginnings of the lines as a vector<char*>.
Program ended with exit code: 0
It's very important to understand that a string can move it's data to a new location any time it changes. So pointers into c_str() are only valid until the string changes. Your code handles this, but I wanted to make sure you know that you're relying on that fact.
Looking at your latest code:
Line 21: why stop at a semicolon? Shouldn't you read the whole input?
Line 36: You're always searching from the beginning, so you'll always find the first null character, not the next one.
Line 37: string::npos instead of -1. Also, pos should be type size_t.
Line 43: Buffer[npos] is guaranteed to be '\0' at this point, so no need to set it.
Line 44: You're pushing the address of the null character. You want to push the address of the next character.
Lines 48-53: why not do this inside the previous loop instead. That way there's no need for the positions vector at all.
Lines 55-58: The value s are already '\0' so no need to set them again.
Line 37: string::npos instead of -1. Also, pos should be type size_t.
I have seen a fair number of online examples doing this. Its works on most compilers, but not all; I had some trouble with it and stopped doing it.