How to copy an array of characters to a string C++ - c++

I am writing a function that takes in a string through pass by reference and an array of characters and the size of the array. The string already has characters in it. I am trying to erase the characters in the string and copy the characters from the array.
I tried setting up a for loop to copy, but it doesn't work if the string is too small or too big. I can't use strcopy in this function. Need some guidance.
void functionname(string &first, char arr[], int size) {
int i;
(for i = 0; i < size; i++) {
first[i] = arr[i];
}
}

You can use std::string's default assignment operator = and simply do
first = arr;

std::string has function to do it first.assign(arr, size)

The below works as std::string overrides the assignment operator (=) for char* to allow direct assignment to the string from a character pointer.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void functionname(string &first, char arr[], int size)
{
first = arr;
}
int main()
{
std::string x = "mystring";
char buff[x.length()];
strcpy(buff, "other");
cout << x << endl;
functionname(x, buff, x.length());
cout << x << endl;
return 0;
}

string has a constructor that copies a character array and takes a count. This will work no matter what contents are inside the arr array, even embedded null characters.
void functionname(string &first, char arr[], int size) {
first = string(arr, size);
}
Again, the contents of arr are copied into the string, you don't need to keep arr around after this if you don't need it anymore.

Related

I am having trouble getting 3 strings from the user using cin.getline() and using a pointer array to store them

I am getting an exception thrown at my cin.getline. I am new to c++, I am sorry if the code is really bad.
The GetInput function should do the following:
This function accepts three lines of user-input text and stores the entered lines as three individual strings. Use a pointer array to store the strings. The function should ask the user to enter in three lines of data. The function will store the information in the pointer array. (cin.getline()). Should be allocated in inside GetInput and should be exactly the correct size for each string.
int main() {
char* str[2];
GetInput(str);
}
void GetInput(char* ptr[]) {
for (int i = 0; i < 3; i++) {
cout << "Enter a string: ";
cin.getline(ptr[i], strlen(ptr[i]), '\n');
}
}
It's unfortunate that the assignment demands pointers since this would have been easy using std::vector<std::string>. If you do need to use pointers, make use of smart pointers, like std::unique_ptr. They will delete/delete[] the raw pointer they own when they are destroyed (go out of scope) and will therefor help preventing memory leaks. So, using arrays and pointers, this is one way it could be done.
#include <iostream>
#include <array> // std::array
#include <cstring> // std::memcpy
#include <memory> // std::unique_ptr
constexpr size_t max_line_length = 256;
// convenience alias
using CStrPtr = std::unique_ptr<char[]>;
void GetInput(std::array<CStrPtr, 3>& ptrs) {
char buf[max_line_length]; // temporary buffer when reading a line
// loop through the 3 pointers in the array
for(CStrPtr& cptr : ptrs) {
std::cout << "Enter a string: ";
std::cin.getline(buf, max_line_length);
size_t len = std::strlen(buf) + 1; // +1 to make place for the string terminator, '\0'
// create a new pointer to a char[] with space for the string
// and assign it to the pointer in the array
cptr = std::make_unique<char[]>(len);
// copy the string in buf into the space the raw pointer held by cptr now points to
std::memcpy(cptr.get(), buf, len);
}
}
int main() {
std::array<CStrPtr, 3> strs;
GetInput(strs);
for(const CStrPtr& cptr : strs) {
std::cout << cptr.get() << "\n";
}
}
In case you're not allowed to use the standard smart pointers, you could create your own smart pointer or a simple string class. Here's a version of the above but with a simple string class:
#include <iostream>
#include <array> // std::array
#include <cstring> // std::strlen
#include <algorithm> // std::copy
constexpr size_t max_line_length = 256;
class cstring {
char* m_mem; // the precious pointer
public:
cstring() : // default constructor
m_mem(new char[1]) // make place for the string terminator
{
m_mem[0] = '\0'; // the string terminator
}
cstring(char const* buf) : // converting constructor
m_mem{}
{
// allocate memory
size_t len = std::strlen(buf) + 1;
m_mem = new char[len];
// and copy buf to m_mem
std::copy(buf, buf+len, m_mem);
}
cstring(const cstring& o) : // copy ctor
cstring(o.m_mem) // delegate to converting ctor
{}
cstring(cstring&& o) : // move ctor
// copy the pointer from o and set o:s pointer to nullptr
m_mem(std::exchange(o.m_mem, nullptr))
{}
cstring& operator=(const cstring& o) { // copy assignment
*this = cstring(o); // using copy ctor + move assignment
return *this;
}
cstring& operator=(cstring&& o) { // move assignment
// swap pointers: let o destroy our old pointer for us
std::swap(m_mem, o.m_mem);
return *this;
}
~cstring() { delete[] m_mem; } // destructor
// user-defined conversions
operator char const* () const { return m_mem; }
operator char* () { return m_mem; }
};
void GetInput(std::array<cstring, 3>& ptrs) {
char buf[max_line_length]; // temporary buffer when reading a line
// loop through the 3 pointers in the array
for(cstring& cptr : ptrs) {
std::cout << "Enter a string: ";
std::cin.getline(buf, max_line_length);
// create a new cstring and assign it to the cstring in the array
cptr = cstring(buf);
}
}
int main() {
std::array<cstring, 3> strs;
GetInput(strs);
for(const cstring& cptr : strs) {
// cptr will here use the user-defined conversion to "char const*"
// for which there's a standard operator<< defined
std::cout << cptr << "\n";
}
}
#include <iostream>
#include <string>
using namespace std;
void getLine(string ptr[]) {
for (int index = 0; index < 3; ++index) {
string line;
getline(cin, line);
ptr[index] = line;
}
}
int main() {
string ptr[3];
getLine(ptr);
for (int index = 0; index < 3; ++index) {
cout << ptr[index] << endl;
}
}
There were several tings wrong with your code. First, you didn't allocate enough space for your array. Your length should be the length of the array, not the index of the last element. So if it's 3 strings, it's [3].
Next, I wouldn't use char * but instead use the string class. See my code.
Third, your strlen stuff -- well, you have an array of pointers to random places in memory, or maybe an array of null pointers. Either way, it's wrong.
You COULD have done something like this:
char myStrings[3][1000];
And then in your getline, use 1000 as the maximum length (maybe 999 -- I don't use getline in the form you did). This would allocate 3 character arrays of 1000 bytes each.
But the strlen thing just flat won't work because you don't start with any strings to strlen from.

Adding spaces at the beginning of an array of chars

As in the title, I need to add user-specified number of spaces at the beginning of some word, using array of chars. I need to do it in a function which takes my array as a parameter and returns it. Here's my code:
#include <iostream>
using namespace std;
void writeDownCharArray(char t[], int sizee)
{
for (int i=0;i<sizee;i++)
{
cout<<t[i];
}
}
char * addSpaces(char t[], int ammountOfSpaces)
{
int numberOfCharacters=0;
for (int i=0; t[i]!=NULL; i++){numberOfCharacters++;} //checking the amount of characters in my array
char t2[numberOfCharacters+10];
for (int i=0; i<ammountOfSpaces; i++) {t2[i]=' ';} //adding the sapces
for (int i=ilosc;i<numberOfCharacters+ammountOfSpaces;i++) {t2[i]=t[i-ammountOfSpaces];} //filling my new array with characters from the previous one
return t2;
}
int main()
{
int numberOfSpaces;
char t[10];
cout << "Text some word: ";
cin.getline(t,10);
cout<<"How many spaces?: ";cin>>numberOfSpaces;
writeDownCharArray(addSpaces(t, numberOfSpaces), HERE);
return 0;
}
And now: How do I print it to the screen? If I say cout<<addSpaces(t, numberOfSpaces); it actually prints something strange to the screen (not numbers, just strange characters). And if I say writeDownCharArray, then what should I put in "HERE" place?
The C++ way to solve this would be to use a std::string like
std::string add_spaces(const std::string & line, std::size_t number_of_spaces)
{
std::string spaces(number_of_spaces, ' ');
return spaces + line;
}
If you cannot use std::string then you are doing to have to deal with dynamic memory allocations and change
char t2[numberOfCharacters+10];
to
char * ts = new char[numberOfCharacters + ammountOfSpaces + 1];
We have to have this as Variable length arrays are not standard and trying to return a pointer to an array declared in a function will leave you with a dangling pointer and trying to use it is undefined behavior.
Since new[] was used in the function you will need to remember to call delete[] on the pointer that is returned after you are done with it. This is another benefit of using a std::string as it takes care of itself.
As far as writeDownCharArray is concerned you do not need a size parameter as cout can handle null terminated c-strings. You can simply have
void writeDownCharArray(char t[])
{
cout<<t;
}
And then you main would look like
char * foo = addSpaces(t, numberOfSpaces);
writeDownCharArray(foo);
delete [] foo;

FIXED: Access Violation Reading Location (pointer to string array)

FIXED: http://pastebin.com/71QxqGk5
first post/question.
So this is C++ and I am trying to print an array of words.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cctype>
#include <ctime>
using namespace std;
//structs
struct Input
{
int size;
string* word;
bool is_palindrome[];
};
//prototypes
bool openInputFile(ifstream &ifs);
void File_to_Array(string* word, int &size);
void PrintArray(string* word, int size);
//main
int main()
{
Input myInput = { 0, nullptr, false };
File_to_Array(myInput.word, myInput.size);//copy arr and get size
cout << myInput.word; //this outputs 00000000
cout << *myInput.word; //this breaks and throws exception as commented below
//Exception thrown at 0x0098BB6B in Project1.exe: 0xC0000005: Access violation reading location 0x00000014.
PrintArray(myInput.word, myInput.size);//print array of strings
system("PAUSE");
return 0;
}
//functions
bool openInputFile(ifstream &ifs)
{
string filename;
cout << "Enter the input filename: " << endl;
getline(cin, filename);
ifs.open(filename.c_str());
return ifs.is_open();
}
void File_to_Array(string* word, int &size)//copies file to dyn arr and assigns size from first elem
{
ifstream myFile;
while (!openInputFile(myFile))
cout << "Could not open file" << endl;
string tempstr = "";
getline(myFile, tempstr);//first line is size of dyn arr
size = stoi(tempstr);//now we have max size of dyn arr of strings
word = new string [size];//now we have the array of strings, *word[index] = string1
int i;
for (i = 0; getline(myFile, word[i]) && i < size; ++i);//for each line
//copy line of string from file to string arr within "bool" test, second param of for loop //copying done
size = i;
myFile.close();//done with file, no need, close it
}
void PrintArray(string* word, int size)
{
//for (int i = 0; i < size; ++i)
//cout used to be here, but now its in main, for debugging
}
So I'm wondering if my problem is with passing a member of a struct, and if I should have instead passed the entire struct type "myInput" into the functions and use the -> operator to access the members of myInput.
below is an example of a text file
5
month
Runner
NEON
digit
ferret
nothing
the 5 would be the size of the dynamically allocated array, the rest are strings, as you can see there are 6 strings, so I have in the for loop a test for whether the file is still transferring strings to the array.
This part of the File_to_Array is causing the problem:
word = new string [size];
You think that you are setting the pointer of myInput object to point to the string array, but you're not. When you pass the pointer to the function here:
File_to_Array(myInput.word, myInput.size)
^^^^^^^^^^^^
you are really passing a copy of the pointer. So inside the File_to_Array, this copy is re-pointed to the newly-created string array, but the real pointer inside myInput is not changed. You should pass a reference to the pointer instead:
void File_to_Array(string*& word, int &size)
\___________/
^--reference to a pointer
I would also suggest you to use a vector[string] instead. Finally, your bool is_palindrome[]; member and it's initialization look very strange, but it's hard to comment further since they are never used in the code.

How to modify array that pointer points to

I need to pass a char pointer to function, then change the value that it points to inside the function and print values outside the function.
The problem I have is that I'm losing it when I leave function and try to print it outside. What can I do to avoid this?
This is an code example:
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
cout << (pText);
cout should print
moob adaB
When I print inside the function, everything is fine(it prints reversed).
My task is to print It out outside the function (as you can see in a 4th line of code)
This is the full of code which have the bug (printing inside func works, outside didn't work)
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
char reverseText(char *text);
int main(){
char array[] = "Bada boom";
char *pTekst = array;
reverseText(pTekst);
cout << (pTekst); //in here it doesn't work
}
char reverseText(char *text){
char befRev[100]; int lenght=-1;
/*until *text doesn't meet '\0' */
for(int i=0;*text!='\0';i++){
befRev[i]=(*text);
text++;
lenght++;
}
/*reversing*/
int j=0;
for(int i=lenght;i>=0;i--){
*(text+j)=befRev[i];
j++;
}
for(int i=0;i<=lenght;i++) //in here it does print the right value
cout << text[i];
};
Just re-arrange the array in-place. The pointer itself doesn't need to change:
#include <cstring>
#include <algorithm>
void reverseText(char* array)
{
auto len = std::strlen(array);
std::reverse(array, array+len);
}
int main()
{
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText << std::endl;
}
Output:
moob adaB
If you really wanted to provide a pointer that points to a different address to the caller, you could simply return it:
char* foo(char* stuff)
{
char* tmp = ....;
...
// do some stuff
...
return tmp;
}
Alternatively, you could pass the pointer by reference, but the intent is less clear than in the previous version:
void foo(char*& stuff)
{
stuff = something_else;
}
But in both cases, you must make absolutely sure the thing the new pointer points to is valid outside of the function. This might require some dynamic memory allocation. For your case, it seems the best and simplest option is to re-arrange the array in place.
To answer your question, you have an error in logic. Notice that in your first loop in reverseText you increment the local pointer text. In your second loop you did not reset text to it's original value so beforeRev is being copied over starting at location text+offset.
If you were to look at pText on return from call to reverseText you would find it contains:
"Bada boom\0moob adaB"
Your reverseText should be renamed palindrome :)
This is pretty straightforward. Some points to note:
An array decays to a pointer when you pass it to a function.
You are passing in a null terminated string. So the length of the char array you are passing in is the length of the string (including white space) +1.
Because you are using a pointer there is no need to assign a temp variable to hold everything.
Here is some code in C that is easy to translate to C++. Working out the actual reverse algorithm is left for you as an exercise.
#include<stdio.h>
void reverseText(char* text)
{
// Hint: It can be done in one loop!
int i;
for(i = 0; i < 9; i++)
{
// Your algorithm to reverse the text. I'm not doing it for you! ;)
*(text + i) = 'r';
}
}
int main()
{
char array[] = "Bada boom";
reverseText(array);
printf("The text reversed: %s\n", array);
return 0;
}
My final code:
#include <iostream>
void reverseText(char* text){
int length=-1; char tmp;
/*Length = sign from 0 to 8 without counting explicit NUL terminator*/
for(int i=0;*(text+i)!='\0';i++){
length++;
}
int j=0; int i=length;
while(j<i){
tmp=*(text+j); //tmp=first
*(text+j)=*(text+i); //first=last
*(text+i)=tmp; //last=tmp
j++;
i--;
}
}
int main(){
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText;
}
I should have read more about pointers before I started this exercise.
You can either return a pointer or pass a pointer to pointer as a function argument.
//pointer to pointer
void reverseText(char** textPtr) {
char* newText = ...; //initialize;
...
*textPtr = newText; //assign newText
}
//return pointer
char* reverseText(char* text) {
char* newText = ...; //initialize
return newText;
}
Remember that if you allocate memory in this function you must do it dynamically (with new or malloc) and you have to free it afterwards (with delete or free respectively). Memory allocation in a function like this is probably a bad practice and should be avoided.

Reverse String C++ using char array

I wrote a simple C++ program to reverse a string. I store a string in character array. To reverse a string I am using same character array and temp variable to swap the characters of an array.
#include<iostream>
#include<string>
using namespace std;
void reverseChar(char* str);
char str[50],rstr[50];
int i,n;
int main()
{
cout<<"Please Enter the String: ";
cin.getline(str,50);
reverseChar(str);
cout<<str;
return 0;
}
void reverseChar(char* str)
{
for(i=0;i<sizeof(str)/2;i++)
{
char temp=str[i];
str[i]=str[sizeof(str)-i-1];
str[sizeof(str)-i-1]=temp;
}
}
Now this method is not working and, I am getting the NULL String as result after the program execution.
So I want to know why I can't equate character array, why wouldn't this program work. And what is the solution or trick that I can use to make the same program work?
sizeof(str) does not do what you expect.
Given a char *str, sizeof(str) will not give you the length of that string. Instead, it will give you the number of bytes that a pointer occupies. You are probably looking for strlen() instead.
If we fixed that, we would have:
for(i=0;i<strlen(str)/2;i++)
{
char temp=str[i];
str[i]=str[strlen(str)-i-1];
str[strlen(str)-i-1]=temp;
}
This is C++, use std::swap()
In C++, if you want to swap the contents of two variables, use std::swap instead of the temporary variable.
So instead of:
char temp=str[i];
str[i]=str[strlen(str)-i-1];
str[strlen(str)-i-1]=temp;
You would just write:
swap(str[i], str[sizeof(str) - i - 1]);
Note how much clearer that is.
You're using C++, just use std::reverse()
std::reverse(str, str + strlen(str));
Global variables
It's extremely poor practice to make variables global if they don't need to be. In particular, I'm referring to i about this.
Executive Summary
If I was to write this function, it would look like one of the two following implementations:
void reverseChar(char* str) {
const size_t len = strlen(str);
for(size_t i=0; i<len/2; i++)
swap(str[i], str[len-i-1]);
}
void reverseChar(char* str) {
std::reverse(str, str + strlen(str));
}
When tested, both of these produce dlrow olleh on an input of hello world.
The problem is that within your function, str is not an array but a pointer. So sizeof will get you the size of the pointer, not the length of the array it points to. Also, even if it gave you the size of the array, that is not the length of the string. For this, better use strlen.
To avoid multiple calls to strlen, give the function another parameter, which tells the length:
void reverseChar(char* str, int len)
{
for(i=0; i<len/2; i++)
{
char temp=str[i];
str[i]=str[len-i-1];
str[len-i-1]=temp;
}
}
and call it with
reverseChar(str, strlen(str))
Another improvement, as mentioned in the comments, is to use std::swap in the loop body:
void reverseChar(char* str, int len)
{
for(i=0; i<len/2; i++)
{
std::swap(str[i], str[len-i-1]);
}
}
Also, there is std::reverse which does almost exactly that.
//reverse a string
#include<iostream>
using namespace std;
int strlen(char * str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
void reverse(char* str, int len) {
for(int i=0; i<len/2; i++) {
char temp=str[i];
str[i]=str[len-i-1];
str[len-i-1]=temp;
}
}
int main() {
char str[100];
cin.getline(str,100);
reverse(str, strlen(str));
cout<<str<<endl;
getchar();
return 0;
}
If I were you, I would just write it like so:
int main()
{
string str;
cout << "Enter a string: " << endl;
getline(cin, str);
for (int x = str.length() - 1; x > -1; x--)
{
cout << str[x];
}
return 0;
}
This is a very simple way to do it and works great.
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char str[80];
cout << "Enter a string bro: \n";
gets_s(str);
for (int i = strlen(str) - 1; i > -1; i--)
{
cout << str[i];
}
}