Ok so here are the parts of my code that I'm having trouble with:
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(historyArray[i], historyArray[i-1]); //ERROR HERE//
}
strcpy(historyArray[0], readBuffer); //and here but it's the same error//
The error that i'm receiving is:
"invalid conversion from 'char' to 'char*'
initializing argument 1 of 'char* strcpy(char*, const char*)'
The project is to create a psudo OS Shell that will catch and handle interrupts as well as run basic unix commands. The issue that I'm having is that I must store the past 20 commands into a character array that is dynamically allocated on the stack. (And also de-allocated)
When I just use a 2d character array the above code works fine:
char historyArray[20][];
but the problem is that it's not dynamic...
And yes I do know that strcpy is supposed to be used to copy strings.
Any help would be greatly appreciated!
historyArray points to (the first element of) an array of 20 chars. You can only store one string in that array.
In C, you could create a char** object and have it point to the first element of an array of char* objects, where each element points to a string. This is what the argv argument to main() does.
But since you're using C++, it makes a lot more sense to use a vector of strings and let the library do the memory management for you.
Stop using C idioms in a C++ program:
std::deque<std::string> historyArray;
//get input
std::string readBuffer;
std::getline(std::cin, readBuffer);
std::cout << readBuffer << std::endl;
//save to history
historyArray.push_front(readBuffer);
if(historyArray.size() > 20)
historyArray.pop_back();
As a result, we have:
No buffer-overflow threat in readBuffer / getline()
No pointers, anywhere, to confuse us.
No arrays to overstep the ends of
Arbitrarily long input strings
Trivially-proven memory allocation semantics
Two solutions. The first is if you for some reason really want arrays, the other is more recommended and more "C++"ish using std::strings.
char * historyArray[20]; // Create an array of char pointers
// ...
historyArray[i] = new char[SIZE]; // Do this for each element in historyArray
Then you can use strcpy on the elements in historyArray.
Second solution which I repeat is recommended (I've fixed a few other things):
string historyArray[20];
getline(cin, readBuffer); // Make readbuffer an std::string as well
cout << readBuffer << endl;
for(int i = 19; i > 0; i--){ // I think you meant 19 instead of 20
historyArray[i] = historyArray[i-1];
}
historyArray[0] = readBuffer;
historyArray[i] is a char. It is a single character. You want to use a sting. Your fundemental problem is that historyArray is a char* which means that it points to a memory range containing characters. You want it to be a char** which is a pointer to a pointer to a string. Your initialization code would be
char** historyArray;
historyArray = new char* [20];
for (int i = 0; i < 20; i++)
{
historyArray[i] = new char [512]; //Big enough to have a 512 char buffer copied in
}
Error 1: You're indexing past your array bounds with i being set to 20.
Error 2: historyArray[i] is a char, not a char *. You need &historyArray[i].
strcpy(&historyArray[i], &historyArray[i-1]);
Array notation gives references while strcopy wants pointers. Convert references to pointers with address-of (&) operator.
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(&(historyArray[i]), &(historyArray[i-1])); //ERROR HERE//
}
strcpy(historyArray, readBuffer); //and here but it's the same error//
But that will only fix the compiler errors, not the logical errors in the code. Your using C++ so the string solution:
vector<string> history;
cin.getline(readBuffer,512);
history.push_back(readBuffer);
Alternatively if you want one long string containing everything from readBuffer:
string history;
cin.getline(readBuffer,512);
history = history += string(readBuffer);
For example...
Related
I have an Arduino that controls timers. The settings for timers are stored in byte arrays. I need to convert the arrays to strings to SET a string on an external Redis server.
So, I have many arrays of bytes of different lengths that I need to convert to strings to pass as arguments to a function expecting char[]. I need the values to be separated by commas and terminated with '\0'.
byte timer[4] {1,5,23,120};
byte timer2[6] {0,0,0,0,0,0}
I have succeeded to do it manually for each array using sprintf() like this
char buf[30];
for (int i=0;i<5;i++){ buf[i] = (int) timer[i]; }
sprintf(buf, "%d,%d,%d,%d,%d",timer[0],timer[1],timer[2],timer[3],timer[4]);
That gives me an output string buf: 1,5,23,120
But I have to use a fixed number of 'placeholders' in sprintf().
I would like to come up with a function to which I could pass the name of the array (e.g. timer[]) and that would build a string, probably using a for loop of 'variable lengths' (depending of the particular array to to 'process') and many strcat() functions. I have tried a few ways to do this, none of them making sense to the compiler, nor to me!
Which way should I go looking?
Here is the low tech way you could do it in normal C.
char* toString(byte* bytes, int nbytes)
{
// Has to be static so it doesn't go out of scope at the end of the call.
// You could dynamically allocate memory based on nbytes.
// Size of 128 is arbitrary - pick something you know is big enough.
static char buffer[128];
char* bp = buffer;
*bp = 0; // means return will be valid even if nbytes is 0.
for(int i = 0; i < nbytes; i++)
{
if (i > 0) {
*bp = ','; bp++;
}
// sprintf can have errors, so probably want to check for a +ve
// result.
bp += sprintf(bp, "%d", bytes[i])
}
return buffer;
}
an implementation, assuming that timer is an array (else, size would have to be passed as a parameter) with the special handling of the comma.
Basically, print the integer in a temp buffer, then concatenate to the final buffer. Pepper with commas where needed.
The size of the output buffer isn't tested, mind.
#include <stdio.h>
#include <strings.h>
typedef unsigned char byte;
int main()
{
byte timer[4] = {1,5,23,120};
int i;
char buf[30] = "";
int first_item = 1;
for (i=0;i<sizeof(timer)/sizeof(timer[0]);i++)
{
char t[10];
if (!first_item)
{
strcat(buf,",");
}
first_item = 0;
sprintf(t,"%d",timer[i]);
strcat(buf,t);
}
printf(buf);
}
Everywhere I've looked for answers to this question, I see people making one small char * array of size like two and hardcoding in paths for execv. What I need to do is to take a string of parameters with the path as the first set of characters, tokenize them, and then put them in an array of char *s that execv will accept.
here is my tokenization function
char ** stringToVectorToCharArray(string inputString)
{
stringstream ss(inputString);
cout << "\n inputString is: " << inputString <<"\n";
vector<string> tokens;
tokens.clear();
while(ss >> inputString)
{
tokens.push_back(inputString);
}
int size = tokens.size();
char **args = new char*[size + 1];
int i = 0;
for(; i < size; i++)
args[i] = const_cast<char *>(tokens.at(i).c_str());
args[i + 1] = (char *) 0;
return args;
}
And this is called from
char **args = stringToVectorToCharArray(inputString);
execv(executeChar, args);
Within the Child section of my fork() if-else statements for flow control.
I get a bad_alloc error, but I'm not sure which of my allocation statements are right, if any are for that matter. I know the return has to be in the form
char *const argv[]
But I'm not sure how to set that up.
You are returning memory from a local variable (tokens) from your function.
for(; i < size; i++) {
// stores pointer to local memory: args[i] = const_cast<char *>(tokens.at(i).c_str());
args[i] = new char[tokens.at(i).size()+1]; // Create dynamically allocated copy
strcpy(args[i], tokens.at(i).c_str());
}
The above should fix the problem. Technically, this would create a memory leak, since the memory is never deallocated, but your call to execv will replace your executable and effectively deallocate the memory.
I my trying to copy a value into a char.
my char array is
char sms_phone_number[15];
By the way, could tell me if I should write (what the benefic/difference?)
char * sms_phone_number[15]
Below displays a string: "+417611142356"
splitedString[1]
And I want to give that value to sms_from_number
// strcpy(sms_from_number,splitedString[1]); // OP's statement
strcpy(sms_phone_number,splitedString[1]); // edit
I've got an error, I think because splitedString[1] is a String, isn't?
sim908_cooking:835: error: invalid conversion from 'char' to 'char*'
So how can I copy it correctely.
I also tried with sprintf without success.
many thank for your help.
Cheers
I declare spliedString like this
// SlitString
#define NBVALS 9
char *splitedString[NBVALS];
I have that function
splitString("toto,+345,titi",slitedString)
void splitString(char *ligne, char **splitedString)
{
char *p = ligne;
int i = 0;
splitedString[i++] = p;
while (*p) {
if (*p==',') {
*p++ = '\0';
if (i<NBVALS){
splitedString[i++] = p;
}
}
else
{
p++;
}
}
while(i<NBVALS){
splitedString[i++] = p;
}
}
If I do a for with splitedString display, it display this
for(int i=0;i<4;i++){
Serialprint(i);Serial.print(":");Serial.println(splitedString[i]);
}
//0:toto
//1:+4176112233
//2:14/09/19
I also declared and want to copy..
char sms_who[15];
char sms_phone_number[15];
char sms_data[15];
//and I want to copy
strcpy(sms_who,splitedString[0]
strcpy(sms_phone_number,splitedString[1]
strcpy(sms_date,splitedString[2]
I know, I am very confused with char and pointer * :o(
The declaration:
char * SplittedString[15];
Declares an array of pointers to characters, a.k.a. C-style strings.
Given:
const char phone1[] = "(555) 853-1212";
const char phone2[] = "(818) 161-0000";
const char phone3[] = "+01242648883";
You can assign them to your SplittedString array:
SplittedString[0] = phone1;
SplittedString[1] = phone2;
SplittedString[2] = phone3;
To help you a little more, the above assignments should be:
SplittedString[0] = &phone1[0];
SplittedString[1] = &phone2[0];
SplittedString[2] = &phone3[0];
By definition, the SplittedStrings array contains pointers to single characters, so the last set of assignments is the correct version.
If you are allowed, prefer std::string to char *, and std::vector to arrays.
What you need is a vector of strings:
std::vector<std::string> SplittedStrings(15);
Edit 1:
REMINDER: Allocate space for your spliedString.
Your spliedString should either be a pre-allocated array:
char spliedString[256];
or a dynamically allocated string:
char *spliedString = new char [256];
Strings and Chars can be confusing for noobs, especially if you've used other languages that can be more flexible.
char msg[40]; // creates an array 40 long that can contains characters
msg = 'a'; // this gives an error as 'a' is not 40 characters long
(void) strcpy(msg, "a"); // but is fine : "a"
(void) strcat(msg, "b"); // and this : "ab"
(void) sprintf(msg,"%s%c",msg, 'c'); // and this : "abc"
HTH
After trying for about 1 hour, my code didn't work because of this:
void s_s(string const& s, char data[10])
{
for (int i = 0; i < 10; i++)
data[i] = s[i];
}
int main()
{
string ss = "1234567890";
char data[10];
s_s("1234567890", data);
cout << data << endl;//why junk
}
I simply don't understand why the cout displays junk after the char array. Can someone please explain why and how to solve it?
You need to null terminate your char array.
std::cout.operator<<(char*) uses \0 to know where to stop.
Your char[] decays to char* by the way.
Look here.
As already mentioned you want to NUL terminate your array, but here's something else to consider:
If s is your source string, then you want to loop to s.size(), so that you don't loop past the size of your source string.
void s_s(std::string const& s, char data[20])
{
for (unsigned int i = 0; i < s.size(); i++)
data[i] = s[i];
data[s.size()] = '\0';
}
Alternatively, you can try this:
std::copy(ss.begin(), ss.begin()+ss.size(),
data);
data[ss.size()] = '\0';
std::cout << data << std::endl;
You have ONLY allocated 10 bytes for data
The string is actually 11 bytes since there is an implied '\0' at the end
At a minimum you should increase the size of data to 11, and change your loop to copy the '\0' as well
The function std::ostream::operator<< that you are trying to use in the last line of the main will take your char array as a pointer and will print every char until the null sentinel character is found (the character is \0).
This sentinel character is generally generated for you in statements where a C-string literal is defined:
char s[] = "123";
In the above example sizeof(s) is 4 because the actual characters stored are:
'1', '2', '3', '\0'
The last character is fundamental in tasks that require to loop on every char of a const char* string, because the condition for the loop to terminate, is that the \0 must be read.
In your example the "junk" that you see are the bytes following the 0 char byte in the memory (interpreted as char). This behavior is clearly undefined and can potentially lead the program to crash.
One solution is to obviously add the \0 char at the end of the char array (of course fixing the size).
The best solution, though, is to never use const char* for strings at all. You are correctly using std::string in your example, which will prevent this kind of problems and many others.
If you ever need a const char* (for C APIs for example) you can always use std::string::c_str and retrieve the C string version of the std::string.
Your example could be rewritten to:
int main(int, char*[]) {
std::string ss = "1234567890";
const char* data = ss.c_str();
std::cout << data << std::endl;
}
(in this particular instance, a version of std::ostream::operator<< that takes a std::string is already defined, so you don't even need data at all)
I need help in my following code and hope that you can help me through. All I wanted is to pass in INT type to setX() and setY(). However, there is no way for me to convert vector char* to int. Is there alternative to this?
template<class T>
vector<string> Delimiter(T inputString){
int count=0;
char str[inputString.length()];
strcpy(str,inputString.c_str());
char * pch;
vector<string> returnContainer;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str,",[]");
while (pch != NULL)
{
returnContainer.push_back(pch);
pch = strtok (NULL, " ,[]");
count++;
}
for(int i=0; i<returnContainer.size(); i++){
cout << "return:" << returnContainer[i] << endl;
}
return returnContainer;
}
//Main()
fileDataAfterFiltered = Delimiter(fileData[i]); // Delimiter (vector<string> type)
point2DObj[point2DCount].setX(fileDataAfterFiltered[1]); // error
point2DObj[point2DCount].setY(fileDataAfterFiltered[2]); // error
//Assn3.cpp:107:59: error: no matching function for call to ‘Point2D::setX(std::basic_string&)’
Delimiter() returns a vector<string> and you give one of these strings to setX() and setY(), but both expect an integer parameter. You must convert the string to int
int x = atoi(fileDataAfterFiltered[1].c_str());
point2DObj[point2DCount].setX(x);
int y = atoi(fileDataAfterFiltered[2].c_str());
point2DObj[point2DCount].setY(y);
But: in C++ array and vector elements start at 0 not 1, so you might want to replace this with fileDataAfterFiltered[0] and fileDataAfterFiltered[1] respectively.
If you are using a C++11 compiler, function std::stoi() will do the trick:
point2DObj[point2DCount].setX(std::stoi(fileDataAfterFiltered[1]));
Otherwise you can use the old atoi():
point2DObj[point2DCount].setX(atoi(fileDataAfterFiltered[1].c_str()));
Aside from this, your code has many other problems, but I hope you can fix them by yourself.
there's plenty of ways of converting string to int. boost::lexical_cast is one which will magically do the conversion you want. Otherwise you can use atoi (if you don't care about errors), or strtol (if you do).
point2DObj[point2DCount].setX(atoi(fileDataAfterFiltered[1].c_str()));
point2DObj[point2DCount].setX(boost::lexical_cast<int>(fileDataAfterFiltered[1]));