Acessing/Adressing variables with strings and int in Arduino - c++

There's already a question about adressing variables with strings in Arduino, but the answers given didn't apply to my problem.
I have multiple sensors (around 14 and the number might increase) connected to my Arduino, I also have relays, engines and RFIDs. I'm creating a function that checks if all of the sensors are active.
The idea is basically this:
#define Sensor_1 2
#define Sensor_2 3
#define Sensor_3 4
#define Sensor_4 5
#define Sensor_5 6
int checkSensors(){
int all_active = 0;
int num_sens = 5;
int n;
int active_sens = 0;
for(n= 1; n <= num_sens; n++) {
if( !digitalRead("Sensor_" + n)) {
active_sens= active_sens+ 1;
}
else {
all_active = 0;
return ( all_active);
}
}
if(active_sens== num_sens) {
all_active = 1;
return(all_active);
}
}
The problem is: I want to address the variable Sensor_n, but I can't find out a way to do it. The error message I get is referring to the digitalRead("Sensor_" + n ) command.
error: invalid conversion from 'const char*' to 'uint8_t {aka unsigned char}' [-fpermissive]
I already tried to use "Sensor_" in a String = "Sensor_", I've tried to force a typecast to uint8_t, but the error message says that it loses precision.
I also tried the .toCharArray command, but it failed as well.
Is there a way to access a variable through a string + int?
I'm more familiar with the "loose" variables in PHP, so this is giving me a lot of trouble.

There are a few issues with your code. First you can't get the value of a variable or a define by dynamically using a string that is the name of the variable. It doesn't work that way in C. The easiest approach is to use an array and then just index through it. To make this work well I've changed the for loop to count from 0 since the array is indexed starting at 0. I changed the all_active logic assuming that at some point later you are going to want to know how many sensors are active instead of just whether they are all active or not. If you don't want that, then your logic is also more complicated than needed. It could just return 1 at the end of the for loop since all must have passed the test to get there.
#define Sensor_1 2
#define Sensor_2 3
#define Sensor_3 4
#define Sensor_4 5
#define Sensor_5 6
int sensors[] = {Sensor_1, Sensor_2, Sensor_3, Sensor_4, Sensor_5};
int checkSensors(){
int all_active = 1;
int num_sens = 5;
int n;
int active_sens = 0;
for(n= 0; n < num_sens; n++){
if( !digitalRead(sensors[n])){
active_sens= active_sens+ 1;
}
else {
all_active = 0;
}
}
return all_active;
}

In C this line will not work
if( !digitalRead("Sensor_" + n))
you cannot build a string like this in C. Since you didn't post the function digitalRead() I presume it takes a char* type, here a string, which in C you could build like this
char senstr[50];
sprintf(senstr, "Sensor_%d", n);
...
if (!digitalRead(senstr)) { ...
As a side issue, please get used to iterating loops from 0. You add 1 to interface with humans.

Related

How do I implement the number of rounds in this C++ code?

int round;
int Starting_index;
int hop_count;
for( round = 0; round < gNumRounds; round++)
{
Starting_index[round] = gPasswordHash[0+round*4] * 256 + gPasswordHash[1+round*4];
hop_count [round] = gPasswordHash[2+round*4] * 256 + gPasswordHash[3+round*4];
if(hop_count == 0) hop_count = 0xFFFF;
}
gPasswordHash, gNumRounds are both global variables. The place where I'm getting an error is with setting the Starting_index[round] and hop_count[round] inside the for loop.
There may be something wrong with my Starting_index and hop_count declarations, but I'm unsure what that is.
You need to declare those variables as arrays, not single int.
int Starting_index[MAXROUNDS];
int hop_count[MAXROUNDS];
Starting_index and hop_count aren't declared as arrays, they're currently only ints. You also should be declaring and defining round inside the for loop declaration instead of earlier: 'for (int round = 0; round < gNumRounds; round++)'.
And I don't really know what you mean by 'if (hop_count == 0) hop_count = 0xFFFF;'.

Edit string by calling it using concatenation in C++

I'm a very new C++ user (and a new StackOverflow user at that), and I'm trying to code a very basic Tic-Tac-Toe (Naughts and Crosses) game. I'm not sure how to render the board as it is updated.
My main question is if it is possible to call a string using concatenation. I have an array set up that indexes the states of the 9 spaces of the board using a 0 for empty, a 1 for an X, and a 2 for an O. If I set up 9 variables in a user-defined renderBoard() function named bit1, bit2, etc; Can I call them this way:
void renderBoard()
{
int i = 1;
string bit1;
string bit2;
string bit3;
string bit4;
string bit5;
string bit6;
string bit7;
string bit8;
string bit9;
while (i < 10)
{
if (Spaces[i] = 0)
{
(bit + i) = * //This is the main bit I'm wondering about
}
else
{
//Check for 1, 2, and edit the string bits accordingly
}
++i;
}
//Put all of the strings together, as well as some more strings for adding the grid
//Output the whole concatenated string to the command line
}
If anyone knows of a better way to do this, please let me know. I've tried Googling and rifling through various C++ help websites, but I find it difficult to express my particular case through anything other than a long-winded and specific explanation.
Thanks for you help!!
If I correctly understood your problem, your problem is that you want to access the strings named bit1, bit2, etc using a variable i like bit + i.
And no, you cannot do that!
It will throw a compile time error.
Please correct me if I didn't get what you are looking for.
But one question is still in my mind that why are you using string variables bit1, bit2 etc?
I think you just want to store single digit value in those strings. If this is the case, you can just use a single string of length 9.
You can do this as follows:
int i = 0; //because string indices start from 0 and also array indices.
string bit(9, ' '); //declare a string of length 9 with default value of a space (you can modify it with your default value)
while (i < 9) { // i < 9 because highest index will be 8
if (Spaces[i] == 0) {
bit[i] = '*';
} else {
}
++i;
}
Declaring 9 variables like this is apparently wrong. What you are looking for is an array.
std::array<std::string, 9> bits;
(You need #include <array> and #include <string>.)
Then, you can traverse the string using a for-loop: (in C++, arrays are indexed starting from zero, not one)
for (std::size_t i = 0; i < 9; ++i) {
// operate on bits[i]
}
In the for-loop, you can use the subscript operator to access the element: bits[i].
Finally, to put all the strings together, use std::accumulate:
std::accumulate(bits.begin(), bits.end(), std::string{})
(You need #include <numeric>.)

How do I fix this runtime error related to div by zero?

Here is the chunk of code in question that I've pulled from my program:
#include <vector>
using namespace std;
vector<double> permittingConstructionCosts(56);
static const int PERMITTING_PERIODS = 0;
static const int CONSTRUCTION_PERIODS = 11;
static const double CONSTRUCTION_COSTS = 2169506;
static const double PERMITTING_COSTS = 142085;
static const int PERMITTING_CONSTRUCTION_PERIODS = PERMITTING_PERIODS + CONSTRUCTION_PERIODS;
void calcExpenses // Calculates permitting and construction expenses
(
vector<double>& expense,
double value1,
double value2
)
{
int i;
for (i=0; i<=PERMITTING_PERIODS + 1; i++)
{
expense[i] = value1;
}
for (i=PERMITTING_PERIODS + 2; i<expense.size(); i++)
{
if (i < PERMITTING_CONSTRUCTION_PERIODS + 2)
{
expense[i] = value2;
}
}
}
int main()
{
if (PERMITTING_PERIODS != 0)
{
calcExpenses(permittingConstructionCosts, -PERMITTING_COSTS/PERMITTING_PERIODS, -CONSTRUCTION_COSTS/CONSTRUCTION_PERIODS);
}
else
{
calcExpenses(permittingConstructionCosts, 0, -CONSTRUCTION_COSTS/CONSTRUCTION_PERIODS);
}
return 0;
}
According to ideone (http://ideone.com/LpzUny) the code has a runtime error that returns "time: 0 memory: 3456 signal:11".
I've tried to look for solutions on SO and found the following links:
How can I avoid a warning about division-by-zero in this template code?
How to eliminate "divide by 0" error in template code
However, I don't know how to use templates because I am new to c++ and I'm not sure I need to use them in this case so I have no clue how to adapt those solutions to my particular problem if it's even possible.
I'm pretty sure that the "-PERMITTING_COSTS/PERMITTING_PERIODS" is causing the problem but I thought that simply checking the divisor would solve the problem. This function seems to work for every other value other than 0 but I need to account for the case where PERMITTING_PERIODS = 0 somehow.
I would very much appreciate any help I can get. Thanks in advance!
Edit: I actually do initialize the vector in my program but I forgot to put that in because the size is decided elsewhere in the program. The chunk of code works once I fix that part by putting in a number but my program still has a runtime error when I set PERMITTING_PERIODS to 0 so I guess I have to go bug hunting elsewhere. Thanks for the help!
The problem lies inside the function, which is called by the else statement in the main function:
for (i=0; i<=PERMITTING_PERIODS + 1; i++)
{
expense[i] = value1;
}
Here, PERMITTING_PERIODS is 0, thus you loop from 0 to 2 (inclusive).
However, expense.size() is 0, since your vector is empty. As a result, you are trying to access an empty vector, which causes a segmentation fault.
With that said, print the value of i inside the loop, you should see that you try to access expense[0], but the vector is empty, so it has no first slot (basically it doesn't have any)!!
So replace that with:
expense.push_back(value1);
which will allocate enough space for your values to be pushed into the vector.
The answer given in the cited links, (i.e. "How to eliminate "divide by 0" error in template code") applies equally well here. The other answers were given in the context of templates, but this is completely irrelevant. The sample principle applies equally well with non-template code, too. The key principle is to compute a division, but if the denominator is zero, you want to compute the value of zero instead of the division.
So we want to compute -PERMITTING_COSTS/PERMITTING_PERIODS, but use the value of 0 instead of the division when PERMITTING_PERIODS is 0. Fine:
int main()
{
calcExpenses(permittingConstructionCosts,
(PERMITTING_PERIODS == 0 ? 0: -PERMITTING_COSTS)/
(PERMITTING_PERIODS == 0 ? 1: PERMITTING_PERIODS),
-CONSTRUCTION_COSTS/CONSTRUCTION_PERIODS);
return 0;
}

Iteration to create variables

I was just curious to know if there is way to create a new variable with a new name every time a loop is executed.
For example:
#include <iostream>
int main()
{
for (int x = 1 ; x<=5 ; x++)
int a_x;
return 0;
}
5 new variables should be created with names a_1, a_2, ..., a_5
The above code just shows what I am looking for and is not the answer.
Is this possible without using arrays?
No, there is no way to do what you've outlined (directly). Here are several possible alternatives:
First off, if you do not need the "variables" to be accessible outside the loop, just use a normal local variable:
for (int x = 1; x <= 5; ++x) {
int a = whatever; // This will be freshly redeclared & reinitialised in each iteration
}
If the bounds of the iteration are known at compile time, you can use an array:
std::array<int, 5> a;
for (int x = 0; x < a.size(); ++x) {
a[x];
}
If the bounds are only known at runtime, use a dynamic array:
std::vector<int> a(the_runtime_size);
for (int x = 0; x < a.size(); ++x) {
a[x];
}
If you really need individual variables for some reason (and you know the number at compile time), you could resort to preprocessor tricks with Boost.Preprocessor. But that is far above beginner level:
#include <boost/preprocessor>
#define DECLARE_MY_VARIABLE(z, idx, name) \
int BOOST_PP_CAT(name, BOOST_PP_CAT(_, idx));
BOOST_PP_REPEAT(5, DECLARE_MY_VARIABLE, a)
The code above will expand to:
int a_0; int a_1; int a_2; int a_3; int a_4;
You could of course take this several steps further, to have each of the variables of a different type, or name them by names instead of by indices. It will just require more macro magic.
Disclaimer: Do NOT use this approach unless you very clearly know you need it. Even then, reconsider twice before you actually do that. And if you still do, document it heavily. Stuff like this should generally be hidden deep inside a library under a nice & clean user-friendly interface.
No you can't do that in C++.
The best thing to do in this case would be to create an array of ints and use the for loop to populate them.
int a_x[5];
for (int x = 1 ; x<=5 ; x++)
a_x[x - 1] = /*ToDo - something*/
Note that
arrays are zero-based: can you see how I've used x - 1. The normal thing to do would be to rebase x in the for loop though: for (int x = 0 ; x < 5; ...
arrays are not initialised. You must populate the contents.
While many will assume that this is impossible, it can be achieved with the preprocessor. It is necessary that the loop count is known at compile time. Here I use the Boost Preprocessor Library. The example for PP_REPEAT does almost exactly what you want.
#include <boost/preprocessor/repetition/repeat.hpp>
#define DECL(z, n, text) text ## n = n;
int main()
{
BOOST_PP_REPEAT(5, DECL, int a_) // expands to int a_0 = 0; int a_1 = 1; ...
return 0;
}
Please remember: this is certainly not what you want. You probably want to use an array. Do only use this if you are absolutely certain that you need it.

Initializing An Array with a Variable Size

I am almost done with my code except I need help on two thing. Here is my code: Code. For the function below, I am trying to make it so that I can use the input of "n" to initialize my array, myBits, instead of a constant, which is currently 5.
My Other question is right below that. I am trying to switch all of the right most bits to "true". I wrote the for loop in "/* .....*/" but it doesn't seem to be working. Right above it, I do it long ways for C(5,4) ....(myBit[0] = myBit[1]....etc...... (I am using this to find r-combinations of strings).... and it seems to work. Any help would be appreciated!!
void nCombination(const vector<string> &Vect, int n, int r){
bool myBits[5] = { false }; // everything is false now
myBits[1] = myBits[2] = myBits[3] = myBits[4] = true;
/* for(int b = n - r - 1; b = n - 1; b++){
myBits[b] = true; // I am trying to set the r rightmost bits to true
}
*/
do // start combination generator
{
printVector(Vect, myBits, n);
} while (next_permutation(myBits, myBits + n)); // change the bit pattern
}
These are called variable length arrays (or VLAs for short) and they are not a feature of standard C++. This is because we already have arrays that can change their length how ever they want: std::vector. Use that instead of an array and it will work.
Use std::vector<bool>:
std::vector<bool> myBits(n, false);
Then you have to change your while statement:
while (next_permutation(myBits.begin(), myBits.end()));
You will also have to change your printVector function to take a vector<bool>& as the second argument (you won't need the last argument, n, since a vector knows its own size by utilizing the vector::size() function).
As to your program: If you're attempting to get the combination of n things taken r at a time, you will need to write a loop that initializes the last right r bools to true instead of hard-coding the rightmost 4 entries.
int count = 1;
for (size_t i = n-1; i >= 0 && count <= r; --i, ++count)
myBits[i] = true;
Also, you should return immediately from the function if r is 0.