C++: initialize char array with a string? - c++

Let's say I have a string called garbage.
Whatever's in garbage, I want to make a char array out of it. Each element would be one char of the string.
So, code would be similar to:
const int arrSize = sizeof(garbage); //garbage is a string
char arr[arrSize] = {garbage};
But, this will give an error "cannot convert string to char in initialization".
What is the correct way to do this? I just want to feed the darn thing a string and make an array out of it.

C++ std::string maintains an internal char array. You can access it with the c_str() member function.
#include <string>
std::string myStr = "Strings! Strings everywhere!";
const char* myCharArr = myStr.c_str();
Keep in mind that you cannot modify the internal array. If you want to do so, make a copy of the array and modify the copy.

I think what you're after is a lot simpler:
char arr[] = "some interesting data (garbage)";

You could just use garbage.data(), which is already a pointer to the first element of an array of chars containing your string data.

Or here is a heavy way to do so.
#include <string>
std::string temp = "something";
char* myChar = new char(temp.length());
for(int i = 0; i < temp.length(); ++i){
a[i] = temp[i];
}

Related

Reading string user input into an array of any size

so I'm currently trying to read user input into a char array, but every single example I've looked at defines the size of the array upon its initialization. What I'm looking for, essentially, is a way to read user input (perhaps with getline, as I would want to read user input as a string) and store it in an array.
Let's say a user inputs this into the program:
This is a string
I would want the array size to be able to fit that string, and place the null terminator after the "g". Then, another user could put a string of any size that they so desired into the program, but I would basically want my program to always make the array size just enough to contain what was read in from input.
I haven't been able to get this working and it's been a couple of hours of browsing endless pages, so any help would be appreciated! Thanks.
As Tony Delroy said on his comment (I can't comment yet), you should be using std::string.
If you really need an char array, as parameter to a function for example, you can use the function c_str() to get the content of the std::string as a const char* array or if you need a char* array, you can copy the content of the array given by c_str() to a dynamically allocated array, using
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
As an addend, you need to include the header cstring in order to use the function strcpy and need to use delete[] cstr to delete the char* when you're not going to use it anymore
#include <iostream>
#include <cstring>
using namespace std;
// string argument as std::string
void foo(string str) {
// function body
}
// argument as const char*
void bar(const char* str) {
// function body
}
// argument as char*
void baz(char* str) {
// function body
}
int main() {
string str;
getline(cin, str);
foo(str);
bar(str.c_str());
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
baz(cstr);
delete[] cstr;
return 0;
}
you should use std::string for that.
the null terminator has no use in std::string, because you can just use:
string.size()
to get the size of the user input.
if want to traverse a string like a char array one by one it should look like something like this:
std::string input;
std::getline(std::cin, input);
for (int i = 0; i < input.size() ; i++)
{
std::cout << input[i];
}

google tests: can not create string from char array?

I run this test:
TEST_F(CHAR_TESTS, wtf){
char letter[3] = {'A','B','C'};
char types[2] = {'o','s'};
char tmp[3];
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<2;k++){
tmp[0]=letter[i];
tmp[1]=letter[j];
tmp[2]=types[k];
std::string combination(tmp);
std::cout << combination << std::endl;
}
}
}
}
For some reason, this print this:
AAo~
AAs~
ABo~
ABs~
ACo~
ACs~
BAo~
BAs~
BBo~
BBs~
BCo~
BCs~
CAo~
CAs~
CBo~
CBs~
CCo~
CCs~
I do not think it is an issue with the printing itself, as I ended up doing this after noticing some tests comparing strings generated from char arrays were not passing, and I could not figure out why. So it feels like indeed the "combination" strings do not end up having the expected content.
The same code in a "regular" executable (not a gtest) print out what is expected (the 3 chars without the weird supplementary chars).
Unfortunately std::string does not have a constructor that takes a reference to array of char. So you end up invoking the const char* constructor, and this one requires the pointer to point to the first element of a null terminated string. Your char arrays aren't null-terminated, so you end up with undefined behaviour.
You should null-terminate tmp, which you can do by declaring it with one extra character, and setting it to '\0'. You can achieve that like this
char tmp[4] = {};
The constructor in std::string combination(tmp); only works if tmp is nul terminated. Otherwise the constructor cannot find the length of the string.
However, you can help std::string by explicitly providing the size of the buffer:
std::string combination(tmp, sizeof(tmp));
This constructor is primarilly intended to construct a std::string from a part of a C-style string, but also works if given the full length.
char tmp[3]; is not null-terminated use char tmp[4] = {0};

How can I transfer string to char* (not const char*)

I wanna do something like:
string result;
char* a[100];
a[0]=result;
it seems that result.c_str() has to be const char*. Is there any way to do this?
You can take the address of the first character in the string.
a[0] = &result[0];
This is guaranteed to work in C++11. (The internal string representation must be contiguous and null-terminated like a C-style string)
In C++03 these guarantees do not exist, but all common implementations will work.
string result;
char a[100] = {0};
strncpy(a, result.c_str(), sizeof(a) - 1);
There is a member function (method) called "copy" to have this done.
but you need create the buffer first.
like this
string result;
char* a[100];
a[0] = new char[result.length() + 1];
result.copy(a[0], result.length(), 0);
a[0][result.length()] = '\0';
(references: http://www.cplusplus.com/reference/string/basic_string/copy/ )
by the way, I wonder if you means
string result;
char a[100];
You can do:
char a[100];
::strncpy(a, result.c_str(), 100);
Be careful of null termination.
The old fashioned way:
#include <string.h>
a[0] = strdup(result.c_str()); // allocates memory for a new string and copies it over
[...]
free(a[0]); // don't forget this or you leak memory!
If you really, truly can't avoid doing this, you shouldn't throw away all that C++ offers, and descend to using raw arrays and horrible functions like strncpy.
One reasonable possibility would be to copy the data from the string to a vector:
char const *temp = result.c_str();
std::vector<char> a(temp, temp+result.size()+1);
You can usually leave the data in the string though -- if you need a non-const pointer to the string's data, you can use &result[0].

C++ const char* To const char* const

I am currently writing an assignment for my class that is supposed to act as a very basic shell. I am nearly finished, but I am running into an issue with execvp and my character array of parameters. Here is a light snippet of my code.
//Split the left content args
istringstream iss(left);
while(getline(iss, s, ' ')){
v.push_back(s);
}
//Get the split string and put it into array
const char* cmd_left[v.size()+1];
for(unsigned int i = 0; i < v.size(); i++){
cmd_left[i] = v.at(i).c_str();
}
cmd_left[v.size()] = 0;
v.clear();
And this is utilized by...
execvp(cmd_left[0], cmd_left);
My error is
assign3.cxx:96:34: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
I understand that the problem is that my character array isn't full of constant data, so I need to essentially go from const char* to const char* const. I read something about const_cast, but I wasn't sure if that is what I need to be doing.
If you would be so kind, could you help me get my array of character arrays to be properly accepted by that function? If you need me to post more of my code, let me know.
Thanks
The problem is you cannot pass const variable to function expecting non-const argument.
other word, const char * is a subset of char *.
remove the const
/*const*/ char* cmd_left[v.size()+1];
add const_cast here
cmd_left[i] = const_cast<char *>( v.at(i).c_str() );
other parts of your code look suspicious, but this will make it compile
Without any const_cast:
istringstream iss(left);
while(getline(iss, s, ' ')){
v.push_back(s);
}
//assuming v is not empty! which you were already
string command = v[0]; //store the command in a separate variable (this makes a copy of the string)
char* cmd_left[v.size()+1]; //not a (const char)*
for(unsigned int i = 0; i < v.size(); i++){
cmd_left[i] = new char[v[i].size()+1];
strcpy(cmd_left[i], v[i].c_str()); //copy contents of each string onto a new buffer
}
cmd_left[v.size()] = NULL;
v.clear(); //if you really want to; not necessary from the code you posted
//...
execvp(command.c_str(), cmd_left);
It is not easy, sometimes not possible to create a const dynamic array of elements because all the elements have to declared within the initializer {}.
But luckily you could tell the compiler that the array you are passing is going to be const at least for the certain duration. You could do the following this would yield
&((char* const) (const_cast<char*>(cmd_left[0]) ))
The const_cast inside would remove the const-ness of the array of characters std::string is owning. So, it is quite possible that function might change the contents of array of characters behind the back of std::string. When behaviour of functions taking such argument is known then this might be ok.
If you want to create a const array of char* without resorting to const_cast or managing memory using new/delete, you could use std::vector > instead of vector of strings.
istringstream iss(left);
while(getline(iss, s, ' ')){
v.push_back(std::vector<char>(s.length()+1));
strcpy(&v.back().front(),s.c_str());
}
//Get the split string and put it into array
char* cmd_left[v.size()+1];
for(unsigned int i = 0; i < v.size(); i++){
cmd_left[i] = &v.at(i).front();
}
cmd_left[v.size()] = 0;
v.clear();
execvp(cmd_left[0], &((char* const)cmd_left[0]));
Hope this helps.

C++ error - returning a char array

Consider the following code:
char CeaserCrypt(char str[256],int key)
{
char encrypted[256],encryptedChar;
int currentAsci;
encrypted[0] = '\0';
for(int i = 0; i < strlen(str); i++)
{
currentAsci = (int)str[i];
encryptedChar = (char)(currentAsci+key);
encrypted[i] = encryptedChar;
}
return encrypted;
}
Visual Studio 2010 gives an error because the function returns an array. What should I do?
My friend told me to change the signature to void CeaserCrypt(char str[256], char encrypted[256], int key). But I don't think that is correct. How can I get rid of the compile error?
The return type should be char * but this'll only add another problem.
encrypted is "allocated" on the stack of CeaserCrypt and might not be valid when the function returns. Since encrypted would have the same length as the input, do:
int len = strlen(str);
char *encrypted = (char *) malloc(len+1);
encrypted[len] = '\0';
for (int i = 0; i < len; i++) {
// ...
}
Don't forget to deallocate the buffer later, though (with free()).
EDIT: #Yosy: don't feel obliged to just copy/paste. Use this as a pointer to improve your coding practice. Also, to satisfy criticizers: pass an already allocated pointer to your encryption routine using the above example.
It wants you to return a char* rather than a char. Regardless, you shouldn't be returning a reference or a pointer to something you've created on the stack. Things allocated on the stack have a lifetime that corresponds with their scope. After the scope ends, those stack variables are allowed to go away.
Return a std::vector instead of an array.
std::vector<char> CeaserCrypt(char str[256],int key)
{
std::vector<char> encrypted(256);
char encryptedChar;
int currentAsci;
encrypted[0] = '\0';
for(int i = 0; i < strlen(str); ++i)
{
currentAsci = (int)str[i];
encryptedChar = (char)(currentAsci+key);
encrypted[i] = encryptedChar;
}
return encrypted;
}
There's another subtle problem there though: you're casting an integer to a character value. The max size of an int is much larger than a char, so your cast may truncate the value.
Since you're using C++ you could just use an std::string instead. But otherwise, what your friend suggested is probably best.
There are a few problems here. First up:
char CeaserCrypt(char str[256],int key)
As others have pointed out, your return type is incorrect. You cannot return in a single character an entire array. You could return char* but this returns a pointer to an array which will be allocated locally on the stack, and so be invalid once the stack frame is removed (after the function, basically). In English, you'll be accessing that memory address but who knows what's going to be there...
As your friend suggested, a better signature would be:
void CeaserCrypt(char* encrypted, const char str*, const size_t length ,int key)
I've added a few things - a size_t length so you can process any length string. This way, the size of str can be defined as needed. Just make sure char* encrypted is of the same size.
Then you can do:
for(int i = 0; i < length; i++)
{
// ...
For this to work your caller is going to need to have allocated appropriately-sized buffers of the same length, whose length you must pass in in the length parameter. Look up malloc for C. If C++, use a std::string.
If you need C compatibility make encrypted string function argument.
If not, than use C++ std::string instead C style string.
And also In your code encrypted string isn't ending with '\0'
The problem with the original code is that you are trying to return a char* pointer (to which your local array decayed) from a function that is prototyped as one returning a char. A function cannot return arrays in C, nor in C++.
Your friend probably suggested that you change the function in such a way, that the caller is responsible for allocation the required buffer.
Do note, that the following prototypes are completely equal. You can't pass an array as a parameter to normal function.
int func(char array[256]);
int func(char* array);
OTOH, you should (if you can!) decide the language which you use. Better version of the original (in C++).
std::vector<unsigned char> CeaserCrypt(const std::string& str, const int key)
{
std::vector<unsigned char> encrypted(str.begin(), str.end());
for (std::vector<unsigned char>::iterator iter = vec.begin();
iter != vec.end(); ++iter) {
*iter += key;
}
return vec;
}
Do note that overflowing a signed integer causes undefined behavior.
VS2010 is "yelling" at you because you are trying to return a value that is allocated on the stack, and is no longer valid once your function call returns.
You have two choices: 1) Allocate memory on the heap inside your function, or 2) use memory provided to you by the caller. Number 2 is what your friend in suggesting and is a very good way to do things.
For 1, you need to call malloc() or new depending on whether you are working in C or C++. In C, I'd have the following:
char* encrypted = malloc(256 * sizeof(char));
For C++, if you don't want to use a string, try
char* encrypted = new char[256];
Edit: facepalm Sorry about the C noise, I should have looked at the question more closely and realized you are working in C++.
You can just do your Ceaser cipher in place, no need to pass arrays in and out.
char * CeaserCrypt(char str[256], int key)
{
for(unsigned i = 0; i < strlen(str); i++)
{
str[i] += key;
}
return str;
}
As a further simplification, skip the return value.
void CeaserCrypt(char str[256], int key)
{
for(unsigned i = 0; i < strlen(str); i++)
{
str[i] += key;
}
}
well what you're returning isn't a char, but a char array. Try changing the return type to char*(char* and a char array are ostensibly the same thing for the compiler)
char* CeaserCrypt(char str[256],int key)
EDIT: as said in other posts, the encrypted array will probably not be valid after the function call. you could always do a new[] declaration for encrypted, remembering to delete[] it later on.