parsing military time into into HH MM and SS/ - c

Say I have a time like this
12:34:56
How would I go about storing the parsed integers into a char array?(this is a requirement)
argv[2] is the time passed in as a argument in the terminal.
This is what I have so far:
char *semi;
semi = strchr(argv[2],':')
&semi = '\0';
while(argv[2] != null){
By the way, this is in C. I'm aware other languages would make this easier.

Why not simply use sscanf?
Like
char hh[3], mm[3], ss[3];
const char time[] = "12:34:56";
sscanf(time, "%2s:%2s:%2s", hh, mm, ss);
You should check the return value from sscanf for validation of the input.

You can simply put the null byte '\0' in place of the character ':' in the string argv[2] and save pointers to the beginning of the hours, minutes and seconds part in the string.
// pointer to the start of the hour part
char *hh = argv[2];
char *mm, *ss;
char *temp = strchr(hh, ':');
// pointer to the start of the minute part
mm = temp + 1;
// null-terminate the hour part
*temp = '\0';
temp = strchr(mm, ':');
// pointer to the start of the second part
ss = temp + 1;
// null-terminate the minute part
*temp = '\0';
// print the hours, minutes and seconds part
printf("%s\n", hh);
printf("%s\n", mm);
printf("%s\n", ss);
argv[2] is a string, i.e., it is null-terminated, so the seconds part is already null-terminated.

Related

Splitting a string into two and assigning to two char array

I have a string like:
my age is 22\r\n\r\n and I live in Rostock
and some other strings like:
I like to swim\r\n\r\n .Yesterday I competed with my 2 friends
Now I want to split a string by \r\n\r\n and have it associated with buffer. Here is what I am trying to do:
char buffer[500];
strcpy(buffer, "my age is 22\r\n\r\n and I live in Rostock");
char *p = buffer;
if((p = strchr(p,"\r\n\r\n"))) {
p[strcspn(p,"tock")] = 0; // trying to slice until the end
}
printf("%s", p);
This gives me a warning as I try to compile saying warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast I could not understand what this meant.
Also what is good way to split this into 2 char buffers?
strchr expects a mere char and not a string for its second parameter. So you can only pass it a single character.
In C a char is a single character and strings are null terminated char arrays.
What you want to do is probably:
char buffer[500] = "my age is 22\r\n\r\n and I live in Rostock"; // directly initialize the char array
const char sep[] = "\r\n\r\n";
char * p = strstr(buffer, sep); // search the separator
if (p) {
*p = '\0'; // null terminate the first part
p += strlen(sep); // make p point to the start of the second part
printf("%s - %s\n", buffer, p);
}
If you really need to purge the initial part from buffer and have it start at the second part, you could do:
for (char *dest = buffer; p<buffer+sizeof(buffer)-1;) { // do not go past end of array
*dest++ = *p++;
if (*p == '\0') break; // stop on first null
}

Parsing substrings from a string with "sscanf" function in C

I have a gps string like below:
char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";
I want to parse the substrings between the commas like below sequence:
$GPRMC
080117.000
A
4055.1708
.
.
.
I have tried sscanf function like below:
sscanf(gps_string,"%s,%s,%s,%s,%s,",char1,char2,char3,char4,char5);
But this is not working. char1 array gets the whole string if use above function.
Actually i have used strchr function in my previous algorithm and got it work but it's easier and simplier if i can get it work with sscanf and get those parameters in substring.
By the way, substrings between the commas can vary. But the comma sequence is fixed. For example below is another gps string example but it does not contain some of its parts because of sattellite problem:
char gps_string[] = "$GPRMC,001041.799,V,,,,,0.00,0.00,060180,,,N*"
There have been a number of comments in other answers stating that there are a number of problems with strtok() and suggesting using strpbrk() instead. An example of how this is used can be found at Arrays and strpbrk in C
I do not have a compiler available so I could not test this. I could have typos or other misteaks in the code, but I am sure that you can figure out what is meant.
In this case you would use
char *String_Buffer = gps_string;
char *start = String_Buffer;
char *end;
char *fields[MAXFIELDS];
int i = 0;
int n = 0;
char *match = NULL;
while (end = strpbrk(start, ",")) // Get pointer to next delimiter
{
/* found it, allocate enough space for it and NUL */
/* If there ar two consecutive delimiters, only the NUL gets entered */
n = end - start;
match = malloc(n + 1);
/* copy and NUL terminate */
/* Note that if n is 0, nothing will be copied so do not need to test */
memcpy(match, start, n);
match[n] = '\0';
printf("Found field entry: %s\n", match);
/* Now save the actual match string pointer into the fields array*/
/* Since the match pointer is in fields, it does not need to be freed */
fields[i++] = match;
start = end + 1;
}
/* Check that the last element in the gps_string is not ,
Then get the final field, which has the NUL termination of the string */
n = strlen(start);
match = malloc(n + 1);
/* Note that if n is 0, only the terminator will be put in */
strcpy(match, start);
printf("Found field entry: %s\n", match);
fields[i++] = match;
printf("Total number of fields: %d\n", i);
You can use strtok:
#include <stdio.h>
int main(void) {
char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";
char* c = strtok(gps_string, ",");
while (c != NULL) {
printf("%s\n", c);
c = strtok(NULL, ",");
}
return 0;
}
EDIT: As Carey Gregory mentioned, strtok modifies the given string. This is explained in the man page I linked to, and you can find some details here too.

How do I split a string by character position in c

I'm using C to read in an external text file. The input is not great and would look like;
0PAUL 22 ACACIA AVENUE 02/07/1986RN666
As you can see I have no obvious delimeter, and sometimes the values have no space between them. However I do know how long in character length each value should be when split. Which is as follows,
id = 1
name = 20
house number = 5
street name = 40
date of birth = 10
reference = 5
I've set up a structure I want to hold this information in, and have tried using fscanf to read in the file.
However I find something along the lines of just isn't doing what I need,
fscanf(file_in, "%1d, %20s", person.id[i], person.name[i]);
(The actual line I use attempts to grab all input but you should see where I'm going...)
The long term intention is to reformat the input file into another output file which would be made a little easier on the eye.
I appreciate I'm probably going about this all the wrong way, but I would hugely appreciate it if somebody could set me on the right path. If you're able to take it easy on me in regard to an obvious lack of understanding, I'd appreciate that also.
Thanks for reading
Use fgets to read each line at a time, then extract each field from the input line. Warning: no range checks is performed on buffers, so attention must be kept to resize buffers opportunely.
For example something like this (I don't compile it, so maybe some errors exist):
void copy_substr(const char * pBuffer, int content_size, int start_idx, int end_idx, char * pOutBuffer)
{
end_idx = end_idx > content_size ? content_size : end_idx;
int j = 0;
for (int i = start_idx; i < end_idx; i++)
pOutBuffer[j++] = pBuffer[i];
pOutBuffer[j] = 0;
return;
}
void test_solution()
{
char buffer_char[200];
fgets(buffer_char,sizeof(buffer_char),stdin); // use your own FILE handle instead of stdin
int len = strlen(buffer_char);
char temp_buffer[100];
// Reading first field: str[0..1), so only the char 0 (len=1)
int field_size = 1;
int filed_start_ofs = 0;
copy_substr(buffer_char, len, filed_start_ofs, filed_start_ofs + field_size, temp_buffer);
}
scanf is a good way to do it, you just need to use a buffer and call sscanf multiple times and give the good offsets.
For example :
char buffer[100];
fscanf(file_in, "%s",buffer);
sscanf(buffer, "%1d", person.id[i]);
sscanf(buffer+1, "%20s", person.name[i]);
sscanf(buffer+1+20, "%5d", person.street_number[i]);
and so on.
I feel like it is the easiest way to do it.
Please also consider using an array of your struct instead of a struct of arrays, it just feels wrong to have person.id[i] and not person[i].id
If you have fixed column widths, you can use pointer arithmetic to access substrings of your string str. if you have a starting index begin,
printf("%s", str + begin) ;
will print the substring beginning at begin and up to the end. If you want to print a string of a certain length, you can use printf's precision specifier .*, which takes a maximum length as additional argument:
printf("%.*s", length, str + begin) ;
If you want to copy the string to a temporary buffer, you could use strncpy, which will generate a null terminated string if the buffer is larger than the substring length. You could also use snprintf according to the above pattern:
char buf[length + 1];
snprintf(buf, sizeof(buf), "%.*s", length, str + begin) ;
This will extract leading and trailing spaces, which is probably not what you want. You could write a function to strip the unwanted whitespace; there should be plenty of examples here on SO.
You could also strip the whitespace when copying the substring. The example code below does this with the isspace function/macro from <ctype.h>:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int extract(char *buf, const char *str, int len)
{
const char *end = str + len;
int tail = -1;
int i = 0;
// skip leading white space;
while (str < end && *str && isspace(*str)) str++;
// copy string
while (str < end && *str) {
if (!isspace(*str)) tail = i + 1;
buf[i++] = *str++;
}
if (tail < 0) tail= i;
buf[tail] = '\0';
return tail;
}
int main()
{
char str[][80] = {
"0PAUL 22 ACACIA AVENUE 02/07/1986RN666",
"1BOB 1 POLK ST 01/04/1988RN802",
"2ALICE 99 WEST HIGHLAND CAUSEWAY 28/06/1982RN774"
};
int i;
for (i = 0; i < 3; i++) {
char *p = str[i];
char id[2];
char name[20];
char number[6];
char street[35];
char bday[11];
char ref[11];
extract(id, p + 0, 1);
extract(name, p + 1, 19);
extract(number, p + 20, 5);
extract(street, p + 25, 34);
extract(bday, p + 59, 10);
extract(ref, p + 69, 10);
printf("<person id='%s'>\n", id);
printf(" <name>%s</name>\n", name);
printf(" <house>%s</house>\n", number);
printf(" <street>%s</street>\n", street);
printf(" <birthday>%s</birthday>\n", bday);
printf(" <reference>%s</reference>\n", ref);
printf("</person>\n\n");
}
return 0;
}
There's a danger here, however: When you access a string at a certain position str + pos you should make sure that you don't go beyond the actual string length. For example, you string may be terminated after the name. When you access the birthday, you access valid memory, but it might contain garbage.
You can avoid this problem by padding the full string with spaces.

Double pointer to char[]

Alright, so I have the following code:
char** args = (char**)malloc(10*sizeof(char*));
memset(args, 0, sizeof(char*)*10);
char* curToken = strtok(string, ";");
for (int z = 0; curToken != NULL; z++) {
args[z] = strdup(curToken);
curToken = strtok(NULL, ";")
}
I want every arg[z] casted into an array of chars -- char string[100] -- and then processed in the algorithms I have following. Every arg[z] needs to be casted to the variable string at some point. I am confused by pointers, but I am slowly getting better at them.
EDIT:
char string[100] = "ls ; date ; ls";
arg[0] will be ls, arg[1] will be date, and arg[2] will be ls after the above code.
I want to put each argument back into char string[100] and process it through algorithms.
one easiest way is to keep a backup of the original string in some temporary variable.
char string[100] = "ls ; date ; ls";
char temp_str[100] = {0};
strcpy (temp_str, string);
Another way is to do it by strcat. z has the number of agruments.
memset(string, '\0', 100);
for (i = 0; i < z; i++)
{
strcat(string, args[i]);
if (i != (z - 1))
{
//if it is last string dont append semicolon
strcat(string, ";");
}
}
Note : Take care of the boundary condition check
If you want the parts of string copied into a fixed length string[100] then you need to malloc 100 chars for each args[] inside the loop and strncpy() the result of strtok into it. strdup will only allocate enough memory for the actual length of the supplied string (plus \0)
This:
char** args = (char**)malloc(10*sizeof(char*));
memset(args, 0, sizeof(char*)*10);
is broken code. First, you shouldn't cast malloc()'s return value. Second, args is a pointer to ten pointers to char. You can't set them to NULL using memset(), there's no guarantee that "all bytes zero" is the same as NULL. You need to use a loop.

Arduino serial.print() is adding an extra character after the actual char

char *feedtime = "0:0";
String interval = "6";
char* convert(char* x, String y){
int hour;
int minute;
sscanf(x, "%d:%d", &hour, &minute);
char buf[5];
if (y == "6"){
if (hour > 17){
hour = (hour+6)%24;
snprintf(buf, 5, "%d%s", hour, ":0");
}
if (hour < 18){
hour = hour + 6;
snprintf(buf, 5, "%d%s", hour, ":0\0");
}
}
buf [5] = '\0';
return buf;
}
When I execute convert(time, interval);
the serial monitor returns the correct value but adds a ' or another symbol to it.
Any ideas why?
I updated my code from what people said, however I still get the same issue?
You are returning a pointer to a stack variable. This is wrong. Once the function exits the stack space used by 'buf' is undefined.
You need an extra character in your buffer. You only have a 4 character array, but you need 5 characters (2 for the hour, 2 for the :0, and 1 for the trailing 0). You also need to null terminate the string when you are done.
and what jcopenha says.
Your strings aren't properly zeroterminated. Increase the size of buf.

Resources