I am using C to write a basic shell. The structure of the shell is pretty simple:
get input,
parse input,
exe the commemt.
To get the input, my professor requires to use getline(), so the type of return for my input is char *.
I pass the input to function parse_input(line) and use strtok() / strtok_r() to split the input. but I have problem here. I get null when I split. My professor requires me to use strtok() / strtok_r() to split. I have attached an image of my code here. I can split if I use char[] but here is char*. I don't know how to fix this.
char *parse_line(char *line){
int index = 0;
char *token;
// char **tokens = malloc(buffs * sizeof(char*));
//token = strtok_r(line,TOKEN_SPLIT,&line);
token = strtok(line, TOKEN_SPLIT);
printf("token: %s\n",token);
while(token != NULL){
// tokens[index++] = token;
printf(" %s\n", token);
token = strtok(NULL, TOKEN_SPLIT);
}
return token;
}
Related
I have a problem with regards to separating the contents of a string passed to a function. The function is called with a string like this:
ADD:Nathaniel:50
Where ADD will be the protocol name, Nathaniel will be the key, and 50 will be the value, all separated with a :.
My code looks like this:
bool add_to_list(char* buffer){
char key[40];
char value[40];
int* token;
char buffer_copy[1024];
const char delim[2] = ":";
strcpy(buffer_copy, buffer);
token = strtok(NULL, delim);
//strcpy(key, token);
printf("%d",token);
printf("%p",token);
while(token != NULL){
token = strtok (NULL, delim);
}
//strcpy(value, token);
printf("%s", key);
printf("%s", value);
push(key, value);
return true;
}
What I am trying to do is store each key and value in a separate variable, using strtok(). Note that I am trying to store the second and third values (Nathaniel and 50) not the first bit (ADD).
When I run the code, it gives me a segmentation fault, so I am guessing that I am trying to access an invalid memory address rather than a value. I just need to store the second and third bit of the string. Can anyone help please?
EDIT:
I have changed the code to look like this:
bool add_to_list(char* buffer){
char *key, *value, *token;
const char *delim = ":";
token = strtok(buffer, delim);
//printf("%d",token);
printf("%s",token);
key = strtok(NULL, delim);
value = strtok(NULL, delim);
printf("%s", key);
printf("%s", value);
//push(key, value);
return true;
}
But I am still getting the same segmentation fault (core dumped) error
The first call to strtok() needs to provide the string to scan. You only use NULL on the repeated calls, so it will keep processing the rest of the string. SO the first call should be:
token = strtok(buffer_copy, delim);
Then when you want to get the key and value, you need to copy them to the arrays:
token = strtok(NULL, delim);
key = strcpy(token);
token = strtok(NULL, delim);
value = strcpy(token);
You don't need a loop, since you just want to extract these two values.
Actually, you don't need to declare key and value as arrays, you could use pointers:
char *key, *value;
Then you can do:
token = strtok(buffer_copy, delim);
key = strtok(NULL, delim);
value = strtok(NULL, delim);
Your main problem is that when you first call strtok, the first parameter should be the string you want to parse, so not:
strcpy(buffer_copy, buffer);
token = strtok(NULL, delim);
but
strcpy(buffer_copy, buffer);
token = strtok(buffer_copy, delim);
Additionally when you detect the tokens in your while loop, you are throwing them away. You want to do something at that point (or simply unroll the loop and call strtok three times).
Also:
const char* delim = ":";
would be a more conventional way of ensuring a NUL terminated string than:
const char delim[2] = ":";
Also consider using strtok_r not strtok as strtok is not thread-safe and horrible. Whilst you are not using threads here (it seems), you might as well get into good practice.
I'm trying to make tokens from an input file. So, I get one line with fgets and feed it to a helper method that takes in a char* and returns a char* of the token. I am utilizing strtok() with delimiter as " " since the tokens are all separated by " ". But, I can't figure out why the code only makes 2 tokens per line and just moves on to the next line even though there is more in that line needed to be tokenized. Here is the code:
char *TKGetNextToken( char * start ) {
/* fill in your code here */
printf("Entered TKGetNextToken \n");
printf(&start[0]);
char* temp = &start[0];
//Delimiters for the tokens
const char* delim = " ";
//store tempToken
char* tempTok = strtok(temp, delim);
//return the token
return tempTok;
}
Here is how I'm storing the tokens in the main method:
//call get next token and get the token and store into temptok
while (temp!= NULL) {
tempTok = TKGetNextToken(temp);
printf("tempTok: %s\n",tempTok);
token.charPtr[tempNum] = tempTok;
tempNum++;
printf("Temp: %s\n",tempTok);
temp = strtok(NULL, " \0\n");
}
So, lets say I have a file.txt with:
abcd ef ghij asf32
fsadf ads adf
The tokens created would be "abcd" and "ef" and it will go on to the next line without making tokens for "ghij" and "asf32".
Use the proper syntax for strtok
char *tempTok = strtok(line, " "); //initialize
while (tempTok != NULL) {
//do the work
tempTok = strtok(NULL, " \n"); //update
}
If you do like above, then you can get the tokens quite easy. Please have a look at this example, which is similar to your code, just remember how you use strtok properly, then it will work. Look at strtok and how it is used in the loop, updating and consumes the char *.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *fp = fopen("data.txt", "r");
char line[256];
while (fgets(line, sizeof(line), fp)) {
char *tempTok = strtok(line, " ");
while (tempTok != NULL) {
printf("token %s\n", tempTok);
tempTok = strtok(NULL, " \n");
}
}
fclose(fp);
return 0;
}
File data.txt
abcd ef ghij asf32
fsadf ads adf
Output
./a.out
token abcd
token ef
token ghij
token asf32
token fsadf
token ads
token adf
Hi guys I'm currently using the code below and I'm pretty sure there's a better way to do it. What the code does is look if there's the delimiter (~~~~), puts everything before ~~~~ in cmd and everything after ~~~~ in param. If anyone could let me know how I should be doing this then it would be very appreciated! I'm not used to low-level languages so strings and pointers are still confusing to me!
Thanks!
char buffer[1024], *tempCharPointer, cmd[100], param[1024];
if(strstr(buffer, "~~~~"))
{
strcpy(cmd, buffer);
tempCharPointer = strstr(buffer, "~~~~");
index = (tempCharPointer-buffer) + 4;
strcpy(param, &tempCharPointer[4]);
memmove(&cmd[index-4], "", (index-4));
}
You can simplify your code as follows:
char cmd[1024], *tempCharPointer, *param = "";
// Fill in cmd from somewhere...
...
char *delim = strstr(cmd, "~~~~");
if(delim)
{
param = delim+4;
*delim = '\0';
}
You can simplify your code and insert \0 before the delimiter (modify the first character of the delimiter and make it \0) and have command be a pointer to the beginning of the string and param a pointer to the first character after the delimiter. Saves you memory and all these moves and such.
char buffer[1024], *tempCharPointer, cmd[100], param[1024];
tempCharPointer = strstr(buffer, "~~~~");
if (tempCharPointer){
*tempCharPointer = '\0';
tempCharPointer +=4;
//now buffer points to the first half, and tempCharPointer points to second half
//do with them what you will
}
The strtok function in the C library (extract tokens from strings) can be useful here.
A small example follows. man strtok for more info. Note that strtok_r (used below) is used for reentrant support.
#include <string.h>
#include <stdio.h>
int main(const int argc, const char const** argv)
{
char buffer[1024];
sprintf(buffer, "~~~~foo~~~~bar~~~~baz");
char* saveptr = NULL;
char* token = strtok_r(buffer, "~~~~", &saveptr);
while(token != NULL)
{
printf("TOKEN: %s\n", token);
token = strtok_r(NULL, "~~~~", &saveptr);
}
}
I'm trying to split a string into tokens but somewhat recursively. I am trying to parse:
"content=0&website=Google"
so that I have a way to take out the parameters and values. If I try strtok I end up destroying the string I want to parse twice. So I tried
char *contents = "content=0&website=Google"
char arg[100];
char value[100];
sscanf(contents, "%s&%s", arg, value);
as a first pass, hoping to parse arg again, but it fails, and arg contains the entire string. I tried using "%s\&%s" thinking & was a reserved word, but no luck there.
Help!
Edit:
This was my strtok hack:
static void readParams(char * string, char * param, char * value) {
printf("This is the string %s\n",string);
char * splitted = strtok (string,"=");
while (splitted != NULL)
{
printf("This is the string %s\n",splitted);
splitted = strtok (NULL, "=");
// Then do some saving to param and value
}
}
char * splitted = strtok (contents,"&");
int counter = 0;
while (splitted != NULL)
{
char * t_str = strdup(splitted);
readParams(t_str, param, value);
splitted = strtok (NULL, "&");
}
but it doesn't work because splitted's strtok at the end becomes gobbldygook.
Here is a solution that seems to work:
char *contents = "content=0&website=Google";
char arg[100] = {0};
char value[100] = {0};
sscanf(contents, "%[^&]&%s", arg, value);
printf("%s\n%s\n", arg, value);
scanf is more primitive than you seem to think — %s will match everything up to the next whitespace. Your best solution is probably to stick with strtok but throw it only content you've strduped from the authoritative original.
I recommend something similar to the following:
char t_str[100];
strncpy(t_str, contents, 100);
//now strtok() on t_str, original contents will be preserved
I'm using strtok() in c to parse a csv string. First I tokenize it to just find out how many tokens there are so I can allocate a string of the correct size. Then I go through using the same variable I used last time for tokenization. Every time I do it a second time though it strtok(NULL, ",") returns NULL even though there are still more tokens to parse. Can somebody tell me what I'm doing wrong?
char* tok;
int count = 0;
tok = strtok(buffer, ",");
while(tok != NULL) {
count++;
tok = strtok(NULL, ",");
}
//allocate array
tok = strtok(buffer, ",");
while(tok != NULL) {
//do other stuff
tok = strtok(NULL, ",");
}
So on that second while loop it always ends after the first token is found even though there are more tokens. Does anybody know what I'm doing wrong?
strtok() modifies the string it operates on, replacing delimiter characters with nulls. So if you want to use it more than once, you'll have to make a copy.
There's not necessarily a need to make a copy - strtok() does modify the string it's tokenizing, but in most cases that simply means the string is already tokenized if you want to deal with the tokens again.
Here's your program modified a bit to process the tokens after your first pass:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i;
char buffer[] = "some, string with , tokens";
char* tok;
int count = 0;
tok = strtok(buffer, ",");
while(tok != NULL) {
count++;
tok = strtok(NULL, ",");
}
// walk through the tokenized buffer again
tok = buffer;
for (i = 0; i < count; ++i) {
printf( "token %d: \"%s\"\n", i+1, tok);
tok += strlen(tok) + 1; // get the next token by skipping past the '\0'
tok += strspn(tok, ","); // then skipping any starting delimiters
}
return 0;
}
Note that this is unfortunately trickier than I first posted - the call to strspn() needs to be performed after skipping the '\0' placed by strtok() since strtok() will skip any leading delimiter characters for the token it returns (without replacing the delimiter character in the source).
Use strsep - it actually updates your pointer. In your case you would have to keep calling NULL versus passing in the address of your string. The only issue with strsep is if it was previously allocated on the heap, keep a pointer to the beginning and then free it later.
char *strsep(char **string, char *delim);
char *string;
char *token;
token = strsep(&string, ",");
strtok is used in your normal intro to C course - use strsep, it's much better. :-)
No getting confused on "oh shit - i have to pass in NULL still cuz strtok screwed up my positioning."