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;
Related
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.
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.
I'm making a class to delete repeated character from a random word. For example if the input is "aabbccddeeff", it should output "abcdef". However my output contains strange characters after "abcdef". The main.cpp file already exists as the requirements for creating the class. Please see the following codes:
main.ccp
#include <iostream>
#include "repeatdeletion.h"
using namespace std;
int main()
{
char* noRepeats;
int length;
string s;
cout<<"Enter a random word with repeating characters: ";
cin>>s;
RepeatDeletion d;
length=s.length();
noRepeats=d.deleteRepeats(s, length);
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
delete [] noRepeats;
noRepeats=NULL;
return 0;
}
repeatdeletion.h
#ifndef REPEATDELETION_H
#define REPEATDELETION_H
#include <iostream>
using namespace std;
class RepeatDeletion
{
char* c;
char arr[128]={};
bool repeated;
bool isRepeated(char);
public:
RepeatDeletion();
~RepeatDeletion();
char* deleteRepeats(string, int);
};
#endif // REPEATDELETION_H
repeatdeletion.cpp
#include "repeatdeletion.h"
RepeatDeletion::RepeatDeletion()
{
repeated=false;
}
RepeatDeletion::~RepeatDeletion()
{
delete [] c;
c=NULL;
}
bool RepeatDeletion::isRepeated(char c){
bool repeated=false;
if (arr[c]>=1){
repeated=true;
arr[c]++;
}else{
arr[c]++;
}
return repeated;
}
char* RepeatDeletion::deleteRepeats(string str, int len){
c=new char[len];
int j=0;
for (int i=0; i<len; i++){
if (isRepeated(str[i])==false){
c[j]=str[i];
j++;
}
}
return c;
}
Your return character array is not null terminated.
The length function of string does not include \0.
You have two choices
Add null at the end of returned character array, and std::cout the char array directly (instead of char by char)
Output the final length of your char array, and use that as range to print it char by char
Your printing loop loops using the old and unmodified string length. That means you will go outside the characters you added to memory returned by deleteRepeats.
The easiest solution to handle this is to terminate the data as a proper string, and check for the terminator in the loop.
If you want to use a C-string array, they have a null terminator at the end. That means you'll want to (in deleteRepeats) define your character array one character larger than the length:
c=new char[len+1];
And, after the for loop, ensure you put that null terminator in:
c[j] = '\0';
Then, in your calling function, you can just do:
cout << noRepeats;
Even if you don't want to use C strings, you'll need to communicate the new length back to the caller somehow (currently, you're using the original length). The easiest way to do that is (IMNSHO) still using a C-style string and using strlen to get the new length (a).
Otherwise, you're going to need something like a reference parameter for the new length, populated by the function and used by the caller.
(a) But I'd suggest rethinking the way you do things. If you want to be a C++ coder, be a C++ coder. In other words, use std::string for strings since it avoids the vast majority of problems people seem to have with C strings.
That's because in your code you write the following:
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
Here, length refers to the length of the original string (which you, by the way shouldn't pass to your deleteRepeats method). I would suggest you make deleteRepeats return a string and write something like this:
std::string noRepeats = d.deleteRepeats(s);
std::cout << "Your word without any repeating characters: ";
std::cout << noRepeats << std::endl;
C-style string (char *, if you insist) follow the convention that the last character is '\0', indicating that the string ends. You could also change deleteRepeats by appending '\0', i.e.
char* RepeatDeletion::deleteRepeats(string str){
c = new char[str.size() + 1];
int j = 0;
for (int i = 0; i < str.size(); i++){
if(isRepeated(str[i]) == false){
c[j] = str[i];
j++;
}
}
c[j] = '\0';
return c;
}
and in your main
std::cout << noRepeats << std::endl;
instead of the for loop. But really, you should use std::string, and if possible not mix it with char *. Hope that helps.
for(k=0;k<length;k++)
Here length should be the exact length of noRepeats, but not of s
so :
char* RepeatDeletion::deleteRepeats(string str, int len)
should return the length-after too
use std::unique it does what you want:
std::string s{};
std::cin>>s;
auto it = std::unique(std::begin(s), std::end(s));
s.resize(std::distance(std::begin(s),it));
std::cout << s;
the way it works is to go through the range begin to end and move all the remaining elements forward if the current element is equal to the next. It returns the position of the end of the new string (it in this example) but does not actually shorten the string so on the next line we shorten the string to the length equal to the distance of begin() to it.
see live at http://ideone.com/0CeaHW
[PLEASE CHECK FINAL EDIT BELOW FOR UPDATE]
My C++ is a bit rusty (to say the least) and I'm having an issue trying to pass a char array into a function to manipulate the values. Example code below:
void myFunction(char* splitStrings,String stringToSetInLoop) {
char substringPtr[stringToSetInLoop.length()];
stringToSetInLoop.toCharArray(substringPtr, stringToSetInLoop.length());
for(int i = 0; i < 10; i++) {
splitStrings[i] = *substringPtr;
}
}
char *mySplitStrings[10];
myFunction(*mySplitStrings,String("Repeat Me"));
Serial.println(mySplitStrings[0]);
The code does not crash, but it outputs a blank line. I suspect that I need to initialize a 2 dimensional array outside the function to pass in so that memory space is allocated. I'm guessing that, although the substring pointer exists inside the function, the memory is destroyed, leaving the char* array mySplitStrings[0] pointing at nothing. Also, I think I need to pass in the reference to the array memory space, not as a pointer.
The ultimate goal here is to be able to pass a char array into a function, assign some values to it, then use those values back in the main code loop. If there's a better way to achieve this, then please let me know.
Thanks in advance. Please free me from my personal pointer/reference hell!
EDIT: Further note, this code is being run on an arduino, so the C++ is limited.
EDIT: When I try to pass in a reference to the char* pointer, I get this error, which I'm not sure how to change the function parameters to fix: error: cannot convert char* ()[10] to char for argument 1 to void myFunction(char*, String). Can anybody please take a stab at showing me a working example?
EDIT:
Thanks to the responses... I now have a working static library function that splits strings passed as a char* array. I know it's not pretty, but it does work. Thanks you to those who contributed. Code below:
void ExplodeString::explode(char* explodeResults[], String str, String delimiter) {
int delimiterPosition;
int explodeResultsCounter=0;
String subString;
do {
delimiterPosition = str.indexOf(delimiter);
if(delimiterPosition != -1) {
subString = str.substring(0,delimiterPosition);
char *subStringPtr[subString.length()+1];
subString.toCharArray(*subStringPtr, subString.length()+1);
explodeResults[explodeResultsCounter++] = strdup(*subStringPtr);
str = str.substring(delimiterPosition+1, str.length());
} else { // here after the last delimiter is found
if(str.length() > 0) {
subString = str;
char *subStringLastPtr[subString.length()+1];
subString.toCharArray(*subStringLastPtr, subString.length()+1);
explodeResults[explodeResultsCounter++] = strdup(*subStringLastPtr);
}
}
} while (delimiterPosition >=0);
}
Usage:
char* explodeResults[10];
ExplodeString::explode(explodeResults, String("cat:dog:chicken"), String(":"));
Serial.println(explodeResults[0]);
Serial.println(explodeResults[1]);
Serial.println(explodeResults[2]);
EDIT: Man, this is sooo much easier when you use the stdlib:
void ExplodeString::explode(std::vector<std::string> &explodeResults, std::string str, char delimiter) {
std::stringstream data(str);
std::string line;
while(std::getline(data,line,delimiter))
{
explodeResults.push_back(line);
}
}
Usage:
std::vector<std::string> commandsResult;
char delimiter[] = ",";
std::string _inputString = "my,string,to,parse";
ExplodeString::explode(commandsResult, _inputString, delimiter[0]);
How to pass an array of char*:
void myFunction(char* splitStrings[10], String stringToSetInLoop) {
// ...
char *mySplitStrings[10];
myFunction(mySplitStrings, String("Repeat Me"));
This will also work:
void myFunction(char* splitStrings[], String stringToSetInLoop) {
and this:
void myFunction(char** splitStrings, String stringToSetInLoop) {
Also, seems there is STL for avr platform - include it, C++ without STL is smth strange.
You are not allocating space for character arrays and just passing pointer of character array.
Instead of using char*splitStrings[10], you can use 2d char array with sufficient space to accomodate max length string. Assuming you max string length is less that 64 you can do something like this.
char splitString[10][64];
void myFunction(char**splitStrings,String stringToSetInLoop)
or
void myFunction(char splitString[][64], String stringToSetInLoop)
{
int len = stringToSetInLoop.length();
for(int i = 0; i<10; i++)
{
for(int j = 0; i<len; j++)
{
splitString[i][j] = stringToSetInLoop.charAt(j);
}
}
}
So I'm making a function that is similar to SubStr. This is an assignment so I cannot use the actual function to do this. So far I have created a function to take a string and then get the desired substring. My problem is returning the substring. In the function when I do Substring[b] = AString[b]; the substring is empty, but if I cout from inside the function I get the desired substring. So what is wrong with my code?
Here is a working demo: http://ideone.com/4f5IpA
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length);
int main() {
char someString[] = "abcdefg";
char someSubString[] = "";
subsec(someString, someSubString, 1, 3);
cout << someSubString << endl;
return 0;
}
void subsec(char AString[], char Substring[], int start, int length) {
for (int b = start; b <= length; b++) {
Substring[b] = AString[b];
}
}
Maybe this does what you're looking for? It's hard to say as your initial implementation used the length parameter as more of an end position.
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length)
{
const int end = start + length;
int pos = 0;
for(int b = start; b < end; ++b)
{
Substring[pos++] = AString[b];
}
Substring[pos] = 0;
}
int main()
{
char someString[50] = "abcdefghijklmnopqrstuvwxyz";
char someSubString[50];
subsec(someString, someSubString, 13, 10);
cout << someSubString << endl;
return 0;
}
There are several problems with the code:
1) The char arraysomeSubString has size 1 which cannot hold the substring.
2) The subsec is not correctly implemented, you should copy to the Substring from index 0.
Also remember to add \0 at the end of the substring.
void subsec(char AString[], char *Substring, int start, int length) {
int ii = 0;
for (int jj = start; jj <= length; jj++, ii++) {
Substring[ii] = AString[jj];
}
Substring[ii] = '\0';
}
You need to allocate more than 1 byte for someSubString i.e.
char someSubString[] = "xxxxxxxxxxxxxxxxxx";
or just
char someSubString[100];
if you know the max size you'll ever need.
Either would allocate enough space for the string you're copying to it. Then, you're not doing anything about the terminating 0 either. At the end of a C-style string there needs to be a terminating null to signify end of string. Otherwise cout will print something like;
abcdefgxxxxxxx
if you initialized with x's as I indicated.
There are a few problems with your code as it stands. Firstly, as your compiler is no doubt warning you, in C++ a string literal has type const char[], not just char[].
Secondly, you need to have enough space to store your substring. A good way to do this is for your function to allocate the space it needs, and then pass back a pointer to this memory. This is the way things are typically done in C code. The only thing is that you have to remember to delete the allocated array when you're done with it. (There are other, better ways to do this in C++, with things like smart pointers and wrapper objects, but those come later :-) ).
Thirdly, you'll have a problem if you request a length which is actually longer than the passed-in string -- you'll run off the end and start copying random memory (or just crash), which is definitely not what you want. C strings are terminated with a "nul byte" -- so you need to check whether you've come across this.
Speaking of the nul, you need to make sure that your substring ends with one.
Lastly, it's not really a problem but there's no need for the start parameter, you can just pass a pointer to the middle of the array if you want to.
char* substring(const char* str, int length)
{
// Allocate memory for substring;
char* subs = new char[length+1];
// Copy characters from given string
int i = 0;
while (i < length && str[i] != '\0') {
subs[i] = str[i];
i++;
}
// Append the nul byte
subs[i] = '\0';
return subs;
}
int main()
{
const char someString[] = "foobarbaz"; // Note -- must be const in C++
char* subs = substring(someString + 3, 3);
assert(strcmp(subs, "bar") == 0);
delete subs;
}