CHAR Compare is right, even when it's wrong - c++

first im new at c++ programming and at the moment im stuck in a maybe very easy problem.
I thought, after get the other stuff working and in my oppinion, much harder, i will implement a little string compare and im are ready, ha ha...
I tryed to figure out what is the problem and working on it since hours...
I try to make a string compare.
With serial print i see the correct letters. For Example i compare "A" and "B".
My Problem is, that this compare is right, even when it's wrong.
bool debug = true;
void setup() {
// put your setup code here, to run once:
if (debug) { Serial.begin(9600); }; // Initialize serial communications with the PC
}
void loop() {
int result;
char myWord[6] = "#VOGEL";
char wordBuff[5];
char wordLetter;
char letterBuff;
// I do this here, because actually i get all values from two RFID Reader
strncpy( wordBuff, &myWord[1], 5 );
wordBuff[5] = '\0';
for (int fieldNr = 0; fieldNr < 5; fieldNr++)
{
wordLetter = wordBuff[fieldNr];
letterBuff = 'L';
result = strcmp(letterBuff,wordLetter); // Should be every time wrong? But it is sometimes true?
if ( result == 0)
{
if(debug){ Serial.print(F("Right Field: "));Serial.println(fieldNr);
Serial.print(F(" LetterA: "));Serial.print(wordLetter);Serial.println(F("#"));
Serial.print(F(" LetterB: "));Serial.print(letterBuff);Serial.println(F("#"));}
}
else
{
if(debug){ Serial.print(F("Wrong Field: "));Serial.println(fieldNr);
Serial.print(F(" LetterA: "));Serial.print(wordLetter);Serial.println(F("#"));
Serial.print(F(" LetterB: "));Serial.print(letterBuff);Serial.println(F("#"));}
}
}
delay(1000); //NUR für TESTZWECKE
}

strcmp is only for const char *, not a single char like you are using it.
I don't remember if Arduino permits you to use the std::string but in case just use it.
It introduce you lot more methods for string handling. Like s.find(c) that return directly the position of the char in the string.
By the way, to compare 2 char, in your example, just use a simple:
if(c1 == c2)
...
else
...
It should solve it.

Related

Returning different parts of a char array arduino

I asked a question here about my issue and thanks to #enhzflep I solved the huge part of my problem. My problem was if I write 46754!ABCDEFG12345#qwerwe to the serial, I want to get AB which is two chars after '!'. The code below does this work perfectly. However now I need to get 'CD', 'EF', three chars before '#' (for my example it means '345') and the whole thing between these things which is 'G12' the size of 'G12' depends on the size of the whole thing between '!' and '#'. In short I want to get different parts of the char array between '!' and '#'.
char pack[5] = {0};
char command[5] ={0};
int Index = 0;
bool Seen = false;
void setup(){
Serial.begin(9600);
}
void loop(){
while (Serial.available() > 0){
char received = Serial.read();
if (received == '!')
{
Seen = true;
}
else if (received == '#')
{
return strdup(pack);
return strdup(command);
}
else if (Seen == true){
if(Index<2){
pack[Index++] = received;
Serial.print(received);
}
/*if(Index>2&&Index<5){
command[Index++] = received;
Serial.print(received);
} */
}
}
return NULL;
}
I can't test any code myself, but I think this should work. Change the allocation of command to 200 bytes. Your commented out code seemed mostly correct. I just made some minor changes:
if(Index>=2){
command[Index-2] = received;
Index++;
Serial.print(received);
}

String extraction issue in Arduino

I have the following Arduino code
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"
#include<String.h>
InetGSM inet;
char msg[165];
char store[2];
char a;
char b;
char* disp;
boolean started=false;
void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(2400)) {
Serial.println("\nstatus=READY");
started=true;
} else Serial.println("\nstatus=IDLE");
if(started)
{
//GPRS attach, put in order APN, username and password.
//If no needed auth let them blank.
if (inet.attachGPRS("TATA.DOCOMO.INTERNET", "", ""))
Serial.println("status=ATTACHED");
else Serial.println("status=ERROR");
delay(1000);
//TCP Client GET, send a GET request to the server and
//save the reply.
inet.httpGET("www.boat.esy.es", 80, "/retrieve.php", msg, 165);
//Print the results.
Serial.println("\nData received:");
disp = strstr(msg,"\r\n\r\n");
disp = disp+4;
a = disp[1];
b = disp[2];
}
}
void loop()
{
Serial.println("Begin");
Serial.println(a);
Serial.println("+");
Serial.println(b);
Serial.println("End");
delay(500);
}
The disp variable in my program accepts the value 1 & 1 as string. I want this 1 & 1 to be stored in two separate variables. SO I tried the way mentioned above and this is what I got
Output
Begin
1
+
End
Begin
1
+
End
Begin
1
+
End
If I understand array correctly, char arr[100] is same as char* arr, just that the former one reserves 100 character locations on the memory, then b = disp[2] should give the latter 1 of 11 right?
I am not trying to use the String library because that will occupy a lot of memory. So if there's any way that I'm not aware of that extract both the 1s & store them separately, please let me know.
Thank you for your time!
Your code is almost correct.
The problem is here:
disp = strstr(msg,"\r\n\r\n");
disp = disp+4; // now disp points to the string "11" (correct)
// what follows is wrong
a = disp[1]; // this is the second char element if the disp string
b = disp[2]; // this is the zero terminator of the disp string
You need this because in C arrays indexes start with 0:
a = disp[0];
b = disp[1];
Small test program:
#include <stdio.h>
#include <string.h>
int main()
{
char *disp;
char msg[] = "Fake Header\r\n\r\n12";
char a;
char b;
disp = strstr(msg,"\r\n\r\n");
disp = disp+4;
a = disp[0];
b = disp[1];
printf("a = %c\nb = %c\n", a, b);
return 0;
}
Output:
a = 1
b = 2
There are quite a few problems with your code here...
Firstly, all your variables are un-initialised and you're accessing them after their declaration without initially giving them any value in memory. To solve this set each variable to something before you continue on like so:
char a = ''; // & so on...
Next up, char* disp; is a pointer, not a variable. You dont actually know the physical location of disp, it points to somewhere it memory, maybe a bit of populated memory, maybe nothing at all. So the best way to store something in disp is to turn it into an array and they write to it part by part reading when you need and terminating the variable with the correct formatting.
e.g
char disp[2] = {}; // Declare disp...
disp[0] = '1'; // Write to disp...
disp[1] = '1';
disp[2] = '\0';
& finally the webserver you're connecting too has DynDNS attached to the address, and anybody can access it without a password and anybody can start attacking it, so I would hide it.

return a char function with random options and local variables

I have created a unit test harness to test my program. I wanted it to be able to randomly test each run but I'm not sure how to go about doing this. Here is what I was think but I get stuck on what to do next, any guidance would be much appreciated.
int main (void)
{
int testNumber = 1; //for testing
char carName[] = "";
double carCost = 0;
carName = carChosen (testNumber);
carCost = assessCost (carName); //assessCost takes in the car name and checks what cost of the car will be (error checking so only certain cars can be chosen)
return 0;
}
"testNumber" would normally be seeded with time to create different number's from 1 - 15, but in this situation it's going to be "1" for testing.
This is next bit that I'm having trouble with. Within this function there would be 15 diffrent car options and it will return one depending on the randomly created number.
char carChosen (int randNum)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
return carOne; //local variables, not going to work...
}
else if (randNum == 2)
{
return carTwo; // Again, these return's are here to better represent what I'm trying to create but failing to do so..
}
}
I understand you cannot return local variables, what can I do instead?
This
void carChosen (int randNum, char * out)
{
char carOne[] = "Honda";
char carTwo[] = "Ford";
if (randNum == 1)
{
strcpy(out, carOne);
}
else if (randNum == 2)
{
strcpy(out, carTwo);
} //.. handle other cases
}
Call like
char carName[MAX_LEN];
carChosen (testNumber, carName);
Also maybe you are better of using switch instead of nested if..else if you have many conditions to test.
I thought it was C looking at the code, if you use C++, you can just return std::string objects from your function without any issues.
As others have pointed out, your code looks like C code. If you want to use C++, then read up on std::string and use that.
If you want to continue with your approach (which is very much a C-like approach), then you'll need to better understand how C strings work. Namely, how they are stored in memory and how a char is different from a char * is different from a char array[].
Putting most of that aside for now, my first guess based upon your example code is that you won't actually be modifying the contents of the string. You just want the string for its contents, but you won't be changing them. If this is accurate than you can just use regular char * variable to hold a pointer to a char string. You only need one copy of the string hanging around, so you can pass around a pointer to that one copy and everyone can read from that pointer. A quick way to do this is to just use the string literal directly.
const char* carChosen (int randNum)
{
if (randNum == 1)
{
return "Honda";
}
else if (randNum == 2)
{
return "Ford";
}
else
{
return "Audi";
}
}
Note that we are returning a const char *. The const is just indicating that we will not be modifying the string that is pointed to. We definitely do not want to do that because it points to a string literal (which you are not allowed to modify). Once you have the const char * returned by carChosen, you can pass that along to other functions, e.g. assessCost.

Serial.println changes return value of function (Arduino)

I've been experiencing some very odd behaviour from what should be a very simple function: an integer is passed to the function, and depending on its value will return an unsigned char specific to that integer.
I kept experiencing a problem in which it would return a different value to those that are hard coded into the function. I've had to rewrite the code a number of times to get it to stop happening, but I have found a way to recreate it every time to illustrate how something that shouldn't change the return value is doing.
Below is an example sketch to illustrate:
unsigned char* brokenFunction(int id)
{
switch (id)
{
case 0:
{
//Serial.println("Break it...");
unsigned char retval[8] = {
0b01110,
0b11011,
0b10001,
0b10001,
0b10001,
0b10001,
0b10001,
0b11111
};
return retval;
}
break;
case 5:
{
unsigned char retval[8] = {
0b01110,
0b11011,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111
};
return retval;
}
break;
}
}
void setup()
{
Serial.begin(9600);
unsigned char* array = brokenFunction(0);
Serial.println(*array);
}
void loop()
{
}
On line 7 is a call to Serial.println which is currently commented out. If you run the sketch on your Arduino with this line commented out, the Serial.println call in the setup function will return the value 14 (which is correct).
If, however, you uncomment line 7, the Serial.println call in the setup function will now return what seems like a random value; for my last test it was the value 91; see the serial window log below:
14
Break it...
91
As you can see, my first attempt returned 14, but the subsequent attempt with the extra Serial.println call resulted in the return value being changed.
Does anyone have any idea what may be going wrong here? There were other things I did that managed to replicate this too, but this is the most simple one to use as an example. It's almost as if, if the function is taking a bit longer to finish that the return value is being corrupted some how.
Any help or ideas would be much appreciated.
You are returning a local array from the function brokenFunction(int id), which stops existing when you return, causing undefined behavior from that point on.

C code - need to clarify the effectiveness

Hi I have written a code based upon a requirement.
(field1_6)(field2_30)(field3_16)(field4_16)(field5_1)(field6_6)(field7_2)(field8_1).....
this is one bucket(8 fields) of data. we will receive 20 buckets at a time means totally 160 fields.
i need to take the values of field3,field7 & fields8 based upon predefined condition.
if teh input argument is N then take the three fields from 1st bucket and if it is Y i need
to take the three fields from any other bucket other than 1st one.
if argumnet is Y then i need to scan all the 20 buckets one after other and check
the first field of the bucket is not equal to 0 and if it is true then fetch the three fields of that bucket and exit.
i have written the code and its also working fine ..but not so confident that it is effctive.
i am afraid of a crash some time.please suggest below is the code.
int CMI9_auxc_parse_balance_info(char *i_balance_info,char *i_use_balance_ind,char *o_balance,char *o_balance_change,char *o_balance_sign
)
{
char *pch = NULL;
char *balance_id[MAX_BUCKETS] = {NULL};
char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
char *str[160] = {NULL};
int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
int total_bukets ;
memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
//balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0';
pch = strtok (balance_info,"*");
while (pch != NULL && i < 160)
{
str[i]=(char*)malloc(strlen(pch) + 1);
strcpy(str[i],pch);
pch = strtok (NULL, "*");
i++;
}
total_bukets = i/8 ;
for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
{
balance_id[j]=str[b_id];
b_id=b_id+8;
}
if (!memcmp(i_use_balance_ind,"Y",1))
{
if (atoi(balance_id[0])==1)
{
memcpy(o_balance,str[2],16);
memcpy(o_balance_change,str[3],16);
memcpy(o_balance_sign,str[7],1);
for(i=0;i<160;i++)
free(str[i]);
return 1;
}
else
{
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
}
else if (!memcmp(i_use_balance_ind,"N",1))
{
for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
{
b_ind=(j*8)+2;
bc_ind=(j*8)+3;
bs_ind=(j*8)+7;
if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
{
memcpy(o_balance,str[b_ind],16);
memcpy(o_balance_change,str[bc_ind],16);
memcpy(o_balance_sign,str[bs_ind],1);
for(i=0;i<160;i++)
free(str[i]);
return 1;
}
}
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
My feeling is that this code is very brittle. It may well work when given good input (I don't propose to desk check the thing for you) but if given some incorrect inputs it will either crash and burn or give misleading results.
Have you tested for unexpected inputs? For example:
Suppose i_balance_info is null?
Suppose i_balance_info is ""?
Suppose there are fewer than 8 items in the input string, what will this line of code do?
memcpy(o_balance_sign,str[7],1);
Suppose that that the item in str[3] is less than 16 chars long, what will this line of code do?
memcpy(o_balance_change,str[3],16);
My approach to writing such code would be to protect against all such eventualities. At the very least I would add ASSERT() statements, I would usually write explicit input validation and return errors when it's bad. The problem here is that the interface does not seem to allow for any possibility that there might be bad input.
I had a hard time reading your code but FWIW I've added some comments, HTH:
// do shorter functions, long functions are harder to follow and make errors harder to spot
// document all your variables, at the very least your function parameters
// also what the function is suppose to do and what it expects as input
int CMI9_auxc_parse_balance_info
(
char *i_balance_info,
char *i_use_balance_ind,
char *o_balance,
char *o_balance_change,
char *o_balance_sign
)
{
char *balance_id[MAX_BUCKETS] = {NULL};
char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
char *str[160] = {NULL};
int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
int total_bukets=0; // good practice to initialize all variables
//
// check for null pointers in your arguments, and do sanity checks for any
// calculations
// also move variable declarations to just before they are needed
//
memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
//balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0'; // should be BALANCE_INFO_FIELD_MAX_LENTH-1
char *pch = strtok (balance_info,"*"); // this will potentially crash since no ending \0
while (pch != NULL && i < 160)
{
str[i]=(char*)malloc(strlen(pch) + 1);
strcpy(str[i],pch);
pch = strtok (NULL, "*");
i++;
}
total_bukets = i/8 ;
// you have declared char*str[160] check if enough b_id < 160
// asserts are helpful if nothing else assert( b_id < 160 );
for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
{
balance_id[j]=str[b_id];
b_id=b_id+8;
}
// don't use memcmp, if ('y'==i_use_balance_ind[0]) is better
if (!memcmp(i_use_balance_ind,"Y",1))
{
// atoi needs balance_id str to end with \0 has it?
if (atoi(balance_id[0])==1)
{
// length assumptions and memcpy when its only one byte
memcpy(o_balance,str[2],16);
memcpy(o_balance_change,str[3],16);
memcpy(o_balance_sign,str[7],1);
for(i=0;i<160;i++)
free(str[i]);
return 1;
}
else
{
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
}
// if ('N'==i_use_balance_ind[0])
else if (!memcmp(i_use_balance_ind,"N",1))
{
// here I get a headache, this looks just at first glance risky.
for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
{
b_ind=(j*8)+2;
bc_ind=(j*8)+3;
bs_ind=(j*8)+7;
if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
{
// length assumptions and memcpy when its only one byte
// here u assume strlen(str[b_ind])>15 including \0
memcpy(o_balance,str[b_ind],16);
// here u assume strlen(str[bc_ind])>15 including \0
memcpy(o_balance_change,str[bc_ind],16);
// here, besides length assumption you could use a simple assignment
// since its one byte
memcpy(o_balance_sign,str[bs_ind],1);
// a common practice is to set pointers that are freed to NULL.
// maybe not necessary here since u return
for(i=0;i<160;i++)
free(str[i]);
return 1;
}
}
// suggestion do one function that frees your pointers to avoid dupl
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
for(i=0;i<160;i++)
free(str[i]);
return 0;
}
A helpful technique when you want to access offsets in an array is to create a struct that maps the memory layout. Then you cast your pointer to a pointer of the struct and use the struct members to extract information instead of your various memcpy's
I would also suggest you reconsider your parameters to the function in general, if you place every of them in a struct you have better control and makes the function more readable e.g.
int foo( input* inbalance, output* outbalance )
(or whatever it is you are trying to do)