strtok when process two strings at same time - c

New in C and pretty confused about how to deal with several strings at the same time using strtok, for a simply example, I want to use strtok to extract the number and compare then.
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100]="11.54";
char s2[100]="12.55";
const char tok[2]=".";
char* token1=strtok(s1,tok);
char* token2=strtok(s2,tok);
while(token1 !=NULL && token2 !=NULL){
int temp=strcmp(token1,token2);
if(temp==0){
token1=strtok(NULL,tok);
token2=strtok(NULL,tok);
}
else if(temp<0){
printf("%d\n",-1);
return;
}
else{
printf("%d\n",1);
return;
}
}
if(token1 !=NULL){
printf("%d\n",1);
return;
}
if(token2 !=NULL){
printf("%d\n",-1);
return;
}
printf("%d\n",0);
return 0;
}
But when I use the strtok, the strtok(NULL,token)will point to the current string and will do like: 11->12>55->NULL and skip the 54
How could I deal with such situation? Thanks!!

Do not use strtok(). The documentation will tell you strtok() is not reentrant (i.e. should not be used across threads), but perhaps less obvious is the fact that the reason it is not reentrant is because it uses an internal save variable to remember where it's got to. That means you also can't use two instances at once. Instead use strtok_r() or failing that strsep() might work.
strtok_r() is just like strtok, save that you pass it a char ** (i.e. a pointer to char *) where it can save where it's got to.
The GNU libc manual page gives a good example of using a nested strtok_r which is what you are trying to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}

Related

Segmentation error when convert string to array of strings in c

I want to convert a string to an array of strings and I get an error
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int count = 0;
char *str = argv[1];
char *token, *last;
char **arr_str = calloc(9999, sizeof(char*));
token = strtok_r(str, " ,", &last);
arr_str[count] = strcpy(calloc(strlen(token), sizeof(char)), token);
while (token != NULL) {
count++;
token = strtok_r(NULL, " ", &last);
arr_str[count] = strcpy(calloc(strlen(token), sizeof(char)), token);
printf("%s", arr_str[count - 1]);
}
printf("------------");
while(arr_str[count])
printf("%s", arr_str[count--]);
exit (0);
}
how to allocate memory for a string and make a pointer to it from an array?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
/* always check argument count */
if(argc < 2) {
printf("Not enough arguments given\n");
return 1;
}
int count = 0;
char *str = malloc(strlen(argv[1] + 5));
memcpy(str, argv[1], strlen(argv[1]));
char *token, *last;
char **arr_str = calloc(9999, sizeof(char*));
token = strtok_r(str, " ,", &last);
while ((token = strtok_r(NULL, " ", &last)) != NULL) {
count++;
/* sizeof(char) is always 1 and is redundant unless you are on
a obscure platform that it returns other than 1
which shouldnt exist in modern world
*/
arr_str[count] = malloc(strlen(token) + 1);
strcpy(arr_str[count], token);
}
printf("------------");
while(arr_str[count])
printf("%s", arr_str[count--]);
exit (0);
}
strtok is destructive meaning it edits strings it encounters, it tried to edit argv which resulted in a segmentation error.
I also edited code to follow better practices and edited formatting.
You need memory for elements of the arr_str.
calloc(9999) while not great if this not going to end up in a serious application it's not a issue.
sizeof(char) should always return 1 on a normal modern system unless you are on extremely obscure system
Use puts(char* s) if you don't need string formatting.
You should do input validation.

C - Read from .INI file and pass values to vars

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;
...
}

Delimiting Char Array for Three Variables

I'm writing a program to parse a command-line argument into three different parts: host name, file path, and file name, however I am unsure of how to parse a single command-line argument and store the separate parts in three different variables.
I need each portion to create a socket on the client-side of my program. So far I've been able to parse the host name portion, but I get stuck after that.
Is there a way that, after parsing a portion of the string?
EDIT:
The string I'm trying to parse is something like camelot.cba.csuohio.edu/~yourloginid/filename.txt
Here's my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int i, sk;
char buf[256], temp[256];
struct sockaddr_in remote;
struct hostent *hp;
if(argc != 2)
{
printf("Invalid number of arguments. Program terminating...");
exit(1);
}
sk = socket(AF_INET, SOCK_STREAM, 0);
remote.sin_family = AF_INET;
strcpy(buf, argv[1]);
for(i = 0; i < strlen(buf); i++)
{
if(buf[i] == '/')
break;
temp[i] = buf[i];
}
hp = gethostbyname(temp);
return 0;
}
EDIT:
I've implemented a while loop to achieve what I'm looking for, but I feel like it's sloppy. Is there a way I can improve it?
while(tk != NULL)
{
if(c == 0)
strcpy(host, tk);
else if(c == 1)
strcpy(path, tk);
else
strcpy(fname, tk);
c++;
tk = strtok(NULL, "/");
}
char st[] = "camelot.cba.csuohio.edu/~yourloginid/filename.txt";
char *host, *path, *fname;
char *ch[3];
for (int i=0; i < 3; ++i) {
ch[i] = strtok(st, "/");
(if ch[i] == NULL) break;
printf("%s\n", ch[i]);
}
if (ch[0] != NULL) {
host = ch[0];
}
if (ch[1] != NULL) {
path = ch[1];
}
if (ch[2] != null) {
path = ch[2];
}
Output:
camelot.cba.csuohio.edu
~yourloginid
filename.txt
You can parse that with strtok
A rough example for you case would be
const char s[2] = "/";
char *token;
/* get the first token */
token = strtok(argv[1], s);
/* walk through other tokens */
while( token != NULL )
{
printf( " %s\n", token );
token = strtok(NULL, s);
}
I didn't compile it but I hope you can use it as an example.
Here you have a complete example of how to use it
http://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
Hope this helps.
When you know the delimiters, never forget you have simple pointer arithmetic available to you to split/parse any sting. strtok and sscanf are fine tools, but you can do the same thing manually. Here is a short example to add to your list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 128
int main (int argc, char **argv) {
if (argc < 2 ) {
fprintf (stderr, "Error: insufficient input, usage: %s host,path,file\n", argv[0]);
return 1;
}
char *line = strdup (argv[1]); /* make a copy of argument string */
if (!line) {
fprintf (stderr, "error: strdup memory allocation/copy failed.\n");
return 1;
}
char *p = line; /* pointer to the argument string */
char *sp = NULL; /* pointer to use as start pointer */
char host[MAXS] = {0}; /* variables to hold tokens */
char path[MAXS] = {0};
char file[MAXS] = {0};
while (*p && *p != ',') p++; /* find the first ',' */
*p++ = 0; /* null-terminate, advance pointer */
strcpy (host, line); /* read/copy host name */
sp = p; /* set start pointer at current pos */
while (*p && *p != ',') p++; /* find next ',' */
*p++ = 0; /* null-terminate, advance pointer */
strcpy (path, sp); /* read/copy path */
strcpy (file, p); /* pointer on file, read/copy file */
printf ("\n host: %s\n path: %s\n file: %s\n\n", host, path, file);
free (line); /* free memory allocate by strdup */
return 0;
}
Output
$ ./bin/split_host_path_file hostname,pathname,filename
host: hostname
path: pathname
file: filename
Updated to prevent potential read beyond end of line with p.
you can also parse with strtok_r as follows, since strtok is not thread safe.
const char *delim="/";
char *str, *savePtr;
char hosts[3][32];
int i;
for(i=0,str=strtok_r(argv[1], delim, &savePtr);(str!=NULL);str=strtok_r(NULL, delim, &savePtr), i++)
{
print("%s\n", str);
strcpy((char *)host[i], (const char *)str);
}
access host array elements, as it will contain the indexed values delimited by "/"

Global Array doesn't update while inside while loop?

I have an array of structs, inside the while loop I add things to that array, however when I print out the array I get the wrong output?
(The last element added is printed out n times, n being the number of things I added)
I have googled this and I think it is because a while loop in Bash creates a subshell, not too sure.
Any help would be much appreciated
(please have patience I am only a student!!)
Using Mac OSX mountain lion
Xcode 4 gcc
Code:
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node nodes[100];
int count = 0;
void add(char *one,char*two){
Node newNode = {one,two};
nodes[count]= newNode;
printf("one: %s\n",one);
printf("two: %s\n",two);
count++;
}
void print(){
int x;
for (x = 0; x < 10; x++)
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
add(arg[1],arg[2]);
else if(strcmp(*arg,"print") == 0)
print();
else
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] = pch;
}
}else{
printf("\n");
exit(0);
}
}
int main()
{
int i;
for(i = 0;i <100; i++){
nodes[i].one = ".";
nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL)
check(arg);
}
return(0);
}
strtok() returns a pointer to different elements within the buffer it was initially passed. This means that all entries in the array will be pointing to different elements of the same buffer, named line. You need to make a copy of the pointer returned by strtok():
use malloc(), strlen() and strcpy(). Or,
use the non-standard strdup()
in either case, the memory must be free()d when no longer required.
It's because you use the same buffer for all input.
You need to duplicate the strings you put into the structures. Either by using arrays for the strings and strcpy into them, or by using strdup to allocate new memory for the strings and do the copying in one function.

How can I stop scanf-ing input after a certain character?

I'm working on a function that takes filepaths and dices them up into smaller sections.
For example, if the input parameter was "cd mypath/mystuff/stack/overflow/string", I want to be able to return "cd" "mypath", "mystuff", "stack", "overflow", and "string" in succession.
While I could simply continually use "getchar", appending the results to an ever-increasing string, stopping when getchar returns a '/', I feel like there must be a more elegant way to achieve the same functionality.
Any ideas?
You can use the char * strtok ( char * str, const char * delimiters ); using / as separator.
An example here:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s path\n", argv[0]);
exit(EXIT_FAILURE);
}
char* saveptr = NULL;
for (char* str = argv[1]; ; str = NULL) {
char *token = strtok_r(str, "/", &saveptr);
if (token == NULL)
break;
printf("%s\n", token);
}
return 0;
}
Example
clang -Wall *.c && ./a.out mypath/mystuff/stack/overflow/string
mypath
mystuff
stack
overflow
string
Here's an example of how sscanf() can stop after a certain character.
sscanf("abcd/efgh", "%[^/]", &buf);
printf("%s\n", buf);
Should produce
abcd
EDIT: You could try something like this to advance sscanf() input. I have not tested this for various edge cases, but it should get the idea across.
char *str = "abcd/efgh/ijk/xyz";
while (sscanf(str, "%[^/]%n", &buf, &n)) {
printf("%s\n", buf);
str += n;
if (*str == '\0')
break;
++str;
}
should produce
abcd
efgh
ijk
xyz
Here is an example using regcomp, regexec. Compile and run it with the first arg being the character you are searching on, while the second arg is the string to search.
For example, a.out X abcXdefXghiXjkl will print abc def ghi jkl on separate lines.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <regex.h>
int
main(int argc, char *argv[]) {
int len;
char *cp;
char *token;
regex_t preg;
regmatch_t match;
if (regcomp(&preg, argv[1], REG_EXTENDED) != 0) {
return 0;
}
for (cp = argv[2]; *cp != '\0'; cp += len) {
len = (regexec(&preg, cp, 1, &match, 0) == 0) ? match.rm_eo : strlen(cp);
token = malloc(len);
strncpy(token, cp, len);
printf("%s\n", token);
}
return 0;
}

Resources