I wrote some code in order to turn a string (read in with getline()) into an array of c_strings. The problem I'm having is that the items I'm reading is not being stored in the array properly. I originally parsed the input based on the number of spaces in between them, and then going on from there, but that also got me the same problem. So I changed my parsing into what's below me, and I'm getting the same exact problem, suggesting to me that my parsing works, but somewhere in the process of reading what's parsed into the char* array, something is going wrong.
My code:
int i = 0;
unsigned inputSize = input.size();
unsigned int prev = 0; //prev as in previous space position
while((prev = input.find(' ', prev)) < inputSize) {
++i; ++prev;
}
char* charArray[i + 2];
memset(charArray, '\0', i + 2);
stringstream ss(input);
string buffer;
for(int a = 0; ss >> buffer; ++a) {
charArray[a] = const_cast<char*>(buffer.c_str());
}
What I'm doing is that I'm counting the number of spaces of my input, and making a char* array of that number + 2 (+2 because I need to end it with NULL). After that, I parse my input and read it into the array. I am using ss >> buffer as my termination clause because I will not end up allocating memory outside the allocated memory for charArray. buffer.c_str gets me a const char*, so I const_cast it in order for me to store it into the (non-const) array of char*. I use memset to set all elements to NULL because I know it'll be written over, except the last element, which I want to remain NULL.
Test:
Input: Why hello world
Output: Junk
What's going wrong inside my program?
The pointer returned by buffer.c_str() is valid only as long as the string stored in buffer is not modified. If you need to modify buffer, you have to copy its contents beforehand, if you need the old content later on.
See Right way to split an std::string into a vector [duplicate].
Live Example
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
std::string input = "Why hello world";
std::stringstream ss(input);
std::vector<std::string> vstrings(std::istream_iterator<std::string>(ss),
std::istream_iterator<std::string>{}); // C++11 brace syntax
char** charArray = new char*[vstrings.size()];
for (unsigned int i = 0; i < vstrings.size(); i++)
charArray[i] = (char*)vstrings[i].c_str();
for (unsigned int i = 0; i < vstrings.size(); i++)
std::cout << charArray[i] << "\n";
delete[] charArray;
}
Related
char* name[4];
int j=0;
while(cin.getline(name[j],80))//input given:you(ent)me(ent)he(ent)she
cout<<name[j++];
this code is reading only one string upto one newline.should'nt it read all 4 strings and print them ?and is this a good way to input string using getline?
Problem: You are not allocating the memory properly. You are declaring an array of pointers not an array of c style strings.
Possible Solutions: You need to read about pointers and memory allocation first. You can either allocate memory first to each of the four pointers that you declared name[0], name[1], name[2], and name[3] using the following code:
char* name[4];
for (int i = 0; i < 4; i++)
{
name[i] = new char[80];
}
OR you can use a 2D array for which the code is posted below:
char name[4][80];
int j=0;
while(j<4 && cin.getline(name[j],80))
{
cout<<name[j++];
}
I made a bit of correction. And it works on my computer.
char* name[4];
for (int i = 0; i < 4; i++)
name[i] = new char[80];
int j = 0;
while (j < 4)
{
cin.getline(name[j], 80); //input given:you(ent)me(ent)he(ent)she
cout << name[j++] << endl;
}
You need to read some more about pointers, arrays and memory management in C++ i guess. You try to operate on C array of strings, but you didn't initialize it properly. You need to allocate memory before you use such pointers. Currently your program results in UB so you are actually really lucky that it did anything same at all.
Another issue is that, when you reach the end of your input, when j=4, you will still attempt to perform cin(getline(name[j], 80) but you are passing the name[4] as a parameter, which may be a cause of another UB, even if you allocate the memory correctly beforehand.
Other then that you are writing in C++, so use C++ string and vector instead of C arrays.
This is easily done with strings and std::getline:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<string> names;
string name;
while(getline(cin, name)){
names.push_back(name);
cout<<name<<endl;
}
return 0;
}
I'm writing a program to execute Unix commands with any amount of arguments. I have no problem receiving input and making tokens as I use regular strings. However, execvp will only accept an array of pointers and I'm not sure how to go about converting the array of strings to this. Here's what I have:
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
int main()
{
while (true)
{
int argc = 0;
std::istringstream iss;
std::string command;
std::cout << "$> ";
getline(std::cin, command);
iss.str(command);
for (unsigned i = 0; i <= command.length(); i++)
{
if (command[i] == ' ' || command[i] == '\0')
{
argc++;
}
}
std::string arr[argc+1];
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
}
if (arr[0].compare("quit"))
{
break;
}
else
{
char*argv[argc+1];
for (int i = 0; i < argc; i++)
{
argv[i] = arr[i].c_str(); //This line is wrong
}
argv[argc] = NULL;
execvp(argv[0], argv);
}
}
return 0;
}
I've tried various methods and can't figure out how to convert a string to a char array in the proper manner. Methods like strcpy won't work because the length of each argument will vary. Any help would be greatly appreciated.
You have very small mistakes.
Replace:
argv[i] = arr[i].c_str(); with argv[i] = const_cast<char*>(arr[i].c_str());
if(arr[0].compare("quit")) with if(!arr[0].compare("quit"))
And you are good to go, and this would work in any compiler.
Run here
But I have some advice to make it using fork so it won't run only one command at a time.
Example here
Your problem is that your array is holding char*, while std::string::c_str() returns const char*. It can't be stored in your array, because it would lose const-ness.
If you're using a C++11 compliant compiler, you can use &arr[i][0] to obtain a non-const pointer to the internal string buffer.
If you aren't using a C++11 compliant compiler, the internal buffer may not be null-terminated, so your only option is to use new or malloc to allocate correctly sized buffers, then strcpy the strings into them.
char* buffer = new char[arr[i].length() + 1];
strcpy(buffer, arr[i].c_str());
argv[i] = buffer;
You can ensure null terminator at the end of each string in the array this way:
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
arr[i].push_back('\0');
}
Then you can simply capture pointer to the first character of each string. Clean and safe, without any const_cast:
for (int i = 0; i < argc; i++)
{
argv[i] = &arr[i][0];
}
so I'm working on a project that I have to read contents from a file and then analyze them. But I'm having a problem with getting the string out of a pointer that contains the address to what I need.
string lePapel(vector<char> vec){
string *str, s;
int i, j = 0;
vector<char> aux;
aux.resize(6);
for (i = 57; i <= 62; i++){
aux[j] = vec[i];
j++;
}
str = new string[aux.size()];
for (i = 0; i < 6; i++){ str[i] = aux[i]; }
return s;
}
So, the file contains in the array positions from 57 to 62 the word: ABCB4, but when returning the string s my output is A only as expected because of the pointer.
The thing is that I have been trying to find a solution and storing the whole content from vec[57] to vec[64] into the string s and returning it, and the closest that I got to returning anything plausible was using a pointer.
So, now to my question, how can I iterate the *str pointer and copy the whole content to s and return it?
Thanks in advance
I'd suggest you to not use pointers on string in your case. The following code is probably what you want :
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string lePapel(vector<char> vec){
int j = 0;
vector<char> aux;
aux.resize(6);
for (int i = 57; i <= 62; i++){
aux[j] = vec[j];
j++;
}
string str;
str.reserve(6);
for (int i = 0; i < 6; i++){ str.push_back(aux[i]); }
return str;
}
int main() {
char x[5] = {'A', 'B', 'C', 'B', '4'};
vector<char> vec(x, x + 5);
string s = lePapel(vec);
cout << s;
return 0;
}
Tested here : Tested code
About reserving space to your vector : c++ vector::reserve
Same for strings : reserve for strings
The dynamic array of string objects and the whole aux vector seem completely needless here (unless there's some other purpose for them in your code). Additionally, str is currently causing a memory leak because you never delete it when you're finished.
A much simpler approach is just to append the characters one-at-a-time to the s string object (assuming it's a std::string):
string lePapel(vector<char> vec) {
string s;
for (int i = 57; i <= 62; i++) {
s += vec[i];
}
return s;
}
There are various ways to make the code even shorter (and more efficient) than that though, if you really want to.
EDIT: If you still need/want to iterate your dynamic array and concatenate the contents into s, here's how you could do it:
for (i = 0; i < 6; i++) s += str[i];
delete [] str; //<-- very important!
Short answer, you don't want a string * you want a char *. What you created is a string array. String objects contain a pointer to the char * data you are trying to capture. Also, the sizeof(std::string) (8 bytes in size) is a lot bigger than sizeof(char) (1 byte in size) the second character you store is 8 bytes away from the first character instead of being adjacent.
There are a lot of other C++ style and safety concerns, but I'll stick with the question. ;)
I declared a char * array char *excluded_string[50] = { 0 };
Later each element of excluded_string array gets one word. Now I want to convert it into string so that I can have all words seperated by space.
std::string ss(excluded_string); gives error:
`server.cpp:171:32: error: no matching function for call to ‘std::basic_string::basic_string(char* [50])’ and large tricky explaination!
I declared char * array char *excluded_string[50] = { 0 };
Later each element of ex_str array gets one word. Now I want to convert it into string so that I can have all words seperated by space.
To convert it into a single string:
char *excluded_string[50] = { 0 };
// excluded_string filled in the meantime
std::ostringstream buffer; // add #include <sstream> at the top of
// the file for this
for(int i = 0; i < 50; ++i)
buffer << excluded_string[i] << " ";
std::string result = buffer.str();
Edit: A few notes:
if possible, do not concatenate strings directly: that will create and destroy a lot of objects and perform lots of unnecessary allocations.
if your code has stringent efficiency requirements, consider allocating/reserving the result beforehand to ensure a single allocation instead of repeated allocations.
if you concatenate strings, consider using operator += instead of + and =.
Edit 2: (answering comments)
What if + and = instead of +=?
Here's the resolution of the two alternatives for concatenating strings (s += s1 + s2 vs s += s1; s += s2):
Using = and +:
code:
std::string ss;
for (int i=0; i<50; i++)
ss += std::string(excluded_string[i]) + " ";
Equivalent code (in terms of objects constructed and allocations):
std::string ss;
for (int i=0; i<50; i++)
{
// ss += std::string(excluded_string[i]) + " ";
std::string temp1(excluded_string[i]); // "std::string(excluded_string[i])"
std::string temp2 = temp1 + " "; // call std::string operator+(std::string, char*)
ss += temp2; // call std::string::operator +=(std::string)
}
temp1 is created once per iteration;
temp2 is created for the concatenation operator
the second temporary is appended to ss.
Both temporaries create a copy of the data (allocate buffer, copy data, deallocate buffer).
Using += twice:
code:
std::string ss;
for (int i=0; i<50; i++)
{
ss += excluded_string[i]; // call std::string::operator +=(char*)
ss += " "; // same as above
}
std::string::operator += is called twice; It allocates space (if necessary), copies current contents of the string to newly allocated space, then copies new data at the end of the allocated buffer.
single pre-allocated space:
allocating/reserving the result beforehand to ensure a single allocation
std::size_t total_length = 0;
for(int i = 0; i < 50; ++i)
total_length += std::strlen(excluded_strings[i]); // assumes argument is not null
std::string ss;
ss.reserve(total_length + 51); // reserve space for the strings and spaces between
for (int i=0; i<50; i++)
{
ss += excluded_string[i]; // calls std::string::operator +=
ss += " "; // same as above
}
In this case, operator+= doesn't allocate space internally, just at the beginning (a single operation). This is still a bit slow, because you iterate over the strings twice (0->49) and over each string twice (once to compute length, once to copy it to ss).
If your excluded_string were a std::vector instead, it would be more efficient because computing the strings lengths would not iterate each string, just the vector).
Possible solution
Since you took care to initialize your array of pointers to c_str to 0, we can use that knowledge to only add actually allocated words :
Also, you need to first build a std::string based on the original c_str before you can use the concatenation operator+.
std::string stringResult;
for (int i=0; i!=50; ++i)
if(excluded_string[i])
{
stringResult.append(std::string(excluded_string[i]) + " ");
}
Details about the original error
The type of your excluded_string object is a static array of 50 pointers to char. All pointers to char being initialized to 0 by your code.
A pointer to char can be referred as a C string, or more concisely c_str.
C++ STL gives you the std::string class, for which several constructors are defined. One of them taking a c_str (i.e. a pointer to char) to initialize the string (pedantically, converting it to a pointer to const char, which is an implicit conversion in this expression).
This constructor is the one we use in the solution when we write:
std::string(excluded_string[i])
But as you can see, there is no constructor taking an array of c_str, which is exactly what you compiler error's tells you.
EDIT : Wording, thanks to Lightness Races in Orbit comment. (cast meaning in fact explicit conversion).
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <sstream>
#include <iterator>
using namespace std;
int main()
{
char *arr[10] = {0};
for(int i = 0; i < 10; i++)
arr[i] = "wang";
ostringstream str;
copy(arr, arr+10, ostream_iterator<string>(str, " "));
cout<<str.str()<<endl;
}
Try a loop:
std::string ss;
for (int i=0; i < 50; i++)
ss += std::string(excluded_string[i]) + " ";
You're code in the best situation will put first string in ss.
I'm a beginner and i need to ask a question..
I wrote this small code that accepts a string from the user and prints it..very simple.
#include <iostream>
using namespace std;
int main()
{
int i;
char *p = new char[1];
for(i = 0 ; *(p+i) ; i++)
*(p+i) = getchar();
*(p+i) = 0;
for(i = 0 ; *(p+i) ; i++)
putchar(*(p+i));
return 0;
}
when i enter any string..like "stack overflow" for example..it will print "sta" and drop the rest of the string. I know it's an easy one to solve but since I've just started i can't understand what's wrong here . Thanks in advance .
There are several problems with this code. First, you have a buffer overflow, because char *p = new char[1] allocates only one character for storage. This is exceeded when i > 0. Next, your first loop will keep going until it reaches a point in unallocated memory (undefined behavior) that has a value of zero. This just happens to be after the third value in your case. You probably wanted something more like *(p+i-1) == 0 to give "the last character read meets some condition." Finally, you're allocating memory with new[] and not properly deallocating it with a matching delete[].
Consider using std::cin and std::string for much safer and correct code:
#include <iostream>
#include <string>
int main(int, char**) {
std::string s;
std::cout << "Enter a string: ";
std::cin >> s;
std::cout << s << std::endl;
}
Here is some code along your lines that seems to work. I'm sure there are better (and more C++-ish) ways to do this...
#include <iostream>
using namespace std;
#define MAXLEN 80
int main()
{
int i=0;
char c;
char *p = new char[MAXLEN + 1]; // 1 char will not be sufficient
do // Doing this with a for loop would be unreadable
{
c = getchar();
*(p+i) = c;
i++;
} while( c != '\n' && i < MAXLEN ); // Check for a newline. How do you enter the zero with a keyboard?
*(p+i) = 0; // Ensure that the last character is zero
for(i = 0 ; *(p+i) ; i++) putchar(*(p+i)); // This is OK but difficult to read
delete [] p; // Don't forget this
return 0;
}
The fact that your program does anything is just luck; what stops *(p+i) from being \0 to begin with? It's weird that you're using getchar() and putchar() in a C++ program, too. What's the story behind this program?
If you read into memory, be sure that you allocate enough. new char[1] creates an array of only one char, but you are reading more then that. A simple temporary fix would be to simply allocate more, say new char[255].
Other notes:
you never delete the memory you allocated: delete[] p;
you should check wether you read as much characters as your buffer can hold: for(..;.. && i<bufferSize;..)
the condition in the first loop always checks the next character, not what you just read
*(p+i) is equivalent to p[i], which is more readable
why read and write only one character at a time?
why not use iostreams (std::in, std::out) and std::string as you are using C++?
you only allocate space for one character but you try to put many chars in it.
Is this homework? if so please tag it as such. Are you allowed to use STL?
If so then use std::vector instead on new char[1];
EDIT:to do it without any fiddly bits or STL
const int MAX = 100;
char *p=new char[MAX];
for(i = 0 ; *(p+i) && i < MAX ; i++)
*(p+i) = getchar();
probably some out by ones - left as exercise