I have a stream of characters coming over the serial port like this;
FILE1,FILE2,FILE3,
I'm trying to read them in like this;
char* myFiles[20];
boolean done = false;
int fileNum = 0;
int charPos = 0;
char character;
while (!done)
{
if (Serial.available())
{
character = Serial.read();
if ((character == '\n') || (character == '\r'))
{
done = true;
}
else if (character == ',')
{
myFiles[fileNum][charPos] = '\0';
fileNum++;
charPos = 0;
}
else
{
myFiles[fileNum][charPos] = character;
charPos++;
}
}
}
when I try to print the first value like this;
Serial.println(myFiles[0]);
i get a continuous stream of characters.
What am i doing wrong?
What you are doing wrong is not allocating any memory for your strings.
Here's one way to do this
#include <vector>
#include <string>
std::vector<std::string> myFiles;
std::string file;
bool done = false;
char character;
while (!done)
{
if (Serial.available())
{
character = Serial.read();
if ((character == '\n') || (character == '\r'))
{
done = true;
}
else if (character == ',')
{
myfiles.push_back(file);
file = "";
}
else
{
file += character;
}
}
}
Serial.println(myFiles[0].c_str());
Since you are programming in C++ you should learn how to use std::vector and std::string, they will save you a lot of grief.
If std::vector and std::string are not available to you (apparently so on Arduino) then the quick hack would be to preallocate a fixed amount of memory for your strings by replacing
char* myFiles[20];
with
char myFiles[20][100];
Related
So my task is to fill out my function to work with a test driver that feeds it a random string during every run. For this function I have to convert the first character of every word to a capital and everything else must be lower.
It mostly works but the issue i'm having with my code is that it won't capitalize the very first character and if there is a period before the word like:
.word
The 'w' in this case would remain lower.
Here is my source:
void camelCase(char line[])
{
int index = 0;
bool lineStart = true;
for (index;line[index]!='\0';index++)
{
if (lineStart)
{
line[index] = toupper(line[index]);
lineStart = false;
}
if (line[index] == ' ')
{
if (ispunct(line[index]))
{
index++;
line[index] = toupper(line[index]);
}
else
{
index++;
line[index] = toupper(line[index]);
}
}else
line[index] = tolower(line[index]);
}
lineStart = false;
}
Here's a solution that should work and is a bit less complicated in my opinion:
#include <iostream>
#include <cctype>
void camelCase(char line[]) {
bool active = true;
for(int i = 0; line[i] != '\0'; i++) {
if(std::isalpha(line[i])) {
if(active) {
line[i] = std::toupper(line[i]);
active = false;
} else {
line[i] = std::tolower(line[i]);
}
} else if(line[i] == ' ') {
active = true;
}
}
}
int main() {
char arr[] = "hELLO, wORLD!"; // Hello, World!
camelCase(arr);
std::cout << arr << '\n';
}
The variable active tracks whether the next letter should be transformed to an uppercase letter. As soon as we have transformed a letter to uppercase form, active becomes false and the program starts to transform letters into lowercase form. If there's a space, active is set to true and the whole process starts again.
Solution using std::string
void toCamelCase(std::string & s)
{
char previous = ' ';
auto f = [&](char current){
char result = (std::isblank(previous) && std::isalpha(current)) ? std::toupper(current) : std::tolower(current);
previous = current;
return result;
};
std::transform(s.begin(),s.end(),s.begin(),f);
}
I have written a simple tokenizer that will split a command line into seperate lines each containing a single word. I am trying to ...
Make the program close if the first word of a command line is "quit"
Recognize instructions such as "Pickup", "Save", and "Go" in which the compiler will then look to the next token.
My idea has been to use a simple switch with cases to check for these commands, but I cannot figure out where to place it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char command[256];
int commandIndex;
char token[32];
int isWhiteSpace(char character) {
if (character == ' ') {
return 1;
}
else if(character == '\t') {
return 1;
}
else if(character < ' ') {
return 1;
}
else {
return 0;
}
} char* getToken() {
int index = 0; // Skip white spaces
while(commandIndex<256 && isWhiteSpace(command[commandIndex])) {
commandIndex ++;
} // If at end of line return empty token
if(commandIndex>=256) {
token[0] = 0;
return token;
} // Capture token
while(commandIndex<256 && !isWhiteSpace(command[commandIndex])) {
token[index] = command[commandIndex];
index++;
commandIndex ++;
}
token[index] = 0;
return token;
}
void main() {
printf("Zeta - Version 2.0\n");
while(1) {
printf("Command: ");
gets_s(command);
commandIndex = 0;
char* token = getToken();
while (strcmp(token,"") != 0) {
printf("%s\n", token);
token = getToken();
}
}
}
A little reorganization of the loop you have in main will do it.
int main() {
printf("Zeta - Version 2.0\n");
bool done = false;
while (!done) {
printf("Command: ");
gets_s(command);
commandIndex = 0;
char* token = getToken();
if (strcmp(token, "quit") == 0) {
done = true;
} else if (strcmp(token, "pickup") == 0) {
doPickup();
} else if (strcmp(token, "save") == 0) {
char * filename = getToken();
doSave(filename);
} ...
}
return 0;
}
You can't use a switch statement with strings, so you just use a bunch of if ... else if ... statements to check for each command. There are other approaches, but this one required the fewest changes from the code you already have.
In the example, under the handling for "save" I showed how you can just call getToken again to get the next token on the same command line.
(Note that I also fixed the return value for main. Some compilers will let you use void, but that's not standard so it's best if you don't do that.)
I'm having a little bit of trouble with this bit of code here for my Arduino.
Basically, I'm trying to send in a series of characters, turn it into an character array, and use that to run the rest of the program. I'm close because I know everything is working perfectly internally, but when I boot from the serial port, the message isn't getting in.
I assume that at this point it probably is how I am constructing the array... or some oddity. It is probably just a simple error in how I put the code together, but I'm completely struck. (I was previously using a string, but because of how the Arduino works with them, it pretty much makes using them for memory purposes impossible.)
I'm using a Java program (Ardulink) to send the information into the program with a customized version I've edited. So simply put, the input has to be a series of characters, and I need it stored in an array.
void serialEvent()
{
int arrayPostion = 0;
int i;
int maxArraySize = 20;
char CharArrayInLocal[20];
while (Serial.available() && !stringComplete)
{
char inChar = (char)Serial.read();
CharArrayInLocal[arrayPostion] = inChar;
arrayPostion++;
if (inChar == '\n')
{
stringComplete = true;
}
}
for (int i = 0; i<=19; i++)
{
CharArrayIn[i] = CharArrayInLocal[i];
}
}
This worked for me,
String CharArrayInLocal[20];
String inputString = "";
boolean stringComplete = false;
int i = 0;
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
if (inChar == '\n') {
CharArrayInLocal[i] = inputString;
i++;
stringComplete = true;
inputString = "";
}
else {
inputString += inChar;
}
}
}
All I want to do is pass in a char* buffer and compare that to a literal string "#" -- why is this so difficult for me.
char* buffer = "#3702";
string b(buffer);
string c("#");
if (strncmp(b.c_str(), c.c_str(), 1) == 0)
{
perror("Buffer malformated!");
return false;
}
What do I not understand about this?
Edit: haaaa, != not == whoops :)
If you just want to compare char*and use strncmp(), you don't need to use stl string for this.
int main()
{
char* buffer = "#3702";
char* c = "#";
if (strncmp(buffer, c, strlen(c)) == 0)
{
//same string
return true;
}
else
{
//not same string
return false;
}
getchar();
}
And, remember char[] can convert to char*, so in this case, above code is similar to below code.
int main()
{
char buffer[] = "#3702";
char c[] = "#";
if(buffer[0] == c[0])
{
//same string
return true;
}
else
{
//not same string
return false;
}
getchar();
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string>
#include <iostream>
FILE *pfile;
using namespace std;
string temp_string;
string reserved[25] = {"AND", "CALL", "DECLARE", "DO", "ELSE", "ENDDECLARE", "ENDFUNCTION", "ENDIF", "ENDPROCEDURE", "ENDPROGRAM", "EXIT", "FALSE", "FOR", "FUNCTION", "IF", "IN", "INOUT", "NOT","OR", "PROCEDURE", "PROGRAM", "RETURN", "THEN", "TRUE", "WHILE"};
int main(void)
{
pfile = fopen("hello.cel", "r");
char cha, temp_token[30], temp;
int count = 0, check = 1, i;
cha = fgetc(pfile);
while (cha != EOF)
{
if(isalpha(cha) || cha == '_')
{
temp_token[0] = cha;
count = 1;
cha = fgetc(pfile);
while(isdigit(cha) || isalpha(cha) || cha == '_')
{
if(count < 30)
{
temp_token[count] = cha;
count++;
}
cha = fgetc(pfile);
}
count--;
for(i = 0; i <= count; i++)
{
temp_string += temp_token[i];
}
cout << temp_string;
for(i = 0; i < 25; i++)
{
if(temp_string == reserved[i])
{
printf(": RESERVED\n");
}
else
{
printf(": ALPHA\n");
}
}
cha = ungetc(cha, pfile);
count = 0;
}
fclose(pfile);
}
I have a problem with the comparison statement between the reserved[i] and temp_string strings. I cannot succeed printing "RESERVED", it always print "ALPHA".
To your knowledge, this is a program that gets each character from a file (hello.cel) and prints the type of each token.
EDIT: temp_token is a string were I temporary store words. This words have been made by adding characters at this line temp_string += temp_token[i];
temp_string is not declared.
Have you declared temp_string as string?
For me it prints Reserved for keywords.
The end of the loop gets a bit sketchy; you've got a missing }, and ungetc() sounds like completely the wrong thing to do. You need to change
cha = ungetc(cha, pfile);
count = 0;
}
fclose(pfile);
}
to
}
cha = fgetc(pfile);
}
fclose(pfile);
}
Also declare temp_string just before the loop that populates it (or, if you really want it to be global for some reason, call clear() at that point). Better still, initialise it from the buffer, after removing the pointless count--:
std::string temp_string(temp_token, temp_token+count);
or even better still, get rid of the temporary buffer, and build the string as you read characters:
std::string token(1, cha);
cha = fgetc(pfile);
while(isdigit(cha) || isalpha(cha) || cha == '_')
{
if(token.size() < 30)
{
token.push_back(cha);
}
cha = fgetc(pfile);
}
And finally, only print ALPHA after checking all the reserved tokens:
bool is_reserved = false;
for(i = 0; i < 25; i++)
{
if(token == reserved[i])
{
is_reserved = true;
break;
}
}
printf(": %s\n", is_reserved ? "RESERVED" : "ALPHA");
Here is a less broken version.