I wrote a functions to parse a NMEA sentence, store parameters in separate arrays and write their values.
First I ran it in console and everything worked as expected. The functions along the test commands in main() are the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06
char *get_substring(size_t start, size_t stop, const char *src, char *dst, size_t size)
{
int count = stop - start;
if ( count >= --size )
{
count = size;
}
sprintf(dst, "%.*s", count, src + start);
return dst;
}
void get_separator_position(char *input_string, int *separators_array, int separators_count)
{
//10 separators
char *separator = ",";
char *current_string = input_string;
int current = 0;
char *found;
int pos;
int cur_pos = 0;
for(current = 0; current < separators_count; current++)
{
found = strstr(current_string, separator);
if(found != NULL)
{
pos = found - current_string;
cur_pos += pos;
separators_array[current] = cur_pos + current;
current_string = &input_string[cur_pos + 1 + current];
}
else
{
//printf("Not found!\n");
}
}
}
void parse_nmea_string(char *nmea_string, char *utc, char *latitude, char *longitude, char *hdop, char *altitude, char *fix, char *cog, char *spkm, char *spkn, char *date, char *nsat)
{
//10 separators "," in NMEA sentence
int separators_array[10];
get_separator_position(nmea_string, &separators_array[0], 10);
int length = strlen(nmea_string);
utc = get_substring(9, separators_array[0] + 1, nmea_string, utc, sizeof(char) * (separators_array[0] - 9 + 1));
latitude = get_substring(separators_array[0] + 1, separators_array[1], nmea_string, latitude, sizeof(char) * (separators_array[1] - separators_array[0]));
longitude = get_substring(separators_array[1] + 1, separators_array[2], nmea_string, longitude, sizeof(char) * (separators_array[2] - separators_array[1]));
hdop = get_substring(separators_array[2] + 1, separators_array[3], nmea_string, hdop, sizeof(char) * (separators_array[3] - separators_array[2]));
altitude = get_substring(separators_array[3] + 1, separators_array[4], nmea_string, altitude, sizeof(char) * (separators_array[4] - separators_array[3]));
fix = get_substring(separators_array[4] + 1, separators_array[5], nmea_string, fix, sizeof(char) * (separators_array[5] - separators_array[4]));
cog = get_substring(separators_array[5] + 1, separators_array[6], nmea_string, cog, sizeof(char) * (separators_array[6] - separators_array[5]));
spkm = get_substring(separators_array[6] + 1, separators_array[7], nmea_string, spkm, sizeof(char) * (separators_array[7] - separators_array[6]));
spkn = get_substring(separators_array[7] + 1, separators_array[8], nmea_string, spkn, sizeof(char) * (separators_array[8] - separators_array[7]));
date = get_substring(separators_array[8] + 1, separators_array[9], nmea_string, date, sizeof(char) * (separators_array[9] - separators_array[8]));
nsat = get_substring(separators_array[9] + 1, length, nmea_string, nsat, sizeof(char) * (length - separators_array[9]));
}
int main(int argc, char *argv[])
{
static const char text[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
char utc[20];
char latitude[30];
char longitude[20];
char hdop[20];
char altitude[20];
char fix[20];
char cog[20];
char spkm[20];
char spkn[20];
char date[20];
char nsat[20];
printf("Separator %d at position %d\n", pos, separators_array[pos]);
parse_nmea_string(text, utc, latitude, longitude, hdop, altitude, fix, cog, spkm, spkn, date, nsat);
printf("UTC: %s\n", utc);
system("PAUSE");
return 0;
}
This code works fine and the test output is
UTC: 200949.000
Then I tried to use the above function on the microcontroller project and write the array values using the existing debug_str() function which is the following:
// Debug function prints string msg to UART1 (to PC)
void debug_str(const char* msg)
{
#ifdef debug
putchar1(0x24); //$
while(*msg)
{
putchar1(*msg++);
}
putchar1(0x0D); //Carriage Return
#endif
}
So combining the parsing functions with existing code I tried to write the array values the following way:
char UTC[15];
char latitude[15];
char longitude[15];
char hdop[6];
char altitude[9];
char fix[5];
char cog[10];
char spkm[8];
char spkn[8];
char date[10];
char nsat[6];
static const char nmea_test[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
...
parse_nmea_string(nmea_test, UTC, latitude, longitude, hdop, altitude, fix, cog, spkm, spkn, date, nsat);
debug_str(latitude);
But this way the output was not correct.
Output:
$*s
Does anyone what the problem is and how to correctly store and write to the output the parameters which are parsed from the string nmea_test?
Thank you!
You should understand the difference between arrays and pointers in C.
Read any good C textbook about this.
Your get_substring function don't do what you expect. It does not allocate any string for its result.
You might consider using strdup inside get_substring, and adopt the convention that the caller should free the result.
Now it works. Functions get_substring and get_separator_positions had to be modified the following way:
char *get_substring(unsigned int start, unsigned int stop, const char *src, char *dst, unsigned int size)
{
int count = stop - start;
if ( count >= --size )
{
count = size;
}
// sprintf(dst, "%.*s", count, src + start); - this line was replaced by the following two lines (the microcontroller does not support strdup so strncpy had to be used)
strncpy(dst, &src[start], size);
dst[size] = '\n';
return dst;
}
//char input_string[] = "$GPSACP: 200949.000,4603.9172N,01429.5821E,1.0,337.8,3,53.82,0.36,0.19,231011,06";
void get_separator_position(char *input_string, int *separators_array, int separators_count)
{
//10 separators
char separator[] = ",";//char *separator = "," didn't work
char *current_string = input_string;
int current = 0;
char *found;
int pos;
int cur_pos = 0;
//char tmp_pos[10];
for(current = 0; current < separators_count; current++)
{
found = strstr(current_string, separator);
if(found != NULL)
{
debug_str("found!");
//debug_str(found);
pos = found - current_string;
// itoa(pos,tmp_pos);
// debug_str(tmp_pos);
cur_pos += pos;
separators_array[current] = cur_pos + current;
current_string = &input_string[cur_pos + 1 + current];
}
else
{
debug_str("Not found!");
}
}
}
Related
So, I implemented split in C, now I know strtok exists, but I wanted to implement it, so my function returns a struct that has the string array and the length, which is decided by the number of times the delimiter occurs and whether it's the first value or not, here's the code.
split.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int count_delm(char *, char);
char *make_str(char);
struct split_output {
char **arr;
int size;
};
typedef struct split_output split_arr;
split_arr *split(char *, char);
split.c
#include "split.h"
int count_delm(char *str, char delm) {
register int lpvar = 0;
register int counter = 0;
while (str[lpvar] != '\0') {
if (str[lpvar] == delm) {
counter++;
}
lpvar++;
}
return counter;
}
char *make_str(char ch) {
char *ret_str = (char *)malloc(2);
ret_str[0] = ch;
ret_str[1] = '\0';
return ret_str;
}
split_arr *split(char *str, char delm) {
int num_delm = count_delm(str, delm);
char **final_arr;
register int lpvar = 0;
register int arr_counter = 0;
char *concat_str = (char *)malloc(2);
int ret_size = 0;
if (str[0] == delm) {
concat_str = make_str(str[1]);
final_arr = (char **)malloc(sizeof(char *) * (num_delm));
ret_size = num_delm;
lpvar++;
} else {
concat_str = make_str(str[0]);
final_arr = (char **)malloc(sizeof(char *) * (num_delm + 1));
ret_size = num_delm + 1;
}
while (1) {
if (str[lpvar + 1] != '\0') {
if (str[lpvar + 1] != delm) {
concat_str = strcat(concat_str, make_str(str[lpvar + 1]));
lpvar++;
} else {
final_arr[arr_counter] = concat_str;
arr_counter++;
if (str[lpvar + 2] != '\0') {
lpvar++;
lpvar++;
concat_str = make_str(str[lpvar]);
}
}
} else {
arr_counter++;
final_arr[arr_counter] = concat_str;
printf("%s is the last at pos %d\n", concat_str, arr_counter);
break;
}
}
split_arr *ret_struct = (split_arr *)malloc(sizeof(split_arr));
(*ret_struct).size = ret_size;
(*ret_struct).arr = final_arr;
return ret_struct;
}
That was the code of the split implementation, here's the code that tests it.
test.c
#include "split.h"
int main() {
char *x = "lryabruahsdfads";
split_arr output = *(split(x, 'a'));
char **read = output.arr;
int len = output.size;
int loop = 0;
printf("size: %d", len - 1);
for (loop = 0; loop < len; loop++) {
puts(*(read + loop));
}
return 0;
}
Here's the output when executed:
ds is the last at pos 4
size: 3lry
bru
hsdf
Segmentation fault (core dumped)
Why is output.size 3lry? I de-referenced the struct pointer to get the struct so there's nothing wrong with that. I can't find the error, I've been trying to debug for almost an hour.
In your split.c file over here:
else{
arr_counter++; //comment this line
final_arr[arr_counter]=concat_str;
printf("%s is the last at pos %d\n",concat_str,arr_counter);
break;
}
You are incrementing variable arr_counter which you should not because you already incremented it inside the if. Just comment out this line and your code works fine.
And your output is fine just add a line return to the printf statements like:
printf("size: %d \n",len-1);
I need write the following function: char * Rev(char * str, int size);
The function get *pointer to string. It should replace the order of words within str, and return the result in the pointer. Only need reverse order for the words. Must use the helper swap function. In this function, there is no use of [] anywhere, ONLY USE pointers. Printing via main only.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str1,*str2,*pRev;
char *pstr="YPEFMI ICMKMS JGLYZJ";
swap(&str1, &str2);
getchar();
*pRev =*RevWords (pstr,SIZE)
return 0;
}
methods.c
void swap(char* str1, char* str2);
char * Rev(char * string, int size);
//The function replaces the contents of both strings 1s and 2s.
void swap(char* str1, char* str2)
{
// if both of them are zero characters then stop
if (*str1 == '\0' && *str2 == '\0')
return;
// else swap the contents of the pointers
else
{
char tmp = *str1;
*str1 = *str2;
*str2 = tmp;
// advance both pointer and swap them too if thye are not '\0'
swap(++str1, ++str2);
}
}
char * Rev(char * string, int size)
{ //no idea-->NOT work in reverse.
char string[SIZE * (SIZE + 1)]
char *str = (char *)(malloc (SIZE * SIZE + SIZE-1));
for (int i = 0; i < SIZE; i++) {
memcpy(string + i * SIZE, matrix + i, SIZE);
if (i < SIZE - 1) {
swap(*(string + i * SIZE + SIZE));
} else {
swap(*(string + i * SIZE + SIZE)) = 0;
}
}
return string;
}
The swap method work but REV method NOT work.
For example:
pStr = YPEFMI ICMKMS JGLYZJ
pRev = -->JGLYZJ ICMKMS YPEFMI <--
I have this simple function for extrapolate a substring in a string.
char* substr(const char *string, size_t start, size_t end) {
const char *char_start = &string[start];
const char *char_end = &string[end];
char *substring = (char *) calloc(1, char_end - char_start + 1);
memcpy(substring, char_start, char_end - char_start + 1);
return substring;
}
I have only one calloc, that create the returned string.
I try the code in a cycle, for extrapolate the substring of a string array.
This is the main code where I test the function:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t i;
char *tmp = NULL;
char *kmer_array[5] = {"GTGAA", "ACGGT", "AACGG", "AGTGA", "TGAAC"};
for ( i = 0; i < 5; i++ ) {
tmp = substr(kmer_array[i], 1, strlen(kmer_array[i]));
}
free(tmp);
return 0;
}
But when I test the code with valgrind this is the output (link).
I dont't understade where I lost the byte
You set tmp inside the loop 5 times but only free the last one (outside the loop)
i got a new task from my teach to implement some basic string operations like append, remove, substr and insert.
while i was thinking at how should i approach this problem i thought i could just write a function which does the copying and ...
int copy(char* buffer,char * string,int begin,int end)
{
if(end == 0)
end = length(string);
//Copy from begin to end and save result into buffer
for(int i = 0; i < end;i++)
buffer[i] = *(string+begin+i);
return end;
}
with that implementation, so my idea i could just implement all the other functions asked by my teacher like this :
void insert(char* buffer,char * string, char * toInsert, int begin,int end)
{
//Copy till the position of the original string
begin = copy(buffer,
string,0,begin);
//Insert
//copy from the last change of the original string
begin = copy(buffer+begin,
toInsert,0,end);
//Copy whats left
copy(buffer+begin,
string);
}
So if i now try to insert something with this function i get some weird output:
int main() {
char * Hallo = "Hello World how are things?";
char * appendix = "Halt die schnauze!";
char buffer[128];
for (int i = 0; i < 128;i++)
buffer[i] = -0;
insert(buffer,Hallo,appendix,5,0);
printf("%s\n",buffer);
return 0;
}
output: HelloHalt die schnHello World how are things?
I simply cannot get my head around why the output does look like this. Do i have a logical mistake there?
fix like this:
#include <stdio.h>
size_t length(const char *s){
size_t len = 0;
while(*s++){
++len;
}
return len;
}
int copy(char *buffer, const char *string, int begin, int end){
int len = 0;//copy length
if(end == 0)
end = length(string);
for(int i = begin; i < end; i++)//End position is not included
buffer[len++] = string[i];
return len;
}
void insert(char *buffer, const char *string, const char *toInsert, int begin, int end){
int len;
len = copy(buffer, string, 0, begin);
len += copy(buffer + len, toInsert, 0, end);
len += copy(buffer + len, string, begin, end);
buffer[len] = 0;
}
int main(void) {
char * Hallo = "Hello World how are things?";
char * appendix = "Halt die schnauze!";
char buffer[128] = {0};
insert(buffer, Hallo, appendix, 5, 0);
printf("%s\n",buffer);
return 0;
}
I have a character array of length 32 and would like to take certain charcters out of it.
for example
111111000000000000000000111111 <32 chars
I would like to take chars 0-6 which would be 111111
Or even take chars 26-31 which would be 111111
char check_type[32];
Above is how I'm declaring.
What I would like to be able to do is define a function or use a function that takes that starting place, and end character.
Ive looked at many ways like using strncpy and strcpy but found no way yet.
I would simply wrap strncpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Creates a sub-string of range [start, end], return value must be freed */
char *substr(char *src, size_t start, size_t end)
{
size_t sub_len = end - start + 1;
char * new_str = malloc(sub_len + 1); /* TODO: check malloc's return value */
strncpy(new_str, src, sub_len);
new_str[sub_len] = '\0'; /* new_str is of size sub_len + 1 */
return new_str;
}
int main(void)
{
char str[] = "111111000000000000000000111111";
char *sub_str = substr(str, 0, 5);
puts(sub_str);
free(sub_str);
return EXIT_SUCCESS;
}
Output:
111111
Use memcpy.
// Stores s[from..to) in sub.
// The caller is responsible for memory allocation.
void extract_substr(char const *s, char *sub, size_t from, size_t to)
{
size_t sublen = to - from;
memcpy(sub, s + from, sublen);
sub[sublen] = '\0';
}
Sample:
char *substr(char *source, int startpos, int endpos)
{
int len = endpos - startpos + 2; // must account for final 0
int i = 0;
char *src, *dst;
char *ret = calloc(len, sizeof(char));
if (!ret)
return ret;
src = source + startpos;
dst = ret;
while (i++ < len)
*dst++ = *src++;
*dst = 0;
return ret;
}
Of course, free the return code when you don't need it anymore. And you notice this function will not check for the validity of endpos vs startpos.
First define the required interface...perhaps:
int substring(char *target, size_t tgtlen, const char *source, size_t src_bgn, size_t src_end);
This takes a destination (target) array where the data will be copied, and is given its length. The data will come from the source array, between positions src_bgn and src_end. The return value will be -1 for an error, and the length of the output (excluding the terminating null). If the target string is too short, you will get an error.
With that set of details in place, you can implement the body fairly easily, and strncpy() might well be appropriate this time (it often isn't).
Usage (based on your question):
char check_type[32] = "111111000000000000000000111111";
char result1[10];
char result2[10];
if (substring(result1, sizeof(result1), check_type, 0, 6) <= 0 ||
substring(result2, sizeof(result2), check_type, 26, 31) <= 0)
...something went wrong...
else
...use result1 and result2...
Check this:
char* Substring(char *string, int len, int start, int end) {
/*
Creates a substring from a given string.
Args:
string: The string whose substring you need to find.
len: The length of the string.
start: The start position for the substring.
end: The end position of the substring (inclusive).
Returns:
substring: (of type char*) which is allocated on the heap.
NULL: on error.
*/
// Check that the start and end position are valid.
// If not valid, then return NULL.
if (start < 0 || start >= len || end < 0 || end >= len) {
return NULL;
}
// Allocate memory to return the substring on the heap.
char *substring = malloc(sizeof(char) * (end - start + 2));
int index = 0, i;
for (i = start; i <= end; i++) {
substring[index] = string[i];
index++;
}
// End with a null character.
substring[index] = '\0';
return substring;
}
int main() {
char str[] = "11111100000000000000000000111111";
printf("%s\n", Substring(str, strlen(str), 0, 5));
printf("%s\n", Substring(str, strlen(str), 26, 31));
}