Strightforward parsing json using ‏µC/OS-II - c

Can anyone help in writing a C parser (using Codewarrior) to parse the following file? I tried many C language json parser, but unfortunately didn't get the idea or they make it difficult.
[
[0,"Door1","Door1Drv","Calculator","Alarm"],
[1,"Door3","Door3Drv","Calculator","Alarm"],
[2,"Door2","Door2Drv","Calculator","Alarm"]]

For advance application, recommend to use Frozen. If your application has fix data format as shown above, see below for your ref.
Quite basic version look like below:
#include <stdio.h>
#define MAX_PRAM 4
struct param_t {
int id;
// FIXME: use pointer & malloc to allocate if possible
char data[MAX_PRAM][30];
};
static int parse(const char *buff, int start, const int end,
struct param_t *out)
{
char *ptr = out->data[0];
int state = 0;
int index = 0;
int param_index = 0;
printf("\t> parse next record<%d:%d>\n", start, end);
while((start < end) && (param_index < MAX_PRAM)) {
char ch = buff[start];
// printf("\t> state: %d, char '%c'\n", state, ch);
switch (state) {
case 0: // searching for start point
if ((ch >= '0') && (ch <= '9')) {
out->id = ch - '0';
state++;
}
break;
case 1: // parse number
if ((ch < '0') || (ch > '9')) {
printf ("\t> number %d\n", out->id);
state++;
if (ch == '"')
state++;
} else
out->id = (out->id * 10) + (ch - '0');
break;
case 2: // search string
if (ch == '"') {
index = 0;
state++;
}
break;
case 3: // get string
if (ch == '"') { // finish one string, parse next one if need
ptr[index] = '\0';
printf ("\t> string '%s', length %d\n",
out->data[param_index], index);
param_index++;
ptr = out->data[param_index];
state--;
} else
ptr[index++] = ch;
break;
default: // EOS - exit
break;
}
start++;
}
return (param_index >= 4) ? start : 0;
}
//
// main entry
//
int main(int argc, char *argv[]) {
int file = open("test.txt", 0 /* 0 ~ O_RDONLY in fcntl.h */ );
if (file) {
char buff[1024] = { 0 };
struct param_t param = { 0 };
int len = read(file, buff, 1024);
int pos = 0;
while((pos = parse(buff, pos, len, &param)) > 0) {
printf ("\t%d\n", param.id);
printf("[%4d] %d - %-10s | %-10s | %-15s | %-10s \n",
pos, param.id, param.data[0], param.data[1], param.data[2],
param.data[3]);
}
close(file);
}
}
With input:
[[10,"Door0",
"Door0Drv","Calculator0","Alarm0"],
[15,"Door1","Door1Drv","Calculator1","Alarm1"],
[230,"Door2","Door2Drv","Calculator2",
"Alarm2"]]
Output looks like:
> number 10
> string 'Door0', length 5
> string 'Door0Drv', length 8
> string 'Calculator0', length 11
> string 'Alarm0', length 6
10
[ 49] 10 - Door0 | Door0Drv | Calculator0 | Alarm0
> number 15
> string 'Door1', length 5
> string 'Door1Drv', length 8
> string 'Calculator1', length 11
> string 'Alarm1', length 6
15
[ 100] 15 - Door1 | Door1Drv | Calculator1 | Alarm1
> number 230
> string 'Door2', length 5
> string 'Door2Drv', length 8
> string 'Calculator2', length 11
> string 'Alarm2', length 6
230
[ 158] 230 - Door2 | Door2Drv | Calculator2 | Alarm2
Feel free to customize.

Related

converting binary to corresponding ASCII character

So I'm trying to create a program where the user enters a 12-bit binary hamming code sequence like "100010010001" and it should print out its corresponding ASCII character, which in this case is 'A'.
I'm trying to get my program to ignore the 4 parity bits which are positioned in _ _ 0 _ 1 0 0 _ 0 0 0 1 and shift the other 8 bits over so they're together. In the else statement, I tried to convert the remaining 8 bits to a character. When I attempt to run the program however, the program crashes after I type my binary sequence and press enter. This is the part of the program that I'm struggling with and I was wondering if someone could help me or give me hints as to what I'm doing wrong?
char charToBin(char usersInput[]) {
char c = " ";
for (int i = 12; i >= 0; i--) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
usersInput[i] = usersInput[i + 1];
}else{
c = strtol(usersInput[i], (char **)NULL, 2);
}
}
return c;
}
For your code, you can't use "strtol" without a twist. The char array that you give to "strtol" may not end with "\0". Also, does not matter what you do your array will always have 12 indexes unless you copy a "\0" to index 9 so that "strtol" know that it is the end of the input.
Also, sometimes loops are not the best. For your case, you already know how many indexes you are working with. There is no point in using a loop. Nonetheless, I wrote two methods and included the test code as an example below.
#include <stdio.h>
/*
* This function generate a hammer binary digit string for testing.
* It does not care about the validity of the hammer bit.
* The array that is passed to this function should be the length of 12.
*/
void generateChar(int value, char * output){
output[0] = '0';
output[1] = '0';
output[3] = '0';
output[7] = '0';
output[2] = (value & 0b10000000) > 0? '1' : '0';
output[4] = (value & 0b01000000) > 0? '1' : '0';
output[5] = (value & 0b00100000) > 0? '1' : '0';
output[6] = (value & 0b00010000) > 0? '1' : '0';
output[8] = (value & 0b00001000) > 0? '1' : '0';
output[9] = (value & 0b00000100) > 0? '1' : '0';
output[10] = (value & 0b00000010) > 0? '1' : '0';
output[11] = (value & 0b00000001) > 0? '1' : '0';
}
/*
* First method.
*
*/
char charToBin(char usersInput[]) {
char c = 0;
c = usersInput[2] == '1'? c | 0b10000000 : c;
c = usersInput[4] == '1'? c | 0b01000000 : c;
c = usersInput[5] == '1'? c | 0b00100000 : c;
c = usersInput[6] == '1'? c | 0b00010000 : c;
c = usersInput[8] == '1'? c | 0b00001000 : c;
c = usersInput[9] == '1'? c | 0b00000100 : c;
c = usersInput[10] == '1'? c | 0b00000010 : c;
c = usersInput[11] == '1'? c | 0b00000001 : c;
return c;
}
/*
* Second method.
*/
char charToBin2(char usersInput[]) {
char temp[9];
int pos = 0;
temp[8] = '\0'; // Protect from overflow.
for ( int i = 2; i < 12; i++ ){
if ( i == 3 || i == 7 ) continue;
temp[pos] = usersInput[i];
pos++;
}
return (char) strtol(temp, (char **)NULL, 2);
}
int main(){
char a[] = "100010010001";
char t[12];
int b;
// Test for method 1
for ( int i = 0; i < 256; i++ ){
generateChar(i, t);
b = charToBin(t);
printf("%d ", (unsigned char) b );
}
printf("\n\n");
// Test for method 2
for ( int i = 0; i < 256; i++ ){
generateChar(i, t);
b = charToBin2(t);
printf("%d ", (unsigned char) b );
}
return 0;
}
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
usersInput[i] = usersInput[i + 1];
}else{
In here your if (condition), the curly bracket after that is not necessary.
if((i == 0) || (i == 1) || (i == 3) || (i == 7))
usersInput[i] = usersInput[i + 1];
else{
that would fix a bit maybe
You program has two compile error:
You can not assign string to character ( c= " ") ;
The strtol call takes a string, not a character
After fixing the compile error, two fixes are needed to logic:
1. Perform the filtering of the input string from left to right, to avoid copying position 12 to 11, 11 to 10, which will result in duplicating the last positions. An extra counter is needed to help with the compaction.
2. Perform the strtol once, after the input is fully compacted.
char charToBin(char usersInput[]) {
char j = 0 ;
// Copy relevant input positions, INCLUDING terminating NUL byte at position 12.
for (int i = 0; i <= 12 ; i++) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
continue ;
} ;
usersInput[j] = usersInput[i] ;
j++ ;
} ;
char c = strtol(usersInput, (char **)NULL, 2);
return c;
}
Alternatively you could use bit operations. Something like:
char charToBin(char usersInput[]) {
unsigned c = strtol(usersInput, NULL, 2);
unsigned part1 = c & 0xFu;
unsigned part2 = c >> 1u & 0x70u;
unsigned part3 = c >> 2u & 0x80u;
return (char) (part1 | part2 | part3);
}
Which would give with your input of
char userInput[] = "100010010001";
char ch = charToBin(userInput);
printf("result: %c(%d)\n", ch, ch);
the following output on the console:
result: A(65)

How to convert a sum of money to Indian currency format(Indian number format)? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I wanted to build a C program to convert any number to Indian Currency Format. It can take inputs with negative sign, leading zeros and Decimal point + Mantissa and it will format the input to take care of the leading zeros and add the commas according to Indian number foramt. For example, numbers in Indian Number Format are represented as:
1
10
100
1,000
10,000
1,00,000
10,00,000
1,00,00,000
10,00,00,000
the input and related output would be like:
Minus sign: "-12345" -> "-12,345"
Decimal Point: "-12345.123" -> "-12,345.123"
Leading Zero's: 000000.123 → "0.123" or "-000123456.1234" -> "-1,23,456.1234"
If anyone would like to optimise this code in terms of time and space complexity, make it more concise and clean then do share your code.
Indian numbers are represented in decimal with groups of digits separated by commas. The last group has 3 digits and all more significant digits are grouped in pairs.
Here is a simple solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *convertToInrFormat(const char *s) {
const char *src = s + strspn(s, " \t\r\n"); /* skip spaces */
int len = strspn(src, "0123456789"); /* count number of digits */
int destlen = len + (len > 3 ? len / 2 - 1 : len == 0);
char *dest = malloc(destlen + 1);
if (dest != NULL) {
int i = 0, j = 0;
while (i < len) {
dest[j++] = src[i++];
if (i + 2 < len && ((i ^ len) & 1))
dest[j++] = ',';
}
if (len == 0) {
dest[j++] = '0';
}
dest[j] = '\0';
}
return dest;
}
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
char *input = argv[i];
char *output = convertToInrFormat(input);
printf("%s -> %s\n", input, output);
free(output);
}
return 0;
}
The basic logic of adding the commas is to first copy the sign character if it exists to the second array and then remove it from the original number array. Then if the number of digits in the Exponent part is odd then 1 digit is copied to the second array and removed to make the length even. then for every odd value of the index 'i' a comma is added.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *convertToInrFormat(char *lp_number, int lv_l)
{
char *lp_fnumber = '\0';
char *lp_p = '\0';
int lv_index = 0;
int lv_nsize = 0;
int lv_zerocount = 0;
int sign_count = 0;
int expo_count = 0;
int lv_i = 0;
int lv_j = 0;
if (lp_number[0] == '-') // The 0th position of the char array is checked for negative sign, if found sign_count is incremented.
{
sign_count++;
}
lv_zerocount = strspn(lp_number + sign_count, "0"); // the no. of Leading Zeros is calculated ignoring the negative sign if present.
if (lp_number[sign_count + lv_zerocount] == '.') //if the exponent part consists of only 0's then the zerocount is reduced by 1 to leave behind 1 zero in the exponent part.
{
lv_zerocount = lv_zerocount - 1;
}
if (lv_zerocount > 0) //the zeros are removed by being overwritten
{
memmove(lp_number + sign_count, lp_number + lv_zerocount + sign_count, strlen(lp_number));
}
while (lp_number[sign_count] != '.' && lp_number[sign_count] != '\0') //the count of remaining exponents is taken
{
expo_count++;
sign_count++;
}
lv_l = strlen(lp_number); // New string length
if (expo_count > 3) //inserting the commas
{
lv_nsize = lv_l + (expo_count / 2 - 1) + 1;
lp_fnumber = (char *)malloc(lv_nsize);
if (lp_fnumber != NULL)
{
if (lp_number[0] == '-')
{
lp_fnumber[0] = lp_number[0];
lv_j++;
memmove(lp_number, lp_number + 1, strlen(lp_number));
lv_l--;
if (expo_count % 2 != 0)
{
lp_fnumber[1] = lp_number[0];
lv_j++;
memmove(lp_number, lp_number + 1, strlen(lp_number));
expo_count--;
}
}
else if (expo_count % 2 != 0)
{
lp_fnumber[0] = lp_number[0];
lv_j = lv_j + 1;
memmove(lp_number, lp_number + 1, strlen(lp_number));
expo_count--;
}
lp_p = strchr(lp_number, '.');
if (lp_p != NULL)
{
lv_index = lp_p - lp_number;
}
while (lv_i < expo_count)
{
lp_fnumber[lv_j++] = lp_number[lv_i++];
if (lv_i + 2 < expo_count && lv_i % 2 != 0) //Alt logic:((lv_i ^ lv_l) & 1) here for every odd value of i index a comma is added.
lp_fnumber[lv_j++] = ',';
}
if (lv_index != 0)
{
while (lp_number[lv_index] != '\0')
{
lp_fnumber[lv_j++] = lp_number[lv_index++];
}
}
lp_fnumber[lv_j] = '\0';
}
return lp_fnumber;
}
else
{
return lp_number;
}
}
int main()
{
char lp_number[255];
int lv_l;
char *formated_number;
printf("Enter the lp_number\n");
fgets(lp_number, 255, stdin);
lv_l = strlen(lp_number);
formated_number = convertToInrFormat(lp_number, lv_l);
puts(formated_number);
}

Error in using atof() and strtod() when trying to convert numerical string into float

I've made code to read expressions from a file in postfix notation (RPN) and output the value. While it is correctly reading the values and displaying outputs for expressions without any numbers that use decimal places, it defaults to error for any expression containing a float value.
Basically, if a digit is found within a string read from file, it needs to be converted to a float.
I've unsuccesfully tried setting the data value equal to atof(str) and strtod(const char *str, char **endptr), but I'm still getting the error.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
int top = -1;
float stack[500];
/* push the given data into the stack */
void push (int data) {
stack[++top] = data;
}
/* Pop the top element from the stack */
float pop () {
float data;
if (top == -1)
return -1;
data = stack[top];
stack[top] = 0;
top--;
return (data);
}
int main() {
char str[500];
FILE *p;
if((p=fopen("testfile1.txt","r"))==NULL){
printf("\n Unable to open file string.txt");
return 1;
}
while(fgets(str,500,p)!='\0'){
float data = -1, operand1, operand2, result;
for (int i = 0; i < strlen(str); i++) {
if (isdigit(str[i])) {
/*
* if the i/p char is digit, parse
* character by character to get
* complete operand
*/
data = (data == -1) ? 0 : data;
data = (data * 10) + (str[i] - 48);
continue;
}
if (data != -1) {
/* if the i/p is operand, push it into the stack */
push(data);
}
if (str[i] == '+' || str[i] == '-'
|| str[i] == '*' || str[i] == '/') {
/*
* if the i/p is an operator, pop 2 elements
* from the stack and apply the operator
*/
operand2 = pop();
operand1 = pop();
if (operand1 == -1 || operand2 == -1)
break;
switch (str[i]) {
case '+':
result = operand1 + operand2;
/* push the result into the stack */
push(result);
break;
case '-':
result = operand1 - operand2;
push(result);
break;
case '*':
result = operand1 * operand2;
push(result);
break;
case '/':
result = operand1 / operand2;
push(result);
break;
}
}
data = -1;
}
if (top == 0)
printf("Output:%3.2f\n", stack[top]);
else
printf("have given wrong postfix expression\n");
return 1;
}
}
There are 5 postfix expressions in the file, and they are as follows:
13 1 - 2 / 3 155 + *
100 100 100 100 + + +
10.33 2 2 2 2 2 * * * * *
30 10 - 10 - 10 - 2 *
300 13.25 - 11 3 - / 4 5 - * 3 /
But, the output of the program denies the third expression because it contains 10.33, which is not an integer value.
Output:
Output: 948.00
Output: 400.00
have given wrong postfix expression
Output: 0.00
Output: 300.00
Does anyone know how to modify this code to handle floats?
Cheers.
You could try to manually process decimal values almost the same you process integers, but in C it would be simpler to directly iterate a number in a single pass:
while(fgets(str, sizeof(str), stdin) != NULL) {
unsigned int i;
for (i=0; i<strlen(str); i++) {
if (isdigit(str[i])) {
data = str[i++] - '0'; // initialize data with first digit
while(isdigit(str[i])) {
data = data * 10 + (str[i++] - '0'); // increment with other digits
}
if (str[i] == '.') { // decimal part
double mult = .1;
i++;
while(isdigit(str[i])) {
data = data + mult * (str[i++] - '0'); // increment with decimal part
mult *= .1;
}
}
push(data);
}
...
But in fact strtod does it for you...:
while(fgets(str, sizeof(str), stdin) != NULL) {
unsigned int i;
for (i=0; i<strlen(str); i++) {
if (isdigit(str[i])) {
char *end;
data = ::strtod(str+i, &end);
i = end - str; // that's all we are past the number...
push(data);
}
...

simple way to delimit whitespace (once) in C when already using another delimiter

I have the following code
while (*ptr != ',') {
int items_read = sscanf(ptr, "%91[^,]%n", field, &n);
printf("field = \"%s\"\n", field);
field[0]='\0';
if (items_read == 1)
ptr += n; /* advance the pointer by the number of characters read */
if ( *ptr != ',' ) {
break; /* didn't find an expected delimiter, done? */
}
++ptr; /* skip the delimiter */
}
It reads through my string and creates a new array for each string it finds between the commas, however I have white space in the middle of the string. I have many strings that will be read in, and some of those have white space in more than one area (after that middle place) and I do not want that white space accounted for, just the first instances.
I know I can put || ' ' on the while line, the int line, and/or the second if line but I haven't gotten to do what I need done.
I've heard that using strtok isn't good, or at least there are better ways to do that. I do not know how to add additional 'flags' (like the commas in my code) for the code to by-pass.
ex:
3,875,837 file1.ext
3,437,281 document two.txt
I already have the beginnings doing what I want.
field1 = 3
field2 = 875
field3 = 837
However I want the rest of the string on those 2 inputs to go into separate char arrays and print out as follows:
field4 = file1
field5 = ext
and
field4 = document
field5 = two
field6 = txt
Or, I'm thinking now, is there anyway I can extract the last iteration of that char array field in order to use another loop through the exact same code except replace the ,s with ' ' spaces?
Depends a lot on what you want to use the data for. How to use it elsewhere in the code etc.
Guess I'd often use plain iteration on parsing like this. If you want to use sscanf this might help; as an example:
#include <stdio.h>
int prnt_fields(char **ptr)
{
char field[128];
int n;
int i = 0;
printf("Item {\n");
while (**ptr) {
if(sscanf(*ptr, "%127[^\t\n., ]%n", field, &n) != 1)
break;
printf(" %d => '%s'\n", i++, field);
(*ptr) += n;
/* To handle multiple spaces tabs etc.: */
if(sscanf(*ptr, "%127[ \t.,]%n", field, &n))
(*ptr) += n;
/* Or:
n = 0;
sscanf(*ptr, "%*[ \t.,]%n", &n);
(*ptr) += n;
*/
if (**ptr == '\n') {
printf("} OK!\n");
(*ptr)++;
return **ptr != '\0';
}
}
/* Should never end here unless input is invalid;
* aka not separated with , \n or over long fields (>127) */
printf("} something failed!\n");
return 0;
}
int main(void)
{
char *tst = "3,875,837 file1.ext\n"
"6,875,847 file2.ext\n"
"3,437,281 document two.txt\n"
"9,991,123\tdrei.txt\n"
"4,494,123 vier fünf . txt\n"
;
char field[128];
int n;
char *ptr = tst;
int i = 0;
while (*ptr) {
if(sscanf(ptr, "%127[^, \n.]%n", field, &n) != 1)
break;
printf("field%d = '%s'\n", i++, field);
ptr += n+1;
/* If one want to validate separator
ptr += n;
if (*ptr != ',' && *ptr != ' ' && *ptr != '\n')
break;
++ptr;
*/
}
ptr = tst;
printf("\n---------------\n");
while (prnt_fields(&ptr) > 0)
;
return 0;
}
Should give something like:
field0 = '3'
field1 = '875'
field2 = '837'
...
field18 = '123 drei' <= breaks here
field19 = 'txt'
field20 = '4'
field21 = '494'
field22 = '123'
Item {
0 => '3'
1 => '875'
2 => '837'
3 => 'file1'
4 => 'ext'
} OK!
Item {
0 => '6'
1 => '875'
2 => '847'
3 => 'file2'
4 => 'ext'
} OK!
Item {
0 => '3'
1 => '437'
2 => '281'
3 => 'document'
4 => 'two'
5 => 'txt'
} OK!
Item {
0 => '9'
1 => '991'
2 => '123'
3 => 'drei'
4 => 'txt'
} OK!
Item {
0 => '4'
1 => '494'
2 => '123'
3 => 'vier'
4 => 'fünf'
5 => 'txt'
} OK!
Edit:
OK. This can be done much cleaner and nice, but you'll might get an idea:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
struct file_data {
struct date {
int y;
int m;
int d;
} date;
struct time {
int h;
int m;
} time;
int size_prt[8]; /* max 2^63 : 9223372036854775808 bytes */
double size;
char name[512];
char ext[16];
char ext_tr[16];
char name_prt[32][128]; /* should be malloc or ptrs or done in func or.. */
};
/* Default */
static const struct file_data file_def = {
{0,0,0},{0,0},{-1},0,{'\0'},{'\0'},{'\0'},{{'\0'}}
};
void prnt_filedata(FILE *fh, struct file_data fd)
{
int i = 0;
fprintf(fh,
"File { \n"
" Date: %4d-%02d-%02d\n"
" Time: %02d:%02d\n"
" Size: %.f\n"
" Size: %.2f K\n"
" Size: %.2f M\n"
" Size: %.2f G\n"
" Name: '%s'\n"
" Ext : '%s'\n"
" ExtT: '%s'\n"
" Szpt: ",
fd.date.y, fd.date.m, fd.date.d,
fd.time.h, fd.time.m,
fd.size,
(fd.size / (1 << 10)),
(fd.size / (1 << 20)),
(fd.size / (1 << 30)),
fd.name,
fd.ext,
fd.ext_tr
);
while (fd.size_prt[i] != -1)
fprintf(fh, "%d ", fd.size_prt[i++]);
fprintf(fh, "\n Fprt: ");
i = 0;
while (*fd.name_prt[i])
fprintf(fh, "'%s' ", fd.name_prt[i++]);
fprintf(fh, "\n}\n");
}
int extr_file_data(char **ptr, struct file_data *fd)
{
int i;
int n;
char size[26];
char name[512];
char *p;
*fd = file_def;
while (**ptr) {
if (sscanf(*ptr,
"%4d-%2d-%2d %d:%d %25[0123456789,] %511[^\n]%n",
&fd->date.y, &fd->date.m, &fd->date.d,
&fd->time.h, &fd->time.m,
size, name, &n) != 7) {
fprintf(stderr,
" * ERR; Unable to extract from %s\n",
*ptr);
return 0;
}
(*ptr) += n;
p = size;
i = 0;
/* Size parts + total */
while (*p && i < 7) {
fd->size_prt[i] = (int)strtol(p, &p, 0);
fd->size *= 1000;
fd->size += fd->size_prt[i++];
if (*p) ++p;
}
fd->size_prt[i] = -1; /* flag next to last */
/* get .ext */
if ((p = strrchr(name, '.')) != NULL) {
strncpy(fd->name, name, p - name);
strncpy(fd->ext, p + 1, 16);
/* trimmed ext */
if (sscanf(fd->ext, "%15s", fd->ext_tr) != 1)
*fd->ext_tr = '\0';
} else {
strncpy(fd->name, name, 511);
}
/* get trimmed parts of name */
p = fd->name;
i = 0;
while (sscanf(p, "%127s%n", fd->name_prt[i++], &n) == 1 && i < 32)
p+=n;
;
*fd->name_prt[n] = '\0';
if (**ptr == '\n')
(*ptr)++;
return **ptr != '\0';
}
return 0;
}
int main(void)
{
char *tst =
"2012-04-18 13:28 32 ein.ext\n"
"2012-04-18 13:28 2,446,875,847 zwei.xt \n"
"2012-04-18 13:28 0 drei .xt\n"
"2012-04-18 13:28 7,694,587,183,883,665 vier fünf.txt\n"
"2012-04-18 13:28 9,991,123\t\tsechs\n"
"2012-04-18 13:28 4,494,123 sieben acht . txt\n"
;
char *ptr = tst;
struct file_data fd;
while (extr_file_data(&ptr, &fd) > 0)
prnt_filedata(stdout, fd);
prnt_filedata(stdout, fd);
return 0;
}
Should give:
...
File {
Date: 2012-04-18
Time: 13:28
Size: 2446875847
Size: 2389527.19 K
Size: 2333.52 M
Size: 2.28 G
Name: 'zwei'
Ext : 'xt '
ExtT: 'xt'
Szpt: 2 446 875 847
Fprt: 'zwei'
}
...
File {
Date: 2012-04-18
Time: 13:28
Size: 4494123
Size: 4388.79 K
Size: 4.29 M
Size: 0.00 G
Name: 'sieben acht '
Ext : ' txt'
ExtT: 'txt'
Szpt: 4 494 123
Fprt: 'sieben' 'acht'
}
...
Edit (again); sorry, only a weird shift i forgot to change after testing.
You might take a look at the strcspn() method.
As a nice side effect it could be implemented multi-byte character safe.
How I'd do this would depend on the data. I'd probably read in one string, parse it into two at the first space possibly with strchr, then go through the first string splitting on commas.

Reading an integer and / or character without an array

I need to read an integer one by one until i read a '$', and then to determine the largest, smallest and so on. I could use a character variable and do it, but it works for numbers from 0 to 9. But how do I read integers of two or more digits and at the same time, detect a '$' - I used a char *, but I guess it is equivalent to an array, which I should not use here. Also, char holds a single number / char, hence not suitable for larger numbers. What should I do?
No arrays, no pointers, no tricky char-by-char read & convert. Just plain scanf and getchar.
#include <stdio.h>
int main()
{
int newValue=0; /* value being acquired */
int max; /* current maximum value */
int min; /* current minimum value */
int firstAcquired=0; /* boolean flag set to 1 after first acquisition */
int ch; /* used as temporary storage for the getchar() */
for(;;)
{
/* scanf returns the number of successfully acquired fields; here if it
returns 0 means that the value couldn't be acquired */
if(scanf("%d",&newValue)==0)
{
/* scanf failed, but it's guaranteed it put the offending character
back into the stream, from where we can get it */
ch=getchar();
if(ch=='$' || ch==EOF)
break;
else
/* from here to the break it's just to handle invalid input and EOF
gracefully; if you are not interested you can replace this stuff
with a random curse to the user */
{
puts("Invalid input, retry.");
/* Empty the buffer */
while((ch=getchar())!='\n' && ch!=EOF)
;
}
/* if it's EOF we exit */
if(ch==EOF)
break;
}
else
{
/* Everything went better than expected */
if(!firstAcquired || newValue>max)
max=newValue;
if(!firstAcquired || newValue<min)
min=newValue;
firstAcquired=1;
}
}
if(firstAcquired)
{
printf("The maximum value was %d\n", max);
printf("The minimum value was %d\n", min);
}
return 0;
}
In the interest of spoiling all the fun, showing off, outright overkill and darn tooting fun:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
namespace qi = boost::spirit::qi;
template <typename V>
void show_statistics(const V& data)
{
using namespace boost::spirit::karma;
std::cout << "data:\t"<< format('{' << auto_ % ", " << '}', data) << std::endl;
std::cout << "min:\t" << *std::min_element(data.begin(), data.end()) << std::endl;
std::cout << "max:\t" << *std::max_element(data.begin(), data.end()) << std::endl;
auto sum = std::accumulate(data.begin(), data.end(), 0);
std::cout << "sum:\t" << sum << std::endl;
std::cout << "avg:\t" << (1.0*sum) / data.size() << std::endl;
}
void dostats(const std::vector<int>& data) { show_statistics(data); }
int main()
{
std::cin.unsetf(std::ios::skipws);
auto f = boost::spirit::istream_iterator(std::cin);
decltype(f) l;
bool ok = qi::phrase_parse(f, l, +(+qi::int_ > "$") [ dostats ], qi::space);
if (f!=l)
std::cout << "Remaining input unparsed: " << std::string(f,l) << std::endl;
return ok? 0:255;
}
Demo:
Sample run:
sehe#natty:/tmp$ ./test2 <<< "1 2 3 4 5 $ 3 -9 0 0 0 $ 900 9000 $ unparsed trailing text"
data: {1, 2, 3, 4, 5}
min: 1
max: 5
sum: 15
avg: 3
data: {3, -9, 0, 0, 0}
min: -9
max: 3
sum: -6
avg: -1.2
data: {900, 9000}
min: 900
max: 9000
sum: 9900
avg: 4950
Remaining input unparsed: unparsed trailing text
You can use 'scanf("%s")' to read a group of characters. You can then check if the first character is a '%' and terminate if so. Otherwise, call atoi to convert to an integer. Store the largest and smallest in integer types, not character types.
Basically, the only time you have to deal with characters is when you read them in and check if it's a '$'. Otherwise, use integers all the way through.
If I'm getting what you want correctly it should be something like this:
int i = 0;
char c = getchar();
while (c != '$')
{
i = i * 10 + (c - '0');
c = getchar();
}
Hope it helped.
You can read char by char in a loop, check values and so on...
int i = 0;
char c = 0;
int size = 10;
int currentIndex = 0;
int* integers = malloc(sizeof(int) * size);
int counter = 0;
do
{
scanf("%c", &c);
if (c == ' ') // Match space, used a number separator
{
if (counter != 0 && i != 0)
{
if (currentIndex >= size)
{
size += 5;
integers = realloc(integers, size);
}
integers[currentIndex] = i;
currentIndex++;
}
counter = 0;
i = 0;
}
else if (c >= '0' && c <= '9')
{
i = (i * counter * 10) + (c - '0');
counter++;
}
}
while(c != '$');
Don't forget to free integers in the end!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFF_SIZE 16
#define DATA_MAX_SIZE 64
int main(){
char buff[BUFF_SIZE];
int data[DATA_MAX_SIZE];
int i,value,counter = 0;
char *buffp,*p;
while(NULL!=fgets(buff,BUFF_SIZE,stdin)){
buff[BUFF_SIZE - 1]='\0';
buffp = buff;
next: while(isspace(*buffp))
++buffp;
if(*buffp == '\0')
continue;
value = strtol(buffp, &p, 0);
if(counter == DATA_MAX_SIZE){
printf("over data max size!\n");
break;
} else if(p != buffp){
data[counter++]=value;
if(*p == '\0' || *p == '\r'|| *p == '\n')
continue;
buffp = p;
goto next;
} else {
if(*p == '$')
break;
printf("format error\n");
break;
}
}
//check code
for(i=0;i<counter;++i){
printf("data[%d]=%d\n",i, data[i]);
}
return 0;
}
OUTPUT:
1 2 3
123
456
99 $
data[0]=1
data[1]=2
data[2]=3
data[3]=123
data[4]=456
data[5]=99
12345
4
$
data[0]=12345
data[1]=4

Resources