I'm working on a client-server program, where initial step involves parsing the request from client on the server side. The input would look like this.
INSERT A->B B->C; QUERY A B; RESET;
So there are three different commands and they are separated by ';'. RESET option has no parameters. INSERT might have any number of parameter(which are space separated and each value separated by "->"). QUERY is again space separated. The server has to build a acyclic graph based on the input. So my problem is to parse this string into subsequent requests. I planned on using 'strtok' and when the final value is reached(for example 'A'), create a linked list of INSERTS(since the number of request is unknown). But my code is too big and I'm looking for a more concise solution for this problem.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct insert {
char event1;
char event2;
struct insert * next;
}insert,*insPtr;
typedef struct query {
char event1;
char event2;
struct query * next;
}query,*queryPtr;
typedef struct reset {
int status;
}reset,*rPtr;
void create_node(char *events) {
char event[2];
char *a,*str;
char *pch = strtok(events,"->");
while(pch != NULL) {
printf("%s\n",pch);
pch = strtok(NULL,"->");
}
}
int insert_parser(char *string) {
char *a, *b;
a = string;
b = "INSERT ";
while(*a == *b){
a++;
b++;
}
char *pch = strtok(a," ");
while(pch){
printf("%s\n",pch);
pch = strtok(NULL," ");
}
return(0);
}
int parse_for_values (char* command) {
int value;
if (strstr(command, "INSERT") !=NULL ) {
printf("%s\n",command);
printf ("Insert command found\n");
value = 1;
} else if(strstr(command, "QUERY") !=NULL) {
printf("%s\n",command);
printf ("Query command found\n");
value = 2;
} else if(strstr(command, "RESET") != NULL) {
printf ("Reset command found\n");
printf("%s\n",command);
value = 3;
} else {
printf("unknown command:%s:\n",command);
printf("Unknown command\n");
return(1);
}
switch(value) {
case 1:
insert_parser(command);
break;
case 2:
break;
case 3:
break;
}
return(0);
}
int parse_for_command(char *input) {
char *ptr;
input = strtok(input,"\n");// this strtok is to remove the trailing '\n' in the string
ptr = strtok(input,";");
// printf("%s\n",ptr);
char *cmdPtr;
while(ptr != NULL) {
cmdPtr = ptr;
parse_for_values(cmdPtr);
// printf("%s",ptr);
ptr = strtok(NULL, ";"); //NULL as first argument tells strtok to work on internally held value
}
return(0);
}
int main() {
char input[100];
printf("Enter the input\n");
fgets(input, 100, stdin);
//printf("%s",input);
char *inp = input;
inp = strtok(inp,"\n");
create_node(inp);
//parser(input,"INSERT ", "->");
//parse_for_command(input);
return(0);
}
You have to find individual tokens (lexical analysis) and analyse this sequence of tokens (syntactic analysis). Either you write these procedures manually, or you formally specify syntax of your language and employ existing tools to create the required C code automatically (see flex and bison).
I'm not 100% clear on what you are asking, but the separation of the input commands into individual strings can be done with a single set of calls to strtok. Additionally, the time to remove the trailing newline resulting from the call to fgets is immediately after the call to fgets so you do not have dangling newlines hanging off the end of the string. (e.g.):
fgets(input, 100, stdin);
len = strlen (input); /* get length of str */
if (input[len - 1] != '\n') /* no '\n', input too long */
input[--len] = 0; /* null-terminate */
Separating the strings with strtok can make use of a for loop to handle the initial and subsequent calls to NULL in a single call. For purposes of the example, I've just used a statically declared character array to hold the separated strings, but you can just as well pass p to whatever type list or abstraction you desire. If your intent was to further separate the individual components of each command, then a simple while loop walking a pointer (or two) down the separated INSERT or QUERY command will work. Below is the example, if your intent was different, please let me know.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCMD 10
#define LCMD 64
int main (void) {
char input[] = "INSERT A->B B->C; QUERY A B; RESET;";
char command[NCMD][LCMD] = {{0}};
char *p = NULL;
size_t i = 0;
size_t ncmd = 0;
for (p = strtok (input, ";"); p; p = strtok (NULL, ";")) {
while (*p == ' ') p++;
strncpy (command[ncmd++], p, LCMD);
}
printf ("\n The separated commands are:\n\n");
for (i = 0; i < ncmd; i++)
printf (" command[%zu] : %s\n", i, command[i]);
printf ("\n");
return 0;
}
Output
$ ./bin/parseinput
The separated commands are:
command[0] : INSERT A->B B->C
command[1] : QUERY A B
command[2] : RESET
Note: the length validation on p as well as the limit check on ncmd were intentionally omitted for purposes of the example.
Related
Whenever a word from wordlist passes as a valid word, strcat(code,wordlist[i]) is called to add the word to world list.
So if at the first line "am" is put, code=am.
Or if abhcgmsopa bqcedpwon abmnpc abcdponm dfajbbmmn cabnmo is put at the first line, the three corresponding valid words are put.
However at the second line the values in code get overwritten and extra characters are put, even though code is initialized outside the while-loop and strcat should append the values to the end of code. Then when the while-loop ends, code is replaced by the entirely by "xq", where x was the first letter put into code and q is from "quitting".
Code isn't reinitialized or changed aside from what is appended to it.
How can I prevent this?
Thanks
*Edit: I defined some stack functions before the main but edited it out here to minimize the code
int main(int argc, char const *argv[])
{
char input[300];
char code[]="";
int ci;
/* set up an infinite loop */
while (1)
{
//break;
/* get line of input from standard input */
printf ("\nEnter input to check or q to quit\n");
fgets(input, 300, stdin);
/* remove the newline character from the input */
int i = 0;
while (input[i] != '\n' && input[i] != '\0')
{
i++;
}
input[i] = '\0';
/* check if user enter q or Q to quit program */
if ( (strcmp (input, "q") == 0) || (strcmp (input, "Q") == 0) )
break;
/*Start tokenizing the input into words separated by space
We use strtok() function from string.h*/
/*The tokenized words are added to an array of words*/
char delim[] = " ";
char *ptr = strtok(input, delim);
int j = 0 ;
char *wordlist[300];
while (ptr != NULL)
{
wordlist[j++] = ptr;
ptr = strtok(NULL, delim);
}
/*Run the algorithm to decode the message*/
//j=words in line;i=i-th word we are evaluating
//k=k-th letter in i-th word
stack1 st;
for(int i=0;i<j;i++){
//stack1 st;
init(&st);
for(int k=0;k<strlen(wordlist[i]);k++){
if((int)wordlist[i][k]<101 && (int)wordlist[i][k]>96){ //check if this letter is a/b/c/d with ascii
push(&st,&wordlist[i][k]);
printf("%c added\n",st.ptr[st.inUse-1]);
}
else{
if(wordlist[i][k]==top(&st)+12){ //check if letter is m/n/o/p corresponding to a/b/c/d from top()
pop(&st);
}
}
}
if(is_empty(&st)){
printf("%s is valid\n",wordlist[i]);
strcat(code,wordlist[i]);
strcat(code," ");
}
else{
printf("%s is invalid\n",wordlist[i]);
clear(&st);
}
printf("code:%s\n",code);
}
printf("code after loop: %s",code);
}
printf("code: %s\n",code);
for(int i=0;i<300;i++){
if ((int)code[i]<101 && (int)code[i]>96){
printf("%c",code[i]);
}
if(!((int)code[i]<96+26 && (int)code[i]>96)){
printf(" ");
}
}
printf("code:%s",code);
printf ("\nGoodbye\n");
return 0;
}
The problem is that your code variable is an array of 1 character! This line:
char code[]="";
declares it as an empty string (no characters) plus a null terminator.
You need to assign it as an array big enough to hold the maximum possible answer! If this is, say, 500, then use this:
char code[500]="";
I am having issues when it comes to concatenating these two pointer strings together, below is my concatenating function, I am supposed to take string 1 and add it to string 2. Also I cannot use any functions in the string library, that's the point of this is to help us understand what code is actually in the functions by writing it ourself.
char strconcat(char *user2p, char *user1p) {
while (*user2p) {
user2p++;
}
while (*user1p) {
*user2p = *user1p;
*user2p++;
*user1p++;
}
*user2p = '\0';
printf("test: %c", *user2p);
return *user2p;
}
And here is the part of my main that is relevant to the function.
int main() {
char userString1[21], userString2[21];
char *user1p, *user2p;
user1p = userString1;
user2p = userString2;
printf("Please enter the first string: ");
gets(userString1);
printf("Please enter the second string: ");
gets(userString2);
printf("String 1 after concatenation: ");
puts(userString1);
printf("String 2 after concatenation: %c\n", strconcat(user2p, user1p));
The terminal keeps giving me this, I didn't include the code for the length and alphabetical order. It gives me a null when I try to run the test printf in the function and it gives me nothing when I return the function. I'm at a loss and any help is much appreciated!
Please enter the first string: jackhammer
Please enter the second string: jacky
The length of string 1 is: 10
The length of string 2 is: 5
String 1 comes before string 2 alphabetically.
String 1 after concatenation: jackhammer
(null)
String 2 after concatenation:
Your concat algorithm is fine, but you have to return a pointer to the original [leftmost] value, so your function needs to save it before looping:
char *
strconcat(char *user2p, char *user1p)
{
char *orig2p = user2p;
while (*user2p) {
user2p++;
}
while (*user1p) {
*user2p = *user1p;
user2p++;
user1p++;
}
*user2p = '\0';
printf("test: %s\n", orig2p);
return orig2p;
}
UPDATE:
To come up with a completely bulletproof test program for the concat function, we can use [overly] large input buffers and clip the input length to a maximum of 1/2 of the target buffer.
gets strips the newline but fgets does not. So, I've created an xgets function that is similar to gets but uses fgets and strchr to get [nearly] the same effect.
Although I believe it's okay to use standard string functions as part of the test code, I've created a hand coded version of strchr [hope that's not your next assignment :-)].
Anyway, here's the full program:
#include <stdio.h>
char *
strconcat(char *user2p, char *user1p)
{
char *orig2p = user2p;
while (*user2p) {
user2p++;
}
while (*user1p) {
*user2p = *user1p;
*user2p++;
*user1p++;
}
*user2p = '\0';
printf("test: %s\n", orig2p);
return orig2p;
}
char *
xstrchr(char *buf,int chrwant)
{
int chrcur;
char *res = NULL;
for (chrcur = *buf++; chrcur != 0; chrcur = *buf++) {
if (chrcur == chrwant) {
res = buf - 1;
break;
}
}
return res;
}
char *
xgets(char *buf,int maxlen)
{
char *cp;
char *res;
res = fgets(buf,maxlen,stdin);
if (res != NULL) {
cp = xstrchr(buf,'\n');
if (cp != NULL)
*cp = 0;
}
return res;
}
#define MAXLEN 800
int
main(void)
{
char userString1[MAXLEN], userString2[MAXLEN + 1];
char *user1p, *user2p;
printf("Please enter the first string: ");
user1p = xgets(userString1,MAXLEN / 2);
printf("Please enter the second string: ");
user2p = xgets(userString2,MAXLEN / 2);
if ((user2p != NULL) && (user1p != NULL))
printf("String 2 after concatenation: %s\n",strconcat(user2p, user1p));
return 0;
}
There's a number of issues. First is this.
while (*user1p) {
*user2p = *user1p;
*user2p++;
*user1p++;
}
This is working by accident. If you have compiler warnings on you should get a warning...
test.c:13:9: warning: expression result unused [-Wunused-value]
*user2p++;
^~~~~
test.c:14:9: warning: expression result unused [-Wunused-value]
*user1p++;
^~~~~~~
The reason it's unused is because C is interpreting it like so:
*(user1p++)
Increment the pointer, then dereference it. You just want to increment the pointers, no dereferencing required.
while (*user1p) {
*user2p = *user1p;
user2p++;
user1p++;
}
Then down here.
printf("String 2 after concatenation: %c\n", strconcat(user2p, user1p));
%c prints an individual char. You want %s which prints a char *. This reveals you have the wrong signature. strconcat should return a char * (ie. what C uses for strings) and return user2p (a char *).
char *strconcat(char *orig_to, const char *from) {
...
return user2p;
}
And since you're not changing from it should be const char * to let the compiler know and warn you if its accidentally changed.
Finally, when you return *user2p it's already been moved to the end of the string.
while (*user1p) {
*user2p = *user1p;
user2p++;
user1p++;
}
*user2p = '\0';
printf("test: %c", *user2p);
// This points to the null byte just set above
return user2p;
So printing the result of strconcat will print nothing. To get around this, store the original pointer for user2p and return that.
char *strconcat(char *orig_to, const char *from) {
char *orig_user2p = user2p;
...
return orig_user2p;
}
And some tips. It's easier to follow the code with good variable names that describe what they're doing.
char *strconcat(char *orig_to, const char *from) {
char *to = orig_to;
...
}
char foo[NN] already makes foo a pointer. There's no need to declare separate char * variables and copy the pointer.
char from[21], to[21];
Never use gets. There's no limit to how much memory it can use and it can easily overflow your buffer. Use fgets which can limit how much can be read to available memory.
printf("Please enter the string to concat from: ");
fgets(from, sizeof(from), stdin);
Though it's annoying that it keeps the newline and there's no simple function to strip it. You can use scanf which will strip whitespace, but beware its many pitfalls.
printf("Please enter the string to concat from: ");
scanf("%20s", from);
printf("Please enter the string to concat to: ");
scanf("%20s", to);
Finally, be sure the string you're concatenating to can hold its own contents and the new contents.
char from[21], to[41];
printf("Please enter the string to concat to: ");
// Be sure to leave enough room in `to` to fit `from`.
fgets(to, sizeof(to) - sizeof(from), stdin);
I would have created a more dynamic memory model. This code is more generic and concatenates strings creating a new string containing both strings.. Free when done :-)...
char *strconcat(char *string1, char *string2) {
int lenStr1=0,lenStr2=0;
char *tmpStr1=string1,*tmpStr2=string2,*returnStr;
while (*tmpStr1++)lenStr1++;
while (*tmpStr2++)lenStr2++;
if((returnStr=(char *)malloc(lenStr1+lenStr2+1))){
memcpy(returnStr,string1,lenStr1);
memcpy(&returnStr[lenStr1],string2,lenStr2);
returnStr[lenStr1+lenStr2]=0;
return returnStr;
} else {
return 0;
}
}
int main() {
char *string1="String 1 ",*string2="String 2 ",*result;
if((result=strconcat(string1, string2))) {
printf("-> %s \n",result);
free(result);
} else {
printf("Out of memory");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I am trying to split a string into two tokens using strtok() that might have spaces and tabs mixed in the string.
So I made this:
struct strstr
{
char *str,
*one,
*two;
};
typedef struct strstr *STRSTR;
void split(STRSTR);
int main()
{
STRSTR str = malloc(sizeof(struct strstr));
str->str = malloc(256);
fgets(str->str, 256, stdin);
split(str);
printf("%s, %s\n", str->one, str->two);
free(str->str);
free(str);
return 0;
}
void split(STRSTR str)
{
int i;
char *temp = str->str;
while(isspace(*(str->str)))
str->str++;
str->one = strtok(str->str, " \t");
for(i = 0; i < strlen(str->one); i++)
{
if(!isspace(str->one[i]))
str->str++;
}
str->str++;
if(str->str != NULL)
{
puts("In null if");
str->two = strtok(str->str, "");
}
str->str = temp;
}
So for example if you input Hello Earth lingss, it will print out Hello, Earth lingss, which is perfect.
However, if I input Hello only, the split function goes inside the if(str->str != NULL) statement. How do I stop it from doing that with the code that I have?
EDIT: Also another problem, if someone doesn't mind checking it out. temp will only point to the first word in str->str. How can I make it point to the whole thing?
Add this statement before the last if block in the split function
str->str = strtok(str->str," \t"); like
str->str = strtok(str->str," \t");
if(str->str != NULL)
{
puts("In null if");
str->two = strtok(str->str, "");
}
you split the string based on the "\t" as the delimiter but you never changed the str->str string, use the above snippet and it should work fine
strtok is a funny function that both modifies the string you pass it, and stores information about it internally. You should pass your string to strtok once, then pass in NULL on subsequent calls. For instance, if your goal is to simply break a string up into tokens (which is obviously what strtok is for), then something like:
#define BUFFER_SIZE 256
int main(void) {
char *buffer = malloc(BUFFER_SIZE);
if (!buffer) {
return -1;
}
fgets(buffer, BUFFER_SIZE, stdin);
char *word;
char *ptr = buffer;
printf("Tokens: [");
while ((word = strtok(ptr, " \t\n"))) {
printf("%s, ", word);
ptr = NULL;
}
printf("]\n");
free(buffer);
}
will work. When I run the code like this:
./quick
when in the fun apple orange
I get the following result:
Tokens: [when, in, the, fun, apple, orange, ]
The important thing is that I only passed the buffer pointer to strtok on the first time through the loop. After that it is passed NULL.
The input text file has some numbers per line, numbers are split by space. The first two lines only got one number, and the following lines got three. What I want to do is read each line of the input and store these numbers.
This is what I've got so far:
int
main(int argc, char *argv[]) {
int n = 0;
char buff[MAX_STRING_LEN]; //MAX_STRING_LEN is defined as 64
while (fgets(buff,MAX_STRING_LEN, stdin) != NULL) {
char temp;
if (n == 0) {
sscanf(buff, "%s", &temp);
int h_num = (int)temp;
} else if (n == 1) {
sscanf(buff, "%s", &temp);
int s_num = (int)temp;
} else {
sscanf(buff, "%s", &temp);
char *token;
token = strtok(&temp, " ");
int i = 0;
int a,b,c;
while (token != NULL) {
if (i == 0) {
a = (int)token;
token = strtok(NULL, " ");
} else if (i == 1) {
b = (int)token;
token = strtok(NULL, " ");
} else {
c = (int)token;
token = strtok(NULL, " ");
}
i++;
}
}
n++;
}
return 0;
}
The print statement I used to test my code is like:
printf("%d\n",h_num);
printf("%d\n%d\n%d\n",a,b,c);
I created a text file like this:
23
34
4 76 91
but the output is not what I expected, it's the address of the pointer I think. (I'm stuck with pointer again =( )
Could someone help me to point out what the problem is? Appreciate it.
In your code, I can see,
int h_num = (int)temp;
and
int s_num = (int)temp;
No, that is not how you convert an aphanumeric string to int.
You need to use strtol() for this purpose.
Then,
sscanf(buff, "%s", &temp);
is wrong. temp is a char, you got to use %c for that.
My suggestion for a better approach:
Read a complete line from file using fgets()
tokenize the input using strtok(), using space () as delimiter, then convert the token (if not NULL) to int using strtol()
continue untill the returned token is NULL
In this case, your code will be much more generic, as don't need to bother seperately about the number of ints present in each line.
I'm building a linked list and need your assistance please as I'm new to C.
I need to input a string that looks like this: (word)_#_(year)_#_(DEFINITION(UPPER CASE))
Ex: Enter a string
Input: invest_#_1945_#_TRADE
Basically I'm looking to build a function that scans the DEFINITION and give's me back the word it relates to.
Enter a word to search in the dictionary
Input: TRADE
Output: Found "TREADE" in the word "invest"
So far I managed to come up using the strtok() function but right now I'm not sure what to do about printing the first word then.
Here's what I could come up with:
char split(char words[99],char *p)
{
p=strtok(words, "_#_");
while (p!=NULL)
{
printf("%s\n",p);
p = strtok(NULL, "_#_");
}
return 0;
}
int main()
{
char hello[99];
char *s = NULL;
printf("Enter a string you want to split\n");
scanf("%s", hello);
split(hello,s);
return 0;
}
Any ideas on what should I do?
I reckon that your problem is how to extract the three bits of information from your formatted string.
The function strtok does not work as you think it does: The second argument is not a literal delimiting string, but a string that serves as a set of characters that are delimiters.
In your case, sscanf seems to be the better choice:
#include <stdlib.h>
#include <stdio.h>
int main()
{
const char *line = "invest_#_1945 _#_TRADE ";
char word[40];
int year;
char def[40];
int n;
n = sscanf(line, "%40[^_]_#_%d_#_%40s", word, &year, def);
if (n == 3) {
printf("word: %s\n", word);
printf("year: %d\n", year);
printf("def'n: %s\n", def);
} else {
printf("Unrecognized line.\n");
}
return 0;
}
The function sscanf examines a given string according to a given pattern. Roughly, that pattern consists of format specifiers that begin with a percent sign, of spaces which denote any amount of white-space characters (including none) and of other characters that have to be matched varbatim. The format specifiers yield a result, which has to be stored. Therefore, for each specifier, a result variable must be given after the format string.
In this case, there are several chunks:
%40[^_] reads up to 40 characters that are not the underscore into a char array. This is a special case of reading a string. Strings in sscanf are really words and may not contain white space. The underscore, however, would be part of a string, so in order not to eat up the underscore of the first delimiter, you have to use the notation [^(chars)], which means: Any sequence of chars that do not contain the given chars. (The caret does the negation here, [(chars)] would mean any sequence of the given chars.)
_#_ matches the first delimiter literally, i.e. only if the next chars are underscore hash mark, underscore.
%d reads a decimal number into an integer. Note that the adress of the integer has to be given here with &.
_#_ matches the second delimiter.
%40s reads a string of up to 40 non-whitespace characters into a char array.
The function returns the number of matched results, which should be three if the line is valid. The function sscanf can be cumbersome, but is probably your best bet here for quick and dirty input.
#include <stdio.h>
#include <string.h>
char *strtokByWord_r(char *str, const char *word, char **store){
char *p, *ret;
if(str != NULL){
*store = str;
}
if(*store == NULL) return NULL;
p = strstr(ret=*store, word);
if(p){
*p='\0';
*store = p + strlen(word);
} else {
*store = NULL;
}
return ret;
}
char *strtokByWord(char *str, const char *word){
static char *store = NULL;
return strtokByWord_r(str, word, &store);
}
int main(){
char input[]="invest_#_1945_#_TRADE";
char *array[3];
char *p;
int i, size = sizeof(array)/sizeof(char*);
for(i=0, p=input;i<size;++i){
if(NULL!=(p=strtokByWord(p, "_#_"))){
array[i]=p;//strdup(p);
p=NULL;
} else {
array[i]=NULL;
break;
}
}
for(i = 0;i<size;++i)
printf("array[%d]=\"%s\"\n", i, array[i]);
/* result
array[0]="invest"
array[1]="1945"
array[2]="TRADE"
*/
return 0;
}