C++: Using loops and variable patterns (sequence) - c++

I have a routine function process_letter_location(const char& c, string &word).
Inside my main I have declared a series of string variables like so:
string sf_1 = "something", sf_2 = "something", sf_3 = "something",
sf_4 = "something";
And i have a string word and i call my routine function as so
process_letter_location(word[0], sf_1);
process_letter_location(word[1], sf_2);
process_letter_location(word[2], sf_3);
process_letter_location(word[3], sf_4);
This does look a bit messy but i know i can use a loop to call the routine like
for(int i=0; i < 4; i++) {
process_letter_location (word[i], ?)
}
But I'm not so sure how i would go about assigning the second argument. The variables have 'sf_' in common and the only thing that change are the numbers. Is there anyway that i can incorporate this routine call in the loop? If not are there better ways of implementing this code?
Any help would be appreciated.
Thanks

You can use an array:
string sf[4] = { "something1", "something2", "something3", "something4"};
Then loop:
for(int i=0; i < 4; i++) {
process_letter_location (word[i], sf[i]);
}

You should use an array. Your use case screams it should be an array.
But if you can only change how you process the variables, you can use a variadic template function as well.
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
void process_letter_location(char c, string const& str)
{
cout << str << '\n';
}
void process_strings(char* buf, string const& str)
{
process_letter_location(*buf, str);
}
template<typename... Args>
auto process_strings(char* buf, string const& str, Args... args)
-> typename enable_if<sizeof...(Args)>::type
{
process_letter_location(*buf, str);
process_strings (++buf, args...);
}
int main() {
string sf_1 = "something1",
sf_2 = "something2",
sf_3 = "something3",
sf_4 = "something4";
char buff[10];
process_strings(buff, sf_1, sf_2, sf_3, sf_4);
return 0;
}
Which is just a fancy way to unroll the loop. See here

You can start with this refactoring: replace string with string * const
in the function process_letter_location. (Adjust the function definition
accordingly).
Then you can fill your favourite container with the string pointers
and loop on it.
I think you can learn a lot of C++ from this refactoring.
Let me show how you could write the loop:
std::vector<std::string*> strings = {&sf_1,
&sf_2,
&sf_3,
&sf_4};
for(int i=0; i < 4; i++) {
process_letter_location (word[i], strings[i]);
}
then you may consider using iterators rather than a C-style loop.

Related

error: variable or field 'Palindrome' declared void in c++

I'm getting this error hence I am new to c++ I could not understand
please help me!!!
I am writing a palindrome code
This is the code given below:.............
I am basically here using some extra concepts not doing in-direct fashion.
if anyone can post the correct code he/she is most welcome...
//palindrome
#include <cstring> //or use #include <string.h>
#include <iostream>
using namespace std;
void Palindrom(string& );
void Palindrome(string& word)// same as (const string& word)
{
int n = word.length();
string word2;
char reverse[n];
for(int i = 0; i <=n; i++){
word[i]=tolower(word[i]);
}
word2=word; //now both are small
for(int i = n-1; i >=0; i--){
reverse[n-1-i]=word2[i];
cout<<reverse[n-1-i];
}
for(int i =0; i >n; i++){ //printing reversed
cout<< " Reverse: "<<reverse[i]<<endl;
}
// word is ok and word2 gets reversed
for (int i = 0; i <= n; i++){
if(word[i]==reverse[i])
{
cout<<"\nit is palandrome ";
}
cout<<"\nit is not a palindrome ";
}
}
int main()
{ string k="YuUuy";
void Palindrome(k);
return 0;
}
Correct syntax for calling a function is Palindrome(k); without the void.
Few remarks:
Get a good c++
book.
// same as (const string& word) is not true.
You did not include <string> header.
It's good practice to use std::size_t for indices, but beware of unsigned>=0 condition being always true.
char reverse[n]; is wrong, n must be a compile-time constant, VLA are not part of the C++ standard.
Function calls should not have return type. Change void Palindrome(k); in main() function to Palindrome(k);
While declaring array, the expression should have constant value. So you can't use char reverse[n];. Change it to char *reverse = new char[n]; and deallocate it using delete[] reverse; after you are done using it.
I would recommend you to use smart pointer. You should also take a look at std::string instead of using stream of char.

Passing the std::string by reference doesn't update the string value in calling function

I am trying to remove duplicates from a string. The code goes like:
#include<iostream>
#include<stdio.h>
#include<string.h>
void removeDup(std::string s, std::string &ex)
{
int hash[256] = {0};
int k = 0;
for (int i = 0; i < s.size(); ++i)
{
if (hash[s[i]] == 0)
{
ex[k++] = s[i];
//std::cout<<ex[k-1];
}
hash[s[i]] = 1;
}
}
int main()
{
std::string s;
std::getline(std::cin, s);
std::string ss;
removeDup(s, ss);
std::cout<<ss<<std::endl;
return 0;
}
Now in main function I have printed the value of ss (which is passed as reference in removeDup function) but it prints nothing. Why is it so? Doesn't the value of string elements gets updated in called function?
Also, when I pass the string by address then I just get the first value printed.
eg :
void removeDup(std::string s, std::string *ex)
{
// same as above body function body
}
int main()
{
......
removeDup(s, &ss);
std::cout<<ss<<std::endl;
return 0;
}
In the output I just get the first letter of whatever is there in s. I can't understand. I am not much familiar with strings in programming languages. Kindly help.
This comes down to the fact that std::string::operator[](size_t index) expects passed index to be lower that string's size().
That means you need to either initialize ss with constructor (variant 2) that will fill it with input's size() worth of ' ''s or, better, use push_back() (ideally in conjunction with reserve() as a way to append elements to the output string.

Passing pointer to char* array into function to manipulate values on Arduino

[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);
}
}
}

reversing the letters of the words in a string

I want to reverse the letters of the words in a string and have to store it in the same array.example: i/p: hi how are you o/p: ih woh era uoy. i wrote this programs but it just prints the same string without reversing and the program is not terminating it continues to print something. i cant findout the mistake. please help me and tell me the correct code.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void stre(char (&a1)[20], int j1, int i1)
{
char b[20];
for(int k=i1-j1;k<i1;k++)
b[k]=a1[i1-k-1];
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
}
void main()
{
clrscr();
int j;
char a[20];
gets(a);
for(int i=0;a[i]!='\0';i++)
{
j++;
if(a[i]==' ')
{
stre(a,j,i);
j=0;
}
}
stre(a,j,i);
for(j=0;j<i;j++)
cout<<a[j];
getch();
}
friends after your answers i removed the semicolon in the for loop and also initialized j=0 but still i am not able to get the required output now for the i/p:hi how are you o/p:ihh hi hhi hhi. still need your help.
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
The semilcolon after the for loop prevents the last action from occuring multiple times.
try
#include <iostream>
using namespace std;
int main() {
int j =0;
char a[20] = "hi how are you";
char b[20] = "";
int l=0;
for(int i=0;a[i]!='\0';i++){
if(a[i]==' ' ||a[i+1]=='\0'){
cout<<j<<' '<<i;
if(a[i+1]=='\0'){
b[l++] = ' ';
}
for(int k=i;k>=j;k--){
b[l]=a[k];
l++;
}
for(int k=j;k<=i;k++){
cout<<b[k];
a[k] = b[k];
}
cout<<endl;
j = i+1;
}
}
cout << a;
return 0;
}
This for loop is terminated by the semi-colon:
for(k=i1-j1;k<i1;k++);
^^^
Here's a version that is not perfect by any means, but at least, it tries to be more like C++ than C:
http://ideone.com/f5vciW
first: tokenize into words and space sequences
//the spaces should be preserved
std::string test("hi how are you"),reference("ih woh era uoy");
std::vector<std::string> tokens;
tokenize(test,tokens);
then reverse the tokens
for (auto& token : tokens)
std::reverse(token.begin(),token.end());
assemble tokens into a string buffer
std::stringstream buf;
for (auto token : tokens)
buf<<token;
check the result
std::string res=buf.str();
assert(res==reference);
where the tokenizer looks like that:
template <typename TContainer,typename TString>
void tokenize(TString input,TContainer& res)
{
if (input.length()<2) {
res.push_back(input);
return;
}
typename TString::const_iterator pos=input.begin();
bool space_state=std::isspace(input[0],std::locale());
for (typename TString::const_iterator it=input.begin(); it!=input.end();
++it) {
bool is_space=std::isspace(*it,std::locale());
if (is_space!=space_state) {
res.push_back(TString(pos,it));
pos=it;
space_state=is_space;
}
}
//the rest
if (pos!=input.end()) {
res.push_back(
TString(
pos,
static_cast<typename TString::const_iterator>(input.end())
));
}
}
you passed j without assigning the value. so it will be garbage.
I can see two things in your code that may not result in the expected output:
1)
int j;
should be replaced with
int j=0;
And
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
the semicolon after the for loop needs to be removed.
FYI, this mixing of C and C++ code is not recommended (it's compromising readability). please stick to either one of them.
A similar example is shown on this site. They've also used almost the same approach that you'v e chosen(reversing each word by counting number of spaces) by with the help of stack data structure.
Make sure you have the STL library installed in your environment to run this code. Better run this code on linux platform.
Here's another, shorter version, doing the inversion in-line without using an extra buffer:
http://ideone.com/hs9NZ7
the criterion for the tokenizer is the change in the isspace condition:
auto next_token=
[&](char c) {
return std::isspace(c,loc)!=std::isspace(*pos,loc);
};
using that we can go through the input string and visit the tokens:
for (auto it=std::find_if(pos,test.end(),next_token);
it!=test.end();
it=std::find_if(pos,test.end(),next_token))
reversing them and updating the current position
std::reverse(pos,it);
pos=it;
and not forgetting the leftover token.

char*-Array as Parameter

I want to put the following code in a function: (The code isn't complete, but I think it should be clear to you)
char *parsedData[SEPERATOR];
for(int i=0; i<SEPERATOR; i++)
{
parsedData[i]=tmp;
}
The function should look like the following:
int main()
{
char *parsedData[SEPERATOR];
Parser(WTString, parsedData);
}
int Parser(char *WTString, *parsedData[SEPERATOR])
{
for(int i=0; i<SEPERATOR; i++)
{
parsedData[i]=tmp;
}
}
The code works fine in one function. By dividing the code in two functions I got no usable data.
I would be grateful if someone could help me. I don't want to use further libraries.
If you don't want to use stl, I propose this function:
int PointToDefault(char* target, char** parsedData, unsigned int count)
{
for (unsigned int i=0; i<count; i++)
{
parsedData[i] = target;
}
}
and this call:
#define SEPERATOR 15
int main()
{
char tmp[] = "default string";
char *parsedData[SEPERATOR];
PointToDefault(tmp, parsedData, SEPERATOR);
}
char *parsedData[SEPERATOR]; Why?
Why do you need to use a raw array of pointers to char in C++?
Why don't you just use a std::vector<std::string> and spare yourself a whole load of misery and despair.
A C++ way of doing it would look like this:
#include <string>
#include <vector>
std::vector<std::string> Parser(const char *WTString)
{
std::vector<std::string> result;
for(std::size_t i = 0; i != SEPERATOR; ++i)
{
result.push_back(tmp); // whatever tmp is
}
return result;
}
I dont want to use further librarys.
Don't worry, my code sample only requries the standard library.