Inserting and deleting spaces in a text array using C - c

I've managed to create the following output from a program:
7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).
I want to either add a space or delete a space depending on what character I am pointing to. Would sscanf allow you to do this?
I was just wondering what would be the easiest way to insert and delete spaces in this text. For example, I want to delete a space between ( and 'num' eg 8, but provide a space between H and 'letter' eg m. So far I have code that looks something like this:
typedef struct node {
int i;
char array[SIZE];
struct node* link;
} node;
node* format(void)
{
int count = 0;
int size = list_size(data, sizeof(data)) / 4;
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
int i;
int j;
for (i = 0, j = 0; i < sizeof(ptr->array); i++, j++)
{
if (ptr->array[0] == ' ' && count == 0)
{
count++;
j--;
}
else if (ptr->array[i] == ' ' && ptr->array[i-1] == '.')
{
j--;
ptr->array[i] = ',';
}
else if (ptr->array[i] == ',' && ptr->array[i-1] == ')')
{
if (count == size)
{
ptr->array[i] = '.';
}
}
ptr->array[j] = ptr->array[i];
}
count++;
}
return head;
}
Note that the above is currently a linked list of size 3, whereby I created the latter to enable swapping of "groups" of characters and then reverse the order in a specific way. Would it be easier to format if I passed everything back to a single array first?
Any tips/advice would be gratefully received!

The easiest way is to use sscanf to parse correctly the string and then just print it to another string. Manually parsing the string in the way you are doing it will give you no observable speed/memory gain and will just add a ton of code.
Example
#include<stdio.h>
int main(){
char str[]= "7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).";
float f1, f2, f3;
int i1, i2, i3;
sscanf(str, "%f ( %dHm,), %f ( %dHm,),%f ( %dHs,).", &f1, &i1, &f2, &i2, &f3, &i3);
printf("%f ( %dHm,), %f ( %dHm,),%f ( %dHs,).\n", f1, i1, f2, i2, f3, i3);
return 0;
}
scanf functions are powerful and as you can see you can use them to parse your formated string. When you run the code in this example, it prints this:
7.860000 ( 8Hm,), 6.820000 ( 4Hm,),12.100000 ( 1Hs,).
The way it works is that scanf can ignore characters. So it reads the first float and then ignores blank spaces, ignores a parenthesis, reads an int, ignores Hm and so on.
My printf is formating the string the same way it came from the input. You can tweak it to meet your requirements. You should also search around and limit decimal digits. But the basic idea is that you get the data you need from the string and then you can print that data the way you want.

Doing the best to understand what you currently have in ptr-array and then how to accomplish the reformat, which you appear to want to do in-place simply updating ptr->array to hold to updated formatted string, then you can build a correctly formatted buffer to replace the current ptr->array.
Note: the better solution would be separate the values in ptr->array into actual separate values and hold that as part of your linked list where you either statically declare an array of structs to hold your values and units (which is my best guess for 7.86 (8Hm,). That would allow you to format the values in any way needed rather than being stuck with what is in array. For example:
#define USIZE 8
typedef struct values {
double value;
char[USIZE];
} values;
typedef struct node {
int i;
char array[SIZE];
values *vals;
struct node* link;
} node;
or, e.g.:
typedef struct node {
int i;
char array[SIZE];
values vals[3];
struct node* link;
} node;
Regardless, your original question was how to reformat your existing ptr->array removing spaces following '(' and separating '8Hm' to '8H m' in your sample data of:
7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).
Given that you are iterating over each node in your list, this reformat would presumably only be run once after you have collected/stored all your nodes. One approach is to construct a new buffer holding array in its new format and then replace your new array with the properly formatted buffer.
Yes, there are many ways to do this, but if your reformat criteria is limited, simply walking down array with a pointer using the tried and true inch-worm method filling your new buffer with the characters in the desired format is about as easy and flexible as anything else.
Below, the example creates a new buffer (buf[SIZE]) copies/replaces/removes characters from ptr->array and then replaces ptr->array with the contents of buf.
NOTE: I have not run this on any data, so you may need to tweak the logic a bit. This is merely meant to show you an approach that can be used and to make that as close a possible to a solution to your question (to the best I understood it).
NOTE2: you can replace the upper/lower case conditionals below with isupper or islower from ctype.h if you are not limited to specific headers. Additionally, memcpy below will require string.h, but can be re-written to simply do the copy without it if that is an issue.
node* format(void)
{
/* for each node in list */
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
/* declare a pointer to `ptr->array` and `buf` */
char *p = ptr->array;
char *pend = p + SIZE;
char buf[SIZE] = {0};
char *bp = buf;
/* for each char in ptr->array */
while (p < pend)
{
/* if not the first char */
if (p > ptr->array)
{
/* if current char is ' ' */
if (*p == ' ')
{
/* if previous char is one of the following */
if (*(p - 1) == '.') *bp++ = ',';
if (*(p - 1) == ')') *bp++ = '.';
if (*(p - 1) == '(') { p++; continue; } /* remove ' ' after '(' */
}
/* if current is lower case & prior is upper, separate */
else if (('a' <= *(p - 1) && *(p - 1) <= 'z') && ('A' <= *p && *p <= 'Z'))
{
*bp++ = ' ';
*bp++ = *p;
}
/* default - copy current to buf */
else
*bp++ = *p;
}
p++; /* advance to next char */
}
/* copy formatted string to ptr->array */
memcpy (ptr->array, buf, SIZE);
}
return head;
}
Note3: if SIZE is a global #define, then replace sizeof (ptr->array) wtih SIZE.

Related

How to separate terms between parentheses and list them in C

I have the following problem, I have a string that comes with x terms, and some are in parentheses. I need to be able to separate the terms that are in parentheses and place them in the nodes of a list:
The first node in the list contains the entire character string, then the terms that are in parentheses are stored in the following nodes.
Something like this:
String: a*(b+(c+j)-h)*2 + (a+(b-c))
So, in list:
Firts node :
a*(b+(c+j)-h)*2+(a+(b-c))->(b+(c+j)-h)->(c+j)->(a+(b-c))->(b-c)
I need ideas to implement the algorithm of separation of terms, I am stuck with that part. I have already implemented all the lists part.
The function they ask me for is
void separate (char * s)
Recursion is a common way to parse nested structures, as #SomeProgrammerDude commented.
My intuition for the algorithm that you are looking for is this:
1) Recursively call the separate method.
2) Every call should parse one term enclosed in parentheses, and insert it at the end of our list.
3) The method has to two modes: iterate over the input string and iterate over the input string while filling up the term.
We are looking for the first occurrence of an opening parenthesis; once this is found, the method enables the "read" mode, and starts copying everything in its path to a local buffer, until the closing parentheses is found.
When that happens, the method disables the "read" mode, flagging that the term is now ready for insertion in the list.
4) How to bypass nested terms? Once the 1st opening parenthesis is found, maintain a counter of parentheses, which is adjusted according to the number of parentheses met (+1 for an opening parenthesis, -1 for a closing one).
If an opening parenthesis is met, the counter gets incremented by 1. If the counter is greater than 1, that signals us that a nested term is found, and thus we shouldn't stop when its closing parentheses is met, but instead continue, while decrementing the counter by 1.
5) Once a term is inserted, then we should recursively call our separate method, where now the input string should be the already parsed input, starting from the character after the first opening parenthesis that we found.
6) Base case of the recursion? When all the input is consumed, and we reached the NULL string terminator.
Full code example (uncomment print statements that show the status as the program progresses):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct listnode *Listptr;
struct listnode {
char* value;
Listptr next;
};
void insert_at_end(Listptr *, char *);
void print(Listptr);
void free_list(Listptr *);
void separate(Listptr *list, char *s)
{
if(!*s)
return;
int parentheses = 0, read = -1, i = 0;
char term[16] = {0}, *opening_parenthesis;
//printf("Before while input is %s\n", s);
while(*s)
{
//printf("#parentheses = %d, read = %d, i = %d, term = %s\n", parentheses, read, i, term);
if(*s == '(')
{
if(parentheses == 0)
opening_parenthesis = s;
read = 1;
parentheses++;
}
else if(*s == ')')
{
if(parentheses > 1)
parentheses--;
else if(parentheses == 1)
{
term[i++] = *s;
read = 0;
}
}
if(read == 1)
{
term[i++] = *s;
//puts(term);
}
else if (read == 0)
{
insert_at_end(list, term);
separate(list, opening_parenthesis + 1);
return;
}
s++;
}
}
int main(void)
{
char buf[128];
fgets(buf, sizeof(buf), stdin);
// eat trailing newline of fgets
if(!strlen(buf))
{
printf("No input, exiting..\n");
return EXIT_FAILURE;
}
// eat trailing newline of fgets
buf[strlen(buf)] = '\0';
// Goal: a*(b+(c+j)-h)*2+(a+(b-c))->(b+(c+j)-h)->(c+j)->(a+(b-c))->(b-c)
Listptr list = NULL;
insert_at_end(&list, buf);
//printf("First node: "); print(list);
separate(&list, buf);
print(list);
free_list(&list);
return EXIT_SUCCESS;
}
void insert_at_end(Listptr *ptraddr, char* str)
{ /* Insert str as last element of list *ptraddr */
while (*ptraddr != NULL) /* Go to end of list */
ptraddr = &((*ptraddr)->next);/* Prepare what we need to change */
/* In real application, check for NULL pointer of malloc! */
*ptraddr = malloc(sizeof(struct listnode)); /* Space for new node */
/* Space for string. Length of str + 1 for the null terminator */
(*ptraddr)->value = malloc((strlen(str) + 1) * sizeof(char));
strcpy((*ptraddr)->value, str); /* Copy str */
(*ptraddr)->next = NULL; /* There is no next element */
}
void print(Listptr list) /* Print elements of list */
{
while (list != NULL) { /* Visit list elements up to the end */
printf("%s--> ", list->value); /* Print current element */
list = list->next; /* Go to next element */
}
printf("NULL\n"); /* Print end of list */
}
void free_list(Listptr *ptraddr)
{
Listptr templist = *ptraddr;
while(*ptraddr != NULL) {
*ptraddr = (*ptraddr)->next;
free(templist->value);
free(templist);
templist = *ptraddr;
}
*ptraddr = NULL;
}
Output (for your input):
a*(b+(c+j)-h)*2 + (a+(b-c))--> (b+(c+j)-h)--> (c+j)--> (a+(b-c))--> (b-c)--> NULL
Note1: I altered the prototype of your separate method to allow for the list to be passed also as a parameter. I guess in your implementation the list is a global variable or something, which in general should be avoided.
Note2: It could have been implemented without the usage of the read flag, by using just the variable for the number of parentheses to determine when to read (when that number positive), and you could assign a reserved value (-1 for example), to designate when reading is done, and the term is ready for list insertion.
Assumption1: Term's length is 15 characters at most. The code should typically check that this length is not surpassed - not done in my implementation.
Assumption2: It is assumed that term is valid, i.e. it contains the same number of opening and closing parentheses. In a real-world scenario one should sanitize the input.
Live demo
PS: I have the list implementation in strList(C) also.
John Bollinger recommended:
Presumably, a recursive function for the purpose would return information about how much of the string had been parsed, so that its caller could\ pick up with the remainder of the string, if any. That implies that it would not necessarily be separate() itself that is recursive, but rather some helper function that it calls.
OP already sketched (in comment):
If given a function it returns a substring with what is inside the two parentheses I can insert it in my list. And then I can call that function back with recursion as they told me above.
This is where I started.
There come various methods in mind to build substrings:
modify original string by overwriting a character with a delimiter '\0' (may be, temporarily) – like done e.g. in strtok()
allocate memory for substrings and copy portions of original string (using something like e.g. strdup())
just return length (and, may be, start) of substring
I used the third option.
#include <assert.h>
#include <stdio.h>
#include <string.h>
void add_term(char *s, size_t len)
{
printf("'%.*s'\n", (int)len, s);
}
size_t find_term(char *s, size_t len)
{
assert(*s == '(');
int n = 1;
size_t i = 1;
for (; i < len && n; ++i) n += (s[i] == '(') - (s[i] == ')');
return n ? fprintf(stderr, "ERROR!\n"), 0 : i;
}
void separate_terms(char *s, size_t lenTotal, int addTotal)
{
for (size_t i = 0; i < lenTotal;) {
switch (s[i]) {
case '(': {
const size_t len = find_term(s + i, lenTotal - i);
if (!len) return;
if (len < lenTotal + addTotal) add_term(s + i, len);
separate_terms(s + i + 1, len - 2, 1);
i += len;
} break;
case ')': fprintf(stderr, "ERROR!\n"); return;
default: ++i;
}
}
}
void separate(char *s)
{
size_t lenTotal = strlen(s);
printf("Term: "); add_term(s, lenTotal);
separate_terms(s, lenTotal, 0);
}
int main(void)
{
// sample of OP:
separate("a*(b+(c+j)-h)*2 + (a+(b-c))");
}
Output:
Term: 'a*(b+(c+j)-h)*2 + (a+(b-c))'
'(b+(c+j)-h)'
'(c+j)'
'(a+(b-c))'
'(b-c)'
Notes:
OP stated that storage of results in lists (with appropriate management) is already solved. Hence, I used simple console output instead (in add_term()).
find_term() is simply counting opening and closing parentheses until the closing parenthesis corresponding to the first opening is found (success) or the string end is reached (error case).
separate_terms() is the recursive descent scanner to find sub-terms in a term.
It iterates over characters of input string. Every time an opening parenthesis (() is found, it calls find_term() to determine the length of sub-term and add the result. The found sub-term is analized recursively by calling itself recursively to the restricted length. Afterwards, the length of subterm is skipped because its fully analyzed now.
While fiddling with edge cases, I found out that my initial (significantly shorter) version reported a duplicated term when the complete input term was in parentheses (e.g. (a + b)). Hence, I added a flag addTotal to denote whether a found subterm shall be added if it has the total length of input.
separate() is rather short. It's just a wrapper to add a term for ful input and to perform the toplevel call of the recursive separate_terms(). (0 is passed for addTotal to prevent duplicate adding of complete input.)
I made some other samples which I considered as edge cases for my solution to check for potential bugs:
// valid edge cases:
separate(""); // valid?
separate("()"); // valid?
separate("a");
separate("(a + b)");
separate("(a + b) * 2");
separate("(a + b) * (c - d)");
separate("((a + b))");
// invalid cases:
separate("(");
separate("((");
separate(")");
separate("))");
separate("())(()");
separate("a(a(a");
separate("((a)))");
Output:
Term: ''
Term: '()'
Term: 'a'
Term: '(a + b)'
Term: '(a + b) * 2'
'(a + b)'
Term: '(a + b) * (c - d)'
'(a + b)'
'(c - d)'
Term: '((a + b))'
'(a + b)'
Term: '('
ERROR!
Term: '(('
ERROR!
Term: ')'
ERROR!
Term: '))'
ERROR!
Term: '())(()'
'()'
ERROR!
Term: 'a(a(a'
ERROR!
Term: '((a)))'
'((a))'
'(a)'
ERROR!
Live Demo on coliru

C language - turning input into code

Most of the times, the questions I ask have to do with a specific part of a code that i did incorrectly, or some bug that i overlooked, but this time, I don't know where to start. I don't even know if what I am trying to do is possible.
I was given an assignment to write a code that gets a string that resembles a variable declaration, for example int x,y; is a valid input. char c,*cptr,carray[80]; is another example of valid input.
The code will create what the user inputs, and will print how much memory it took.
For instance, in the first example (int x,y;) the code will create 2 integers, and print "x requires 4 bytes, y requires 4 bytes".
In the second example, the code will create a character, a pointer to a character, and a string with 80 characters, and will print "c requires 1 byte, cptr requires 4 bytes, carray requires 80 bytes"
Is this even possible? It is not valid code to declare variables after the beginning of the code. They must be declared before anything else in C. So I don't see a way to do this...
This is a parsing problem -- you need to parse the input string and figure out what it means. You don't need to actually "create" anything, you just need to figure out the sizes of the variables that the compiler would create for that code.
Parsing actually a very large subject, with lots of books written about it and tools written to make it easier. While you could use a tool like antlr or bison to complete this task, they're probably overkill -- a simple recursive descent hand-written parser is probably the best approach.
Something like:
const char *parse_declaration(const char *p) {
/* parse a declaration, printing out the names and sizes of the variables
* 'p' points at the beginning of the string containing the declaration, and the
* function returns the pointer immediately after the end or NULL on failure */
int size;
if (!(p = parse_declspecs(p, &size))) return 0;
do {
const char *name;
int namelen, declsize;
if (!(p = parse_declarator(p, size, &name, &namelen, &declsize))) return 0;
printf("%.*s requires %d bytes\n", namelen, name, declsize);
p += strspn(p, " \t\r\n"); /* skip whitespace */
} while (*p++ == ',');
if (p[-1] != ';') return 0;
return p;
}
const char *parse_declspecs(const char *p, int *size) {
/* parse declaration specifiers (a type), and output the size of that type
* p points at the string to be parsed, and we return the point after the declspec */
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) return 0;
int len = 0;
while (isalnum(p[len])) len++;
if (!strncmp(p, "char", len)) {
*size = sizeof(char);
return p+len; }
if (!strncmp(p, "int", len)) {
*size = sizeof(int);
return p+len; }
... more type tests here ...
if (!strncmp(p, "unsigned", len)) {
p += len;
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) {
*size = sizeof(unsigned);
return p; }
while (isalnum(p[len])) len++;
if (!strncmp(p, "int", len)) {
*size = sizeof(unsigned int);
return p+len; }
... more type tests here ...
}
return 0;
}
const char *parse_declarator(const char *p, int typesize, const char **name, int *namelen, int *declsize) {
/* parse a declarator */
p += strspn(p, " \t\r\n");
while (*p == '*') {
typesize = sizeof(void *); /* assuming all pointers are the same size...*/
p++;
p += strspn(p, " \t\r\n"); }
declsize = typesize;
if (isalpha(*p)) {
*name = p;
while (isalnum(*p) | *p == '_') p++;
*namelen = p - *name;
} else if (*p == '(') {
if (!(p = parse_declarator(p+1, typesize, name, namelen, declsize))) return 0;
p += strspn(p, " \t\r\n");
if (*p++ != ')') return 0;
} else
return 0;
p += strspn(p, " \t\r\n");
while (*p == '[') {
int arraysize, len;
if (sscanf(++p, "%d %n", &arraysize, &len) < 1) return 0;
p += len;
declsize *= arraysize;
if (*p++ != ']') return 0;
p += strspn(p, " \t\r\n"); }
return p;
}
should get you started...
If you are trying to execute input code dynamically, to my knowledge that would not be possible without storing the code and then compiling again. This however seems like a very nasty and lengthy approach. If all you are trying to do however is calculate the size of declarations from input, what I would do is take the string received, call a function that analyzes/decomposes the string. So for example if the string has "int", "char", etc.. I know would know what kind of declaration I am dealing with, and after I know what declaration I am dealing with I could just count the number of variables declared and keep a counter in your example it was x,y. I would a loop on the counter and calculate the sizeof the type of declaration and how many were declared.
Sure, it's possible; it's just a bit of work. You're going to have to study C declaration syntax, and then write the code to recognize it (basically a small compiler front end).
For example, in the declaration
char c, *cptr, carray[80];
you have a sequence of tokens:
char c , * cptr , carray [ 80 ] ;
which will be recognized as a type specifier (char) followed by three declarators; a direct declarator, a pointer declarator, and an array declarator.
You can create the space for the objects dynamically using malloc or calloc. Then you'll need to create some kind of table to map the identifier (the variable name) to the dynamically-created object. You won't be able to treat these things as regular variables in regular C code; you're going to be doing a lot of table lookups and dereferencing.
Sure, you could do this with a type of parser. Assuming that you do not want to actually execute the code that you are given, you could read the string and then count how many times a variable of each specific type is declared, and calculate the amount of memory thusly. But, depending on the requirements of the professor, you may run into a view different issues.
In particular, the sizes of different types will likely be different on each processor. With the exception of char, you need to account for this. This is easy if you are analyzing the memory requirements for the computer that your program is executing on, as you could just have const variables whose values are assigned via sizeof to get the sizes, but if not, your program is more difficult, especially since you cannot presume to know the size of any variable.
Secondly, structs will be a problem do to some of the more interesting rules of C. Do you need to account for them?
So, this is entirely possible, because contrary to what you stated in your question, your code doesn't have to "create" a variable at all - it can just create an in-memory total for each type and print them out when done.
Figured I would post my solution just incase anyone is interested
void* q5(char* str_in)
{
char runner;
int i=0,memory,counter=0,arr_size;
runner=str_in[i];
while(1)
{
if(runner=='i') //the input is integer
{
memory=sizeof(int);
break;
}
if(runner=='c') //input is char
{
memory=sizeof(char);
break;
}
if(runner=='d') //input is double
{
memory=sizeof(double);
break;
}
if(runner=='s') //input is short
{
memory=sizeof(short);
break;
}
if(runner=='l') //input is long
{
memory=sizeof(long);
break;
}
if(runner=='f') //input is float
{
memory=sizeof(float);
break;
}
} //we know the type of data, skip in the string until first variable
while(runner!=' ') //advance until you see empty space, signaling next variable
{
i++;
runner=str_in[i];
}
while(runner==' ') //advance until you encounter first letter of new variable
{
i++;
runner=str_in[i];
} //runner is now first letter of first variable
while(runner!=';') //run on the string until its over
{
if(runner==',') //if its ',', then spaces will occur, skip all of them to first char that isnt space
{
i++;
runner=str_in[i];
while(runner==' ')
{
i++;
runner=str_in[i];
} //runner now points to first letter of variable
continue;
}
if(runner=='*') //current variable is a pointer
{
counter=counter+4; //pointers are always 4 bytes regardless of type!
i++;
runner=str_in[i];
while((runner!=',')&&(runner!=';')) //while runner is still on this variable
{
printf("%c",runner);
i++;
runner=str_in[i];
}
printf(" requires 4 bytes\n"); //now runner is the first character after the variable we just finished
continue;
}
while((runner!=',')&&(runner!=';')) //now is the case that runner is the first letter of a non pointer variable
{
printf("%c",runner);
i++;
runner=str_in[i];
if((runner==',')||(runner==';')) //we are done
{
printf(" requires %d bytes\n",memory);
counter+=memory;
continue;
}
if(runner=='[') //this variable is an array
{
printf("[");
i++;
runner=str_in[i]; //runner is now MSB of size of array
arr_size=0;
while(runner!=']')
{
printf("%c",runner);
arr_size*=10;
arr_size=arr_size+runner-48; //48 is ascii of 0
i++;
runner=str_in[i];
} //arr_size is now whats written in the [ ]
printf("] requires %d bytes\n",arr_size*memory);
counter+=arr_size*memory;
i++;
runner=str_in[i]; // should be ',' since we just finished a variable
continue;
}
}
}
printf("Overall %d bytes needed to allocate\n",counter);
return (malloc(counter));
}

How to parse the given string into array of structure variable

P|20131120|20131120
C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|
C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|
C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|
C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|
P|20131121|20131121
C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|
C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|
C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|
Above is the message coming from one server as a single string. Now i want to parse it and store in a structure for the processing in C language.
Here for one P(Period) row, there can be many C(Class) rows. '|' is field delimiter which should be ignored while storing into the structure. Here the number of C(Class) rows are not fixed for a P.
Can anybody suggest me in C, how should i declare the Structures and parse and store these fields into it. As per my guess i will have to declare the structure array at run time for class(C) rows because it is not fixed. One thing is fixed: P(Period) row size is always 17 byte (or charector) excluding pipe(|) and C(Class) row size is 61 character excluding pipe(|. Dear All, can please anybody help me in C logic or code.
There are multiple parsing levels for this string
Use token as P/C for doing the first level of filtering
Use token as | as second level of filtering ( Inside which youi have H/Y etc which you need to take into consideration as well while copying it to structure members).
Accordingly you can have structure declartion .
You can visit this article strtok usage
Here you go -
struct node{
char startChar, endChar;
float numArr[8];
struct node *next;
}
struct headerNode{
int num1, num2;
struct node *first;
}
After that you can make use of
createList() //create a blank list with header node.
createNode() //a C node everytime you need it.
Rest is merely parsing the string.
I hope this will help.
struct c_struct
{
char c_content[61];
struct c_strcut *next_c_strcut; //pointer to next class
};
struct PC_struct
{
char p_content[17];
struct c_struct *c_head; // pointer to first node
struct PC_struct *PC_struct; // pointer to next pc
};
#include <stdio.h>
#include <string.h>
#define MAX_CLASSES 100
#define MAX_PERIODS 100
struct Class{
char a, i;
float b,c,d,e,f,g,h,j;
};
struct Period{
char date1[10], date2[10];
struct Class classes[MAX_CLASSES];
};
struct Period periods[MAX_PERIODS];
int main(void){
//use sscanf to parse the data
//for example, (assuming data is in char *s),
//sscanf(s, "P|%s|%s\n", periods[0].date1, periods[0].date2);
return 0;
}
The most critical part is safely parsing the input, after that, interpretation, validation and organization of the pre-structured data is a breeze, I made only the hard part (input handling) below
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *data =
"P|20131120|20131120\n"
"C|F|350.0|50.0|350.0|16.67|50.0|16.67|1400.0|Y|15.0|\n"
"C|H|610.3|87.19|610.3|29.06|87.19|29.06|2441.2|Y|15.0|\n"
"C|L|1386.0|198.0|1386.0|66.0|198.0|66.0|5544.0|Y|15.0|\n"
"C|Z|1286.0|183.71|1286.0|61.24|183.71|61.24|5144.0|Y|15.0|\n"
"\n"
"P|20131121|20131121\n"
"C|A|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
"C|B|323.65|46.24|323.65|15.41|46.24|15.41|1294.6|Y|15.0|\n"
"C|D|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
"C|E|365.65|52.24|365.65|17.41|52.24|17.41|1462.6|Y|15.0|\n"
;
struct columns
{
char *cols[12]; /* 16 pointers */
} rows[100]; /* bss, all zero */
#define N_COLS (sizeof(struct columns)/sizeof(char*))
#define N_ROWS (sizeof(rows)/sizeof(struct columns))
int main(void)
{
char *rowsdata, *s;
char **curcol = rows->cols;
char **lastcol = rows->cols + N_COLS;
int row, i;
rowsdata = s = strdup(data);
if (rowsdata == 0) {
perror("strdup");
exit(1);
}
for (row=0; row < N_ROWS; s++) {
if (*s == '|') {
*s = 0;
if (++curcol == lastcol) {
puts("error: too much columns");
exit(1);
}
} else if (*s == '\n') {
*s = 0;
row++;
curcol = (rows + row)->cols;
lastcol = (rows + row)->cols + N_COLS;
} else if (*curcol == 0) {
*curcol = s;
} else if (*s == 0) break;
}
/* do your logic here
*/
for (i=0; i<row; i++) {
curcol = (rows + i)->cols;
lastcol = (rows + i)->cols + N_COLS;
while (*curcol && curcol < lastcol) {
printf("[%s]", *curcol);
curcol++;
}
printf("\n");
}
/* free rowsdata only when done with rows
*/
free(rowsdata); rowsdata = 0;
return 0;
}
the code above relies heavily on pointer arithmetic
*edit: rename from 'cols' to 'rows' and 'cells' to 'cols', makes more sense

Initializing an infinite number of char **

I'm making a raytracing engine in C using the minilibX library.
I want to be able to read in a .conf file the configuration for the scene to display:
For example:
(Az#Az 117)cat universe.conf
#randomcomment
obj:eye:x:y:z
light:sun:100
light:moon:test
The number of objects can vary between 1 and the infinite.
From now on, I'm reading the file, copying each line 1 by 1 in a char **tab, and mallocing by the number of objects found, like this:
void open_file(int fd, struct s_img *m)
{
int i;
char *s;
int curs_obj;
int curs_light;
i = 0;
curs_light = 0;
curs_obj = 0;
while (s = get_next_line(fd))
{
i = i + 1;
if (s[0] == 'l')
{
m->lights[curs_light] = s;
curs_light = curs_light + 1;
}
else if (s[0] == 'o')
{
m->objs[curs_obj] = s;
curs_obj = curs_obj + 1;
}
else if (s[0] != '#')
{
show_error(i, s);
stop_parsing(m);
}
}
Now, I want to be able to store each information of each tab[i] in a new char **tab, 1 for each object, using the ':' as a separation.
So I need to initialize and malloc an undetermined number of char **tab. How can I do that?
(Ps: I hope my code and my english are good enough for you to understand. And I'm using only the very basic function, like read, write, open, malloc... and I'm re-building everything else, like printf, get_line, and so on)
You can't allocate an indeterminate amount of memory; malloc doesn't support it. What you can do is to allocate enough memory for now and revise that later:
size_t buffer = 10;
char **tab = malloc(buffer);
//...
if (indexOfObjectToCreate > buffer) {
buffer *= 2;
tab = realloc(tab, buffer);
}
I'd use an alternative approach (as this is c, not c++) and allocate simply large buffers as we go by:
char *my_malloc(size_t n) {
static size_t space_left = 0;
static char *base = NULL;
if (base==NULL || space_left < n) base=malloc(space_left=BIG_N);
base +=n; return base-n;
}
Disclaimer: I've omitted the garbage collection stuff and testing return values and all safety measures to keep the routine short.
Another way to think this is to read the file in to a large enough mallocated array (you can check it with ftell), scan the buffer, replace delimiters, line feeds etc. with ascii zero characters and remember the starting locations of keywords.

Appending a char to a char* in C?

I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}

Resources