I am trying to process a character string in order to change something in a file. I read from a file a character string which contains a command and an argument, separated by a space character. I separated this array in tokens.
Now I want to pass the second token, which is the argument to a function. My problem is that when I run my program, the screen freezes and nothing happens. Here is my separating way and the call to the function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void create_file(char *argument)
{
//some code goes here
}
int main()
{
int i = -1;
char *token[5];
char command[20];
const char delim[1] = " ";
FILE *fin;
fin = fopen("mbr.op", "r");
while(fscanf(fin, "%[^\n]", command) == 1)
{
i = -1;
token[++i] = strtok(command, delim);
while(token[i] != NULL)
token[++i] = strtok(NULL, delim);
if(strcmp(token[0], "CREATE_FILE") == 0)
create_file(token[1]);
}
fclose(fin);
return 0;
}
You have a few errors, first command[20] is an uninitialised string and that will cause undefined behaviour. Second, you failed to check the first arg as well as the second, so I added a test where commented. Also, the strings are not long enough so I removed the length. Lastly I test for a NULL pointer passed to the function.
Edit code was added to the question to show that command[20] was initialised, but it is still too short to take the command and a reasonable file name (thanks to #ameyCU).
#include <stdio.h>
#include <string.h>
void create_file(char *argument)
{
if(argument == NULL)
printf("NULL pointer\n");
else
printf("Arg: %s\n", argument);
}
int main(void)
{
int i = -1;
char *token[5];
char command[] = "CREATE_FILE myfile.txt";
const char delim[] = " ";
token[++i] = strtok(command, delim);
while(token[i] != NULL)
token[++i] = strtok(NULL, delim);
if(token[0] != NULL && strcmp(token[0], "CREATE_FILE") == 0) // added test
create_file(token[1]);
return 0;
}
Program output
Arg: myfile.txt
The first error is present in array definition:
const char delim[1] = " ";
In C "" is a string - an array of characters delimited by '\0'. This means that what stands to the right of "=" is a string of two chars:
// ' ' + '\0'
//0x20 0x00
Therefore this should be an array of two chars:
const char delim[2] = " ";
or
const char delim[] = " ";
Related
I'm doing a project for school and I need to read from an .INI file to start my vars for the game. Problem is, I cannot seem to understand how strtok works and I'm really confused at this point.
I know I'm returning an empty struct because I have no idea how to put the specific values into the vars!
Here's my read_from_config.h
#ifndef READ_FROM_CONFIG_H
#define READ_FROM_CONFIG_H
#define MAXSTR 500
typedef struct {
unsigned int xdim;
unsigned int ydim;
unsigned int nzombies;
unsigned int nhumans;
unsigned int nzplayers;
unsigned int nhplayers;
unsigned int turns;
} CONFIG;
CONFIG read_config(char *argv[]);
#endif
And here is my read_from_config.c
#include "read_from_config.h"
#include "example.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
CONFIG read_config(char *argv[]) {
char str[MAXSTR];
FILE *fp = NULL;
char *filename = argv[1];
char *token;
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Não foi possível abrir ficheiro de configuração.");
fprintf(stderr, "\nModo de uso: ./program_name config.ini");
}
while (fgets(str, MAXSTR, fp) != NULL) {
for (int i = 0; i != '\0'; i++) {
char *equal = strpbrk (str, "=");
if (equal) {
token = strtok(str, "=");
}
}
}
printf("%d", token[0]);
CONFIG config;
return config;
}
CONFIG.INI
; Dimension of the grid
xdim=20
ydim=20
; Inicial number of zombies and humans
nzombies=20
nhumans=20
; Number of zombies and humans controlled by players
nzplayers=0
nhplayers=1
; Number of maximum turns
maxturns=1000
The function strtok take a string only the first time it gets called. All
subsequent calls must be passed with NULL
man strtok
#include <string.h>
char *strtok(char *str, const char *delim);
DESCRIPTION
The strtok() function breaks a string into a sequence of zero or more nonempty tokens.
On the first call to strtok(), the string to be parsed should be specified in str.
In each subsequent call that should parse the same string, str must be NULL.
Example:
char line[] = "a,b,c,d,e,f\n"; // to simulate an fgets line
char *token = strtok(line, ",\n"); // you can add \n to the separator
// to get rid of the \n at the end
puts(token); // prints a
while(token = strtok(NULL, ",\n"))
puts(token); // prints b then c etc..
Keep in mind that strtok modifies the source, this is going to fail:
strtok("a,b,c", ",");
because string literals are not modifiable. In that case you have to make a copy
to a char[] or a dynamic allocated char*.
If you need to have the source intact after the parsing, then you definitively
need to make a copy.
In your code you do:
printf("%d", token[0]);
That's not incorrect but perhaps not what you want to do. This line doesn't
print the first character, it prints the ascii value of the first character.
This
printf("%c", token[0]);
will print the first character.
Also you are doing
CONFIG read_config(char *argv[]) {
...
CONFIG config;
return config;
}
You are returning an uninitialized CONFIG object, you are ignoring the parsing
and nothing is set in your config object.
Your parsing is also a little bit strange.
for (int i = 0; i != '\0'; i++)
The loop exits immediately because 0 == '\0'! I don't understand what you are
trying to do with it.
I would first create a helper function to populate the values of the config, see
set_config_val. Then you can parse it like this:
CONFIG read_config(char *argv[]) {
...
const char *delim = "=\n";
CONFIG config;
while (fgets(str, MAXSTR, fp) != NULL) {
if(strchr(str, '='))
{
char varname[100];
int value;
token = strtok(line, delim);
strcpy(varname, token);
token = strtok(NULL, delim);
value = atoi(token);
set_config_val(&config, varname, value);
} else {
fprintf(stderr, "Skipping line, no = found");
}
}
fclose(fp);
return config;
}
void set_config_val(CONFIG *config, const char *key, int val)
{
if(config == NULL)
return;
if(strcmp(key, "xdim") == 0)
config->xdim = val;
else if(strcmp(key, "ydim") == 0)
config->ydim = val;
...
}
I'm trying to write a string spliter function in C.It uses space as delimiter to split a given string in two or more. It more like the split funtion in Python.Here is the code:-
#include <stdio.h>
#include <string.h>
void slice_input (char *t,char **out)
{
char *x,temp[10];
int i,j;
x = t;
j=0;
i=0;
for (;*x!='\0';x++){
if (*x!=' '){
temp[i] = *x;
i++;
}else if(*x==' '){
out[j] = temp;
j++;i=0;
}
}
}
int main()
{
char *out[2];
char inp[] = "HEllo World ";
slice_input(inp,out);
printf("%s\n%s",out[0],out[1]);
//printf("%d",strlen(out[1]));
return 0;
}
Expeted Output:-
HEllo
World
but it is showing :-
World
World
Can you help please?
out[j] = temp;
where temp is a local variable. It will go out of scope as soon as your function terminates, thus out[j] will point to garbage, invoking Undefined Behavior when being accessed.
A simple fix would be to use a 2D array for out, and use strcpy() to copy the temp string to out[j], like this:
#include <stdio.h>
#include <string.h>
void slice_input(char *t, char out[2][10]) {
char *x, temp[10];
int i,j;
x = t;
j=0;
i=0;
for (;*x!='\0';x++) {
if (*x!=' ') {
temp[i] = *x;
i++;
} else if(*x==' ') {
strcpy(out[j], temp);
j++;
i=0;
}
}
}
int main()
{
char out[2][10];
char inp[] = "HEllo World ";
slice_input(inp,out);
printf("%s\n%s",out[0],out[1]);
return 0;
}
Output:
HEllo
World
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
From the website:
char * strtok ( char * str, const char * delimiters ); On a first
call, the function expects a C string as argument for str, whose first
character is used as the starting location to scan for tokens. In
subsequent calls, the function expects a null pointer and uses the
position right after the end of last token as the new starting
location for scanning.
Once the terminating null character of str is found in a call to
strtok, all subsequent calls to this function (with a null pointer as
the first argument) return a null pointer.
Parameters
str C string to truncate. Notice that this string is modified by being
broken into smaller strings (tokens). Alternativelly [sic], a null
pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
delimiters C string containing the delimiter characters. These may
vary from one call to another. Return Value
A pointer to the last token found in string. A null pointer is
returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
You can use this function to split string into tokens - there is no need to use some own functions. Your code looks like garbage, please format it.
Your source propably would look like this:
char *
strtok(s, delim)
char *s; /* string to search for tokens */
const char *delim; /* delimiting characters */
{
static char *lasts;
register int ch;
if (s == 0)
s = lasts;
do {
if ((ch = *s++) == '\0')
return 0;
} while (strchr(delim, ch));
--s;
lasts = s + strcspn(s, delim);
if (*lasts != 0)
*lasts++ = 0;
return s;
}
I'm currently writing a primitive shell that lets user input few basic commands: ls, cat etc. I'm taking from the user an input like: ls /home/someUser/someDirectory and storing this in a character array, say input. I've written a few little such functions ls, cat etc. that take an argument and print to stdout the expected result.
What I'd like to know is: what would be the best way to break this input up into a command and argument? For the said example, I'd like to get two different chunks: ls and /home/someUser/someDirectory, so that I can check what command the user wants to execute with what argument. Sure, I can maintain pointers and check the first few characters of the array and compare them and then proceed to the character after whitespace and parse the argument accordingly, but that would be very tedious and inefficient. Is there a better way to do this, possibly an in-built function?
Thanks in advance.
Check this out
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split(char *const source, const char *const delimiter)
{
size_t length;
char **list;
size_t count;
char *pointer;
char *token;
void *saved;
if ((source == NULL) || (delimiter == NULL))
return NULL;
list = NULL;
pointer = source;
count = 0;
while ((token = strtok(pointer, delimiter)) != NULL)
{
saved = realloc(list, (1 + count) * sizeof(*list));
if (saved == NULL)
goto abort;
length = strlen(token);
list = saved;
list[count] = malloc(1 + length);
if (list[count] == NULL)
goto abort;
strcpy(list[count], token);
pointer = NULL;
count++;
}
saved = realloc(list, (1 + count) * sizeof(*list));
if (saved == NULL)
return list;
list = saved;
list[count] = NULL;
return list;
abort:
while (count != 0)
free(list[count--]);
free(list);
return NULL;
}
int main()
{
size_t k;
char string[] = "example string with spaces";
char **list;
list = split(string, " ");
if (list == NULL)
return -1;
k = 0;
while (list[k] != NULL)
{
printf("%s\n", list[k]);
free(list[k]);
k++;
}
free(list);
return 0;
}
The split function will return an array of char pointers which contain the tokens, and have a sentinel NULL pointer that tells you where the end of the list is.
You could try using strtok:
#include <string.h>
#include <stdio.h>
int main(){
char example_input[80] = "ls /home/user/directory/file.ext";
const char s[2] = "-";
char *token = strtok(example_input, " ");
/* walk through other tokens */
while( token != NULL ){
printf("%s\n", token );
token = strtok(NULL, s);
}
return(0);
}
Escape characters will be somewhat trickier.
If you only need to divide the string into command and argument this may work:
#include <string.h>
#include <stdio.h>
void cmd_ls(const char *arg){
printf("lsing %s\n",arg);
}
void cmd_pwd(const char *arg){
printf("pwding %s\n",arg);
}
int main(){
char example_input[80] = "psdwd /home/user/directory/file.ext";
const char s[2] = "-";
//Find command, assuming it ends at the first space
//Points to first space in string, will eventually point to beginning of
//command
char *command = strchr(example_input, ' ');
//Will point to beginning of argument
char *argument = NULL;
//If command is not NULL, then there is at least one space, so the string has
//the form "<COMMAND> X" where X is either '\0' (string terminator) or another
//character. If the string contains a space, edit it so that there is a
//terminator after the command. If there is an argument, return a pointer to
//its beginning (which may be a space).
if(command!=NULL){
*(command) = '\0'; //Terminate command string
if(*(command+1)!='\0') //If there are argument characters, point to them
argument = command+1;
}
command = example_input; //Point command to beginning of command
//Do I recognise this command?
if(strcmp(command,"ls")==0){
cmd_ls(argument);
} else if(strcmp(command,"pwd")==0) {
cmd_pwd(argument);
} else {
printf("Unrecognised command!\n");
}
return(0);
}
you can do it simply using scanf. you have to read the input until you get a '\n' character.
the code to do it will be :
scanf("%[^\n]", string);
the total string will be stored in the array string. you can do further string processing to extract the required data.
Have written following code in c
#include "stdio.h"
#include "string.h"
int main()
{
char str[] = "gatway=10.253.1.0,netmask=255.255.0.0,subnet=10.253.0.0,dns=10.253.0.203";
char name[100],value[100];
char *token1,*token2;
char *commasp = ", ";
char *equ="=";
token1 = strtok(str,commasp);
while(token1 != NULL)
{
token2 = strtok(token1,equ);
sprintf(name,"%s",token2);
token2 = strtok(NULL,commasp);
sprintf(value,"%s",token2);
printf("Name:%s Value:%s\n",name,value);
token1 = strtok(NULL,commasp);
}
return 0;
}
My problem is i got only one printf like Name:gatway Value:10.253.1.0. i know last strtok() in while loop followed by previous strok() which turns to null so token1 get null value and break the loop. Have think solution for it to not use strtok() in while loop for sub token (getting name and value) and use other method to extract name and value but it seems to lengthy code(using for or while loop for character match).So any one have batter solution to packup code in single loop.
You could use strtok_r instead of strtok.
char *key_value;
char *key_value_s;
key_value = strtok_r(str, ",", &key_value_s);
while (key_value) {
char *key, *value, *s;
key = strtok_r(key_value, "=", &s);
value = strtok_r(NULL, "=", &s);
printf("%s equals %s\n", key, value);
key_value = strtok_r(NULL, ",", &key_value_s);
}
gatway equals 10.253.1.0
netmask equals 255.255.0.0
subnet equals 10.253.0.0
dns equals 10.253.0.203
Frankly though I think it would be easier to just look for , and when you find one look for = backwards.
You can do this in two steps, first parse the main string:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "gatway=10.253.1.0,netmask=255.255.0.0,subnet=10.253.0.0,dns=10.253.0.203";
char name[100],value[100];
char *commasp = ", ";
char *ptr[256], **t = ptr, *s = str;
*t = strtok(str, commasp);
while (*t) {
t++;
*t = strtok(0, commasp);
}
for (t = ptr; *t; t++) {
printf("%s\n", *t);
// now do strtok for '=' ...
}
return 0;
}
Then parse individual pairs as before.
The above results in:
gatway=10.253.1.0
netmask=255.255.0.0
subnet=10.253.0.0
dns=10.253.0.203
I have following code:
int main(){
char sentence[] = "my name is john";
int i=0;
char ch[50];
for (char* word = strtok(sentence," "); word != NULL; word = strtok(NULL, " "))
{
// put word into array
// *ch=word;
ch[i]=word;
printf("%s \n",ch[i]);
i++;
//Above commeted part does not work, how to put word into character array ch
}
return 0;
}
I am getting error: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
I want to store each word into array, can someone help?
To store a whole set of words you need an array of words, or at least an array of pointers pointing to a word each.
The OP's ch is an array of characters and not an array of pointers to characters.
A possible approach would be:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define WORDS_MAX (50)
int main(void)
{
int result = EXIT_SUCCESS;
char sentence[] = "my name is john";
char * ch[WORDS_MAX] = {0}; /* This stores references to 50 words. */
char * word = strtok(sentence, " "); /* Using the while construct,
keeps the program from running
into undefined behaviour (most
probably crashing) in case the
first call to strtok() would
return NULL. */
size_t i = 0;
while ((NULL != word) && (WORDS_MAX > i))
{
ch[i] = strdup(word); /* Creates a copy of the word found and stores
it's address in ch[i]. This copy should
be free()ed if not used any more. */
if (NULL == ch[i])
{
perror("strdup() failed");
result = EXIT_FAILURE;
break;
}
printf("%s\n", ch[i]);
i++;
word = strtok(NULL, " ")
}
return result;
}