Parsing nmea csv in c++/c for microchip - c

How can I parse a comma separated char string? I've tried using strtok but I can't get it working.
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char *input[8];
int i = 0;
for( i=0;i<8;i++)
{
input[i] = p;
p = strtok(NULL, ",");
}
Ideally I'd like to be able to set a variable to the string. Such as
if (i == 0){
string type = $GNRMC;
}
if (i == 1){
float thisnum = 011802.00
}
etc.
This is being written for a pic so I can't use vectors.

You're upper snippet is working for me, besides two minor issues:
buf should be str2
your array of char pointers is too small to hold all substrings
For the second one, you need to convert your substring to the correct type first.
__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
#define NUM_SUBSTRINGS 13
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char * input[NUM_SUBSTRINGS];
int i = 0;
for(i=0; i<NUM_SUBSTRINGS; i++)
{
char *type = NULL;
float thisnum = 0.0;
if (i == 0){
type = p;
}
if (i == 1){
thisnum = strtof(p, NULL);
}
if(p != NULL)
printf("String %s, type: %s, num: %f\n", p, type, thisnum);
input[i] = p;
p = strtok(NULL, ",");
}
return 0;
}

Related

Strtok() problems when I call a function within the loop

The program prints all the outputs from the file I expect it to if I comment out the second line however if I re-add it the tokens reach null earlier and only 2 words from the file are printed any problems I'm missing?
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
The rest of the code is below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
char *filterer(char* redwords, char* word);
char *lowercase(char *word);
FILE *redptr;
FILE *textptr;
FILE *resultptr;
char *redwords = malloc(20);
char *text = malloc(255);
char *texttoken;
char *temp;
redptr = fopen("redfile.txt", "r");
textptr = fopen("textfile.txt", "r");
resultptr = fopen("result.txt", "w");
fgets(redwords,20,redptr);
redwords = lowercase(redwords);
fgets(text,255,textptr);
texttoken = strtok(text, " ");
while(texttoken != NULL){
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
texttoken = strtok(NULL, " ");
}
}
char *filterer(char *redwords, char *word){
int match = 0;
char *token;
token = strtok(redwords, ",");
while(token != NULL) {
if(strcmp(word,token)==0){
match = 1;
}
token = strtok(NULL, ",");
}
if(match == 1){
int i;
int len = strlen(word);
char modified[len+1];
modified[len] = NULL;
for(i=0; i<len; i++){
modified[i] = '*';
}
return modified;
}
return word;
}
char *lowercase(char *word){
int i;
for(i=0; i<=strlen(word); i++){
if(word[i]>=65&&word[i]<=90)
word[i]=word[i]+32;
}
return word;
}
At least these problems:
Return of invalid pointer
return modified; returns a pointer to a local array. Local arrays become invalid when the function closes.
char modified[len+1];
modified[len] = NULL;
for(i=0; i<len; i++){
modified[i] = '*';
}
return modified; // Bad
Save time: Enable all warnings
Example: warning: function returns address of local variable [-Wreturn-local-addr]
Nested use of strtok()
Both this loop and filterer() call strtok(). That nested use is no good. Only one strtok() should be active at a time.
while(texttoken != NULL){
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
texttoken = strtok(NULL, " ");
}
Since filterer() is only looking for a ',', look to strchr() as a replacement.

Store splitted string in array

I using strtok() to split a string and store in an array like following below
char *table[5];
char buffer[50] = {"1-Study"}; // The value is example, get new value by user
char *number;
char *name;
uint8_t tableNumber;
number = strtok(buffer, "-"); //equals "1"
name = strtok(NULL, "-"); //equals "Study"
tableNumber = atoi(number); //convert char to int
table[tableNumber] = name;
for (c = 0; c < 5; c++)
{
printf("table %d = %s\n", c, table[c]);
}
after get input for 5 times the result should be:
table 0 = Study
table 1 = Sleep
table 2 = Party
table 3 = Hello
table 4 = Exit
But the resualt is:
table 0 = Exit
table 1 = Exit
table 2 = Exit
table 3 = Exit
table 4 = Exit
whats the problem?
please help me?
Thanks
complete code:
char gMessageBuffer[40];
char *gSceneTable[13];
boolean emberAfPreMessageReceivedCallback(EmberAfIncomingMessage* incomingMessage)
{
if (incomingMessage->apsFrame->profileId == HA_PROFILE_ID)
{
if (incomingMessage->apsFrame->clusterId == ZCL_SCENES_CLUSTER_ID)
{
MEMCOPY(gMessageBuffer, incomingMessage->message, incomingMessage->msgLen); // Get incoming message
gMessageBuffer[incomingMessage->msgLen] = '\0';
emberEventControlSetDelayMS(getScenePayloadEventControl, SCENE_ACTION_TRESH);
return true;
}
}
return false;
}
void getScenePayloadEventFunction(void)
{
char *sceneNumber;
char *sceneName;
char *sceneID;
char *sceneAction;
uint8_t sceneTableNumber;
emberAfCorePrintln("///Incoming Message: %s///", gMessageBuffer);
sceneNumber = strtok(gMessageBuffer, ".");
sceneName = strtok(NULL, ".");
sceneID = strtok(NULL, ".");
sceneAction = strtok(NULL, ".");
emberAfCorePrintln("///SCENE NUMBER: %s///", sceneNumber);
emberAfCorePrintln("///SCENE NAME: %s///", sceneName);
emberAfCorePrintln("///SCENE ID: %s///", sceneID);
emberAfCorePrintln("///SCENE ACTION: %s///", sceneAction);
if (strcmp(sceneAction, "Update") == 0)
{
sceneTableNumber = atoi(sceneNumber);
gSceneTable[sceneTableNumber] = strdup(sceneName);
}
emberEventControlSetInactive(getScenePayloadEventControl);
}
this is for microcontroller in simplicity studio IDE.
I get payload in emberAfPreMessageReceivedCallback correctly
and I split it into 4 parts and print correctly too.
But after copy the sceneName to gSceneTable array I see the last sceneName in all the elements of gSceneTable with gSceneTable[sceneTableNumber] = sceneName and I see "p]" with gSceneTable[sceneTableNumber] = strdup(sceneName);
It is highly unlikely that your program produce the posted output. The code fragment only handles a single string and char *table[5]; is uninitialized, so printing the strings from table[0], table[2], table[3] and table[4] has undefined behavior. You specified that the strings are read from a file, posting a complete program is required for a precise and correct analysis. Not initializing the array is a problem in case the file does not have all entries covered, it would be impossible to tell which were set and which weren't.
Assuming your program reads the strings from a file or standard input, parsing them with strtok returns pointers to the source string, which is the array into which you read the lines from the file. Hence all entries in the table[] array point to the same byte in this array, which explains the output you get: 5 times the contents of the last line.
You should make a copy of the string you store in the table:
table[tableNumber] = strdup(name);
Here is a completed and modified program:
#include <stdio.h>
#include <string.h>
int main() {
char *table[5] = { NULL, NULL, NULL, NULL, NULL };
char buffer[50];
char *number;
char *name;
int tableNumber;
for (int i = 0; i < 5; i++) {
if (!fgets(buffer, sizeof buffer, stdin))
break;
number = strtok(buffer, "-");
if (number == NULL) {
printf("empty line\n");
continue;
}
name = strtok(NULL, "-\n");
if (name == NULL) {
printf("no name after -\n");
continue;
}
tableNumber = atoi(number);
if (tableNumber < 0 || tableNumber >= 5) {
printf("invalid number: %d\n", tableNumber);
continue;
}
table[tableNumber] = strdup(name);
}
for (int i = 0; i < 5; i++) {
if (table[i])
printf("table %d = %s\n", i, table[i]);
}
for (int i = 0; i < 5; i++) {
free(table[i]);
}
return 0;
}
If your target system does not support strdup(), use this:
#include <stdlib.h>
#include <string.h>
char *mystrdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
return (p != NULL) ? memcpy(p, s, size) : NULL;
}
The sample code:
Enter message like "sceneNumber.sceneName.sceneID.Update"
For example: 1.Study.12345.Update
#include <stdio.h>
#include <string.h>
#include <conio.h>
char *gSceneTable[13];
char gMessageBuffer[50];
int main()
{
char *sceneNumber;
char *sceneName;
char *sceneID;
char *sceneAction;
int sceneTableNumber;
int check;
int c;
printf("Enter payload for 3 Times\r\n");
while(check != 3)
{
scanf("%s", &gMessageBuffer);
printf("Message is: %s\r\n",gMessageBuffer);
sceneNumber = strtok(gMessageBuffer, ".");
sceneName = strtok(NULL, ".");
sceneID = strtok(NULL, ".");
sceneAction = strtok(NULL, ".");
printf("%s\r\n", sceneNumber);
printf("%s\r\n", sceneName);
printf("%s\r\n", sceneID);
printf("%s\r\n", sceneAction);
if (strcmp(sceneAction, "Update") == 0)
{
sceneTableNumber = atoi(sceneNumber);
gSceneTable[sceneTableNumber] = sceneName;
}
check++;
}
for (c = 0; c < 4; c++)
{
printf("Scene Table: %d ----- %s \r\n", c, gSceneTable[c]);
}
return 0;
}

How to shift letters to the right or left?

I am given a file with a string, for example "The United States was founded in *1776*". What I cannot figure out is how to shift letters one space to the left or right and have the letters wrap around. I am able to shift the letters from an a to b but not change its location within the word.
Example of this output would be:
"heT
nitedU
tatesS
asw
oundedf
ni
1776**"
In C, strings are stored as an array of chars in memory. Unlike C++ vectors, you can not insert or remove element within the array, you can only access their value or change their value.
If you declare a C string as follows:
char *myStr = "Fred";
It will be stored in memory as a five character array with the 5th character being the zero value which terminates a C string:
myStr[0] = 'F'
myStr[1] = 'r'
myStr[2] = 'e'
myStr[3] = 'd'
myStr[4] = 0
You need to design a for loop that copies each array element to the one before, while remembering that you need to save the one you are about to overwrite. In this example, it should result in the following copy operations being performed:
len = strlen(myStr);
saveCh = myStr[0];
myStr[0] = myStr[1];
myStr[1] = myStr[2];
myStr[2] = myStr[3];
myStr[3] = saveCh;
So now your job is to create a for loop that does that for any C string of any length.
So to rotate the chars within a C string to the left, you need to copy each char in the array at index i to previous array element i-1. The tricky part is to handle the wrap around properly when i=0 (in this example, you want to copy myStr[0] to myStr[3]. Now do that with a for loop.
You need to also understand that the last character of any C string is the null character (value zero), which terminates a C string. If you modify that element in the array, then your string will break. That is why saveCh is copied to myStr[3] and not to myStr[4].
void rotateStrLeftOneChar(char *myStr) {
// Always check for error and special cases first!
// If myStr is a NULL pointer, do nothing and exit
// If myStr is less than 2 chars, nothing needs to be done too.
if ((myStr != NULL) && (strlen(myStr)>1)) {
int len = strlen(myStr);
char saveCh = myStr[0];
int i = 0;
// Copy each char at index i+1 left to index i in the array
for(i=0; i<len-2; i++)
myStr[i] = myStr[i+1];
// The last character is special and is set to saveCh
myStr[len-1] = saveCh;
}
}
If you just need to output the letters to shift to the left and don't want to change original input then you can do:
#include <stdio.h>
#include <string.h>
void shiftletters(char * input, int i);
int main () {
char input[256];
int shift;
printf("Enter input : ");
scanf("%[^\n]s", input);
printf("Number of shifts : ");
scanf("%d", &shift);
shiftletters(input, shift);
return 0;
}
void shiftletters(char * input, int numshifts)
{
char str[256] = {'\0'};
char * delim = " \t";
char * pch = NULL;
int j, k, len, shifts;
if (input == NULL)
{
printf ("Invalid input\n");
return;
}
strcpy (str, input);
pch = strtok (str, delim);
while (pch != NULL)
{
len = strlen (pch);
if ((numshifts == len) || (len == 1))
{
printf ("%s\n", pch);
pch = strtok (NULL, delim);
continue;
}
if (len < numshifts)
shifts = numshifts % len;
else
shifts = numshifts;
for(j=shifts; j<len; j++)
printf("%c", pch[j]);
for(k=0; k<shifts; k++)
printf("%c", pch[k]);
printf("\n");
pch = strtok (NULL, delim);
}
}
The output of the program:
Enter input : The United States was founded in *1776*
Number of shifts : 1
heT
nitedU
tatesS
asw
oundedf
ni
1776**
like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate(char word[], int dir){
size_t len = strlen(word);
char *temp = malloc(len + 1);
if(!temp){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(temp, word);
for(char *src = temp; *src; ++src, ++dir){//or use memmove
word[(dir+len)%len] = *src;
}
free(temp);
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate(word, dir);
}
printf("%s\n", word);
}
fclose(fp);
}
using memmove version
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate1(char word[], int dir){
size_t len = strlen(word);
if(len > 2){
char temp;
if(dir == L){
temp = word[0];
memmove(word, word+1, len-1);
word[len-1] = temp;
} else if(dir == R){
temp = word[len-1];
memmove(word+1, word, len-1);
word[0] = temp;
}
}
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate1(word, dir);
}
printf("%s\n", word);
}
}

String Split in C

I want to split a String in C.
My String is defined by my Struct:
struct String
{
char *c;
int length;
int maxLength;
}
Then I have a function that does the splitting. Perhaps C has something that does this, but although I wanted my own, I have not found anything that will do it so far.
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
// set of splitters: {'\n', ' '}
}
Input looks something like this: This is Sparta.
Then I want to return a pointer to each character array.
*p1 = This
*p2 = is
*p3 = Sparta.
If that makes any sense, I want an array of pointers, and each pointer points to a character array.
I will have to realloc the String as I increment the size of each character array. Probably my biggest problem is imagining how the pointers work.
Similar problem: c splitting a char* into an char**
So, how do I go about doing this?
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string test = "aa aa bbc cccd";
vector<string> strvec;
string strtemp;
string::size_type pos1, pos2;
pos2 = test.find(' ');
pos1 = 0;
while (string::npos != pos2)
{
strvec.push_back(test.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = test.find(' ', pos1);
}
strvec.push_back(test.substr(pos1));
vector<string>::iterator iter1 = strvec.begin(), iter2 = strvec.end();
while (iter1 != iter2)
{
cout << *iter1 << endl;
++iter1;
}
return 0;
}
Have you looked at strtok? It should be possible to do this using strtok.
here is a exemple :
String ** spliter(String *s)
{
int i;
int j;
char *p1;
char *p2;
char *p3;
i = 0;
j = 0;
if(s == NULL)
return NULL;
p1 = malloc(sizeof(*p1) * strlen(s));
p2 = malloc(sizeof(*p2) * strlen(s));
p3 = malloc(sizeof(*p3) * strlen(s));
while (s[i] != ' ')
{
p1[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != ' ')
{
p2[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != '\0')
{
p3[j++] = s[i];
i++;
}
printf("%s\n", p1);
printf("%s\n", p2);
printf("%s\n", p3);
}
You're looking for strtok, check out man 3 strtok, or here if you're not on *nix.
You would use it like this: (Assuming that you can write the add_string code yourself.)
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
String **return_strings = NULL;
char *delim = " \n";
char *string = strtok(s, delim);
int i = 0;
for(i = 0; add_string(return_strings, string, i) != -1; i++) {
string = strtok(NULL, delim);
}
return strings;
}
Note that if you need to save the original string (strtok modifies the string it works on), you'll need to call strdup on the original string, then operate on the copy.
EDIT: OP said he was having trouble thinking about the pointers. With the above code sample, add_string only has to worry about dealing with a string of characters, as opposed to an array of pointers to pointers to characters. So it might look something like this:
int add_string(String **strings, char *s, int len)
{
if(s == NULL)
return -1;
String *current_string = NULL;
strings = realloc(strings, sizeof(String) * (len + 1));
current_string = strings[len];
/* fill out struct fields here */
}
add strdup and strtok can work on a copy of the string. The split() call is more generic than the other spliter() examples, but does the same thing with strtok on a duplicate.
char **
split(char **result, char *w, const char *src, const char *delim)
{
int i=0;
char *p;
strcpy(w,src);
for(p=strtok(w, delim) ; p!=NULL; p=strtok('\0', delim) )
{
result[i++]=p;
result[i]=NULL;
}
return result;
}
void display(String *p)
{
char *result[24]={NULL};
char *w=strdup(p->c);
char **s=split(result, w, p->, "\t \n"); split on \n \t and space as delimiters
for( ; *s!=NULL; s++)
printf("%s\n", *s);
free(w);
}

C split a char array into different variables

In C how can I separate a char array by a delimiter? Or is it better to manipulate a string? What are some good C char manipulation functions?
#include<string.h>
#include<stdio.h>
int main()
{
char input[16] = "abc,d";
char *p;
p = strtok(input, ",");
if(p)
{
printf("%s\n", p);
}
p = strtok(NULL, ",");
if(p)
printf("%s\n", p);
return 0;
}
you can look this program .First you should use the strtok(input, ",").input is the string you want to spilt.Then you use the strtok(NULL, ","). If the return value is true ,you can print the other group.
Look at strtok(). strtok() is not a re-entrant function.
strtok_r() is the re-entrant version of strtok(). Here's an example program from the manual:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
Sample run which operates on subtokens which was obtained from the previous token based on a different delimiter:
$ ./a.out hello:word:bye=abc:def:ghi = :
1: hello:word:bye
--> hello
--> word
--> bye
2: abc:def:ghi
--> abc
--> def
--> ghi
One option is strtok
example:
char name[20];
//pretend name is set to the value "My name"
You want to split it at the space between the two words
split=strtok(name," ");
while(split != NULL)
{
word=split;
split=strtok(NULL," ");
}
You could simply replace the separator characters by NULL characters, and store the address after the newly created NULL character in a new char* pointer:
char* input = "asdf|qwer"
char* parts[10];
int partcount = 0;
parts[partcount++] = input;
char* ptr = input;
while(*ptr) { //check if the string is over
if(*ptr == '|') {
*ptr = 0;
parts[partcount++] = ptr + 1;
}
ptr++;
}
Note that this code will of course not work if the input string contains more than 9 separator characters.
I came up with this.This seems to work best for me.It converts a string of number and splits it into array of integer:
void splitInput(int arr[], int sizeArr, char num[])
{
for(int i = 0; i < sizeArr; i++)
// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i] = (int)num[i] - 48;
}
This is how I do it.
void SplitBufferToArray(char *buffer, char * delim, char ** Output) {
int partcount = 0;
Output[partcount++] = buffer;
char* ptr = buffer;
while (ptr != 0) { //check if the string is over
ptr = strstr(ptr, delim);
if (ptr != NULL) {
*ptr = 0;
Output[partcount++] = ptr + strlen(delim);
ptr = ptr + strlen(delim);
}
}
Output[partcount++] = NULL;
}
In addition, you can use sscanf for some very simple scenarios, for example when you know exactly how many parts the string has and what it consists of. You can also parse the arguments on the fly. Do not use it for user inputs because the function will not report conversion errors.
Example:
char text[] = "1:22:300:4444:-5";
int i1, i2, i3, i4, i5;
sscanf(text, "%d:%d:%d:%d:%d", &i1, &i2, &i3, &i4, &i5);
printf("%d, %d, %d, %d, %d", i1, i2, i3, i4, i5);
Output:
1, 22, 300, 4444, -5
For anything more advanced, strtok() and strtok_r() are your best options, as mentioned in other answers.

Resources