this is my code and I have a problem with array.
int main(void)
{
PORTD = 0x01;
LCDOUT();
char count = 0;
char firstLine[] = "Number of count";
char secondLine[] = {count};
while (1)
{
Command(HOME);
LCD_String(firstLine);
Command(LINE2);
LCD_String(secondLine);
if ((PIND&0x01)==0x00)
{
count++;
_delay_ms(500);
}
}
}
I want to make
char secondLine[] = "0"; when the code starts.
And if ((PIND&0x01) == 0x00)), then
secondLine[] = "1"
secondLine[] = "2"
secondLine[] = "3"
...
...
So in the secondLine, the number of counts can be shown through LCD.
The function snprintf() is supporting your goal.
https://en.cppreference.com/w/c/io/fprintf
It allows to create string representation of parameters.
Make sure that there is enough space in char secondLine[2]; and that you use the length parameter ( size_t bufsz ) to not write beyond.
You will have to do the printing inside your loop, so that the string content is updated along with count++.
Related
Problem
I have a function which assigns data from reading a Bluetooth connection to a char array QualArray[4][30], although it appears that the length of each char array is 1 char greater than the number of characters that visually appear in the array, suggesting a hidden character?
Furthermore, I add these strings to another string called 'resource' using strcpy(), and the length of the string resource is 5 chars more than what it should be (so the 4 additional hidden characters from QualArray makes sense but there is apparently another hidden char added??) I have printed a "_" at the start and end of the string to see if there are any empty chars at either side but there aren't.
Somehow there are hidden chars in my strings but I don't know why, any help would greatly be appreciated!
Code
char resource[160] = "/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec?"; //must be pre-defined buffer
char staticresource[160] = "/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec?Cooker=RiceCooker&Meal=Rice&Portion=3&Method=Boil";
char QualArray[5][30]; // [Qparam][charnum]
char CookerQuery[20] = "&Cooker=";
char MealQuery[15] = "&Meal=";
char PortionQuery[15] = "&Portion=";
char MethodQuery[15] = "&Method=";
void CollectQualitativeData() {
int Qparam=0;
int charnum = 0;
while(Qparam < 4) { // While Qualitative data has not been collectedQualDataCollected = 0
if (SerialBT.available()) {
char incomingChar = SerialBT.read();
if (QualArray[Qparam] !="" && incomingChar == '\n') { // If the message isnt empty and the recieved char is nothing (ie if at end of word) if (message !=""
Serial.print(QualArray[Qparam]);
Serial.print("_");
Serial.print(" length = ");
Serial.println(strlen(QualArray[Qparam]));
Qparam++;
charnum = 0;
}
if (incomingChar != '\n'){ // If the incomingChar is different than \n, concatenate that char character to QualArray.
if (charnum <30) { // if greater than maximum specified array val then ignore
QualArray[Qparam][charnum] = incomingChar;
charnum++;
}
} else {
}
}
delay(20);
}
}
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32test"); //Bluetooth device name
//Serial.println("The device started, now you can pair it with bluetooth!");
CollectQualitativeData();
Serial.println("Complete");
Serial.println(QualArray[0]);
Serial.println(QualArray[1]);
Serial.println(QualArray[2]);
Serial.println(QualArray[3]);
Serial.println(QualArray[4]);
strcat(resource,CookerQuery); // resource + Resource_variables
strcat(resource,QualArray[0]);
strcat(resource,MealQuery); // resource + Resource_variables
strcat(resource,QualArray[1]);
strcat(resource,PortionQuery); // resource + Resource_variables
strcat(resource,QualArray[2]);
strcat(resource,MethodQuery); // resource + Resource_variables
strcat(resource,QualArray[3]);
Serial.print("resource=_");
Serial.print(resource);
Serial.println("_");
Serial.print("staticresource=_");
Serial.print(staticresource);
Serial.println("_");
Serial.print("length static=");
Serial.println(strlen(staticresource));
Serial.print("length resource=");
Serial.println(strlen(resource));
}
https://github.com/Conwon99/4th-Year-Project/blob/main/StringLengthIssue
Serial Monitor Debugging
RiceCooker_ length = 11
Rice_ length = 5
3_ length = 2
Boil_ length = 5
Complete
RiceCooker
Rice
3
Boil
resource=_/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec&Cooker=RiceCooker&Meal=Ric&Portion=3&Method=Boil_
staticresource=_/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec?Cooker=RiceCooker&Meal=Rice&Portion=3&Method=Boil_
length static=125
length resource=130
char[] has null-terminator value \0 and it is counted as the length of the array. Just use std::vector and String. Anyway, your code is uncompilable. I'll rewrite for you:
#include <BluetoothSerial.h>
#include <vector>
const char resource[] PROGMEM = "/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec?"; //must be pre-defined buffer
const char staticresource[] PROGMEM = "/macros/s/AKfycbzTAkuhTqJfi-EofdpOjBxKNlDe18fdTkOPHMOuOwvl9zbDqfPHwbb1/exec?Cooker=RiceCooker&Meal=Rice&Portion=3&Method=Boil";
const char cookerQuery[] PROGMEM = "&Cooker=";
const char mealQuery[] PROGMEM = "&Meal=";
const char portionQuery[] PROGMEM = "&Portion=";
const char methodQuery[] PROGMEM = "&Method=";
std::vector<String> qualArray;
BluetoothSerial SerialBT;
void CollectQualitativeData() {
while (qualArray.size() < 4 ) {
if (SerialBT.available()) {
String incomingChar = SerialBT.readStringUntil('\n');
qualArray.push_back(incomingChar);
}
delay(20);
}
}
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP32test");
CollectQualitativeData();
Serial.println("Complete");
for (int i = 0; i < qualArray.size(); i++) {
Serial.println(qualArray[i]);
}
String res(resource);
res += cookerQuery + qualArray[0];
res += mealQuery + qualArray[1];
res += portionQuery + qualArray[2];
res += methodQuery + qualArray[3];
Serial.println(res);
}
void loop() {}
Some very strange things happen in my source code.
The following function works well and it prints 'y' when the password is correct and prints 'n' when it is incorrect. But if i add some UART1_Write and Delay functions to the else statement the bug comes out and even if the password is "zxc" (correct) it ALWAYS enters the else statement.
I'm using MikroC PRO for PIC v6.0.0, the robot system is made of PIC18F452 and RN-42 bluetooth module connected to it. I am testing with a laptop with a bluetooth and TeraTerm.
For more info: http://instagram.com/p/pLnU9eDL8z/#
Here it is the well working routine:
void authenticate() {
char *input = "";
char *password = "zxc\0";
unsigned char ready = 0;
while (connected && !ready) {
if (UART1_Data_Ready()) {
UART1_Read_Text(input, "|", 17);
strcat(input, "\0");
if (strcmp(input, password) == 0) {
UART1_Write('y');
ready = 1;
} else {
UART1_Write('n');
ready = 1;
}
}
}
}
This version of the routine ALWAYS goes in the ELSE statement of the strcmp(input, password) == 0 part:
void authenticate() {
char *input = "";
char *password = "zxc\0";
unsigned char ready = 0;
while (connected && !ready) {
if (UART1_Data_Ready()) {
UART1_Read_Text(input, "|", 17);
strcat(input, "\0");
if (strcmp(input, password) == 0) {
UART1_Write('y');
ready = 1;
} else {
UART1_Write('n');
Delay_ms(100);
UART1_Write('$');
Delay_ms(100);
UART1_Write('$');
Delay_ms(100);
UART1_Write('$');
Delay_ms(100);
UART1_Write('K');
Delay_ms(100);
UART1_Write(',');
Delay_ms(100);
UART1_Write('-');
Delay_ms(100);
UART1_Write('-');
Delay_ms(100);
UART1_Write('-');
Delay_ms(100);
UART1_Write('\n');
ready = 1;
}
}
}
}
It is important to send all these addition symbols in order to get RN-42 into command mode and disconnect the user if the password is wrong.
Please help me solve the problem. Any ideas appreciated!
As others have pointed out in the comments section a major issue with your code is that you are trying to store the UART data to memory that does not belong to you.
When you declare char *input = "";, you haven't actually allocated any space except for a single byte that stores '\0'. Then, when you use UART1_Read_Text(), you tell that function you may have up to 17 characters that will be read before finding the delimiter - all of which should be stored at the location pointed to by input.
The description of that library function can be found here. Also, based on the library description it looks like UART1_Read_Text() already adds the null-termination to the UART data. I base this assumption off the description of UARTx_Write_Text and the example that they provide on their website. However, I would recommend that you verify that is indeed the case.
Also, your initialization of password is redundant and char *password = "zxc\0" should be changed to char *password = "zxc". When you declare a string literal using double quotation marks it is automatically null-terminated. This excerpt is from "C in a Nutshell":
A string literal consists of a sequence of characters (and/or escape sequences) enclosed in double quotation marks... A string literal is a static array of char that contains character codes followed by a string terminator, the null character \0... The empty string "" occupies exactly one byte in memory, which holds the terminating null character.
Based on the above, I would go about it a little more like this:
#define MAX_NUM_UART_RX_CHARACTERS 17
void authenticate()
{
char input[MAX_NUM_UART_RX_CHARACTERS + 1];
char *password = "zxc";
unsigned char ready = 0;
while (connected && !ready)
{
if (UART1_Data_Ready())
{
UART1_Read_Text(input, "|", MAX_NUM_UART_RX_CHARACTERS);
if (strcmp(input, password) == 0)
{
UART1_Write('y');
ready = 1;
}
else
{
UART1_Write('n');
ready = 1;
}
}
}
}
I register functions at a global registry. A function can have multiple arguments. I can register and call them from the registry.
Here is one of my unit tests to understand the registry.
void *a_test_function_d(int a, char *b){
printf("*** c_test called\n");
isRunD = a;
testChar = b;
return NULL;
}
TEST(testWithMultibleArguments) {
isRunD = 0;
testChar = "";
add_command(a_test_function_d);
assertEquals(1, avl_tree_count(command_registry));
exec_command("a_test_function_d", 42, "test");
assertEquals(42, isRunD);
assertEquals("test", testChar);
avl_tree_free(command_registry);
command_registry = NULL;
}
This works fine for me so far. But here comes the part I can’t find a nice solution for. From a line-parser i get tokens. The first one should be the command, the following tokens are the arguments. If i would have a fixed length of arguments, than i doesn’t have any problems, but how can I construct a function or a macro that handles a variable count of tokens to pass them as arguments to a function?
This is what i have so far:
// split lines into tokens
char *token;
token = strtok(linebuffer," ");
if (token) {
if ( has_cammand(token) ) {
// HOW TO PUT ARGS from strtok(linebuffer," ") to FUNCTION....
exec_command(token /* , a1, a2, a3 */ );
} else {
uart_puts("Command not found.\n");
}
}
My line buffer is a char* and can look like:
find honigkuchen
set name peter
(coming from a user input interactive shell).
the prototypes of the functions would be:
void *find(char *);
void *set(char *, char *);
Of cause I can define a macro and count _VA_ARGS_, or the array and do a if-else on 1, 2, 3, 4, … Parameters, but this seems a bit messy to me.
There must be a better way to convert a array, to a parameter list.
Pass the array and the number of items in the array as arguments to the function under test. Is there some reason to complicate this further?
Keep in mind that an array passed to a function is really a pointer to the first item in the array.
So, if you have:
// Prototype for test function:
bool testFunction( char *items, int itemCount );
char items[10];
int itemCount = 0;
// Get items from where ever
items[0] = 'a';
items[1] = 'r';
items[2] = 'r';
items[3] = 'a';
items[4] = 'y';
itemCount = 5;
// Assume testFunction returns true if the test succeeds, else false
if( testFunction( items /*or &items[0] to make it more clear*/, itemCount ) )
puts( "Success!" );
else
puts( "Failure :(" );
Ask away if anything is unclear...
I am programming on some device and I encountered
rather strange situation.
The same variable - for the first time has correct value,
but the SAME variable on a different place in code,
has a DIFFERENT value.
What can be causing this? I am pretty sure I didn't modify
the variable in between, I am also pretty sure I didn't
modify the variable using some pointers accidentally.
What can be causing this? I am really confused?
Can it be related that I for example used whole available stack
space of some function - and because of this compiler automatically
0-ifies my variable(or something similar)?
I have some long code inside a single function f.
Here's whole details on usage of pointsEntered variable in my code (how it is used).
/* Let the user input points */
s32 pointsEntered = 0;
int pointsCounter = 0;
while(1)
{
if(pointsCounter == 3)
return; // User entered wrong points 3 times, exit function
bool retStatus = false;
retStatus = inputPoints(&pointsEntered);
if(false == retStatus) // If user didn't enter amount, exit this function
return;
if(pointsEntered>atoi(userAmount)){
PromptBox(false, 0, "Points should not be more\n than current points");
pointsCounter++;
continue;
}
break;
}
// PROBLEM: pointsEntered - is OK here but as it will be shown below, it gets modified down the way
// even though I don't change it directly
char intTest1[50];
sprintf(intTest1, "1pentered %d", pointsEntered); // Here the value is OK! It shows value that I entered, e.g., 220
PromptBox(false, 0, intTest1);
/* Let the user enter 4 digit pin code */
u8 pinEntered[5] = {0};
bool retStatus1 = false;
retStatus1 = inputPin(pinEntered);
pinEntered[5]='\0';
if(false == retStatus1) // If user didn't enter amount, exit this function
return;
char intTest2[50];
sprintf(intTest2, "2pentered %d", pointsEntered); // Here pointsEnetered is OK
PromptBox(false, 0, intTest2);
/* Compute hash of pin code*/
s32 siRet1 = 0;
u8 pinVerify[25]={0};
u8 hashResult[16] = {0};
memcpy(pinVerify,pinEntered,4);
memcpy(&pinVerify[4],"XXXX",21);
siRet1 = sdkMD5(hashResult,pinVerify,25);
char intTest3[50];
sprintf(intTest3, "3pentered %d", pointsEntered); // Here pointsEntered has changed!!!
PromptBox(false, 0, intTest3);
/* convert string hash code to byte array */
unsigned char val[16] = {0};
unsigned char * pos = pinHash;
size_t count = 0;
// WARNING: no sanitization or error-checking whatsoever
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
{
sscanf(pos, "%2hhx", &val[count]);
pos += 2 * sizeof(char);
}
char intTest4[50];
sprintf(intTest4, "4pentered %d", pointsEntered);
PromptBox(false, 0, intTest4);
/* Does the pin hash match ? */
if (siRet == SDK_OK && (!memcmp(hashResult,val,16)))
{
MsgBox("PIN OK","",0,SDK_KEY_MASK_ESC | SDK_KEY_MASK_ENTER);
}
else
{
MsgBox("PIN doesn't match-exiting","",0,SDK_KEY_MASK_ESC | SDK_KEY_MASK_ENTER);
return;
}
char intTest[50];
sprintf(intTest, "pentered %d", pointsEntered);
PromptBox(false, 0, intTest);
These two lines may cause it (as it's undefined behavior):
u8 pinEntered[5] = {0};
...
pinEntered[5]='\0';
Here you declare an array of five entries, but then you assign to a sixth item. This will most likely overwrite any previous variable on the stack.
#include<stdio.h>
char *removedps(char *x)
{
int Ar[256] = {0};
int ip=0;
int op=0;
char temp;
while(*(x+ip))
{
temp = (*(x+ip));
if (!Ar[temp]) {
Ar[temp] = 1;
*(x+ip) = *(x+op);
op++;
}
ip++;
*(x+op) = '\0';
}
return x;
}
int main()
{
char lo[] = "0001";
printf("%s",removedps(lo));
}
My code is not working
I have tried hard to see the error
All I GET IS the first character .
My idea is simple
make an array of 256 places
insert Zero into them
Then insert 1 for each character inside the string (on that position of the array)
your assignment looks to be the error here.
op is "out postiion", ip is "in position"
so it should be
*(x+op) = *(x+ip);
not the other way.
because *(x+op) = '\0';
is always run every iteration of the loop.
I'd probablly do it more like this ( using your method, which I probablly wouldn't use personally)
char *removedps(char *x)
{
int Ar[256] = {0};
char* start = x;
while(*x)
{
if (Ar[*x])
{ // remove the repeated character
memmove(x, x+1, strlen(x));
}
else
{
Ar[*x] = 1;
x++;
}
}
return start;
}
also, I'd name it remove_duplicate_chars or something, not a fan of cryptic abbreviations.
At the end of the loop, you do *(x+op)='\0';, and then, in the next iteration, you do *(x+ip)=*(x+op);, so from the 2sd iteration, you put there 0.
try do something like:
for (op=ip=0;x[ip];ip++) {
if (!Ar[x[ip]]++) x[op++]=x[ip];
}
x[op]=0;