strtok
is the correct function, however you are using it wrong.
man strtok
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
.
I made the most important part of the quote bold.
Also bear in mind that strtok
modifies the source, if you need the source
afterwards, you have to make a copy.
// assuming that line is either a char[] or char*
char *token = strtok(line, " ");
if(token == NULL)
{
// error detection
}
while(token = strtok(NULL, " "))
{
// do the work
}
Also I recommend not to use sizeof(<data type>)
in
malloc
/calloc
/realloc
calls. It's easy to overlook a *
and make
mistakes. Better:
int *myarray = malloc(size * sizeof *myarray);
// or
int *mayarray = calloc(size, sizeof *myarray);
Using sizeof *var
is better because it will always returns the correct size.
One last thing:
while(!feof(stdin))
See Why is “while ( !feof (file) )” always wrong?
better
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin))
{
// do the work here
}
EDIT
Here you have a sample implementation using strtok
. My implementation uses
an array of MAP
s. Look at the way I construct/destruct the the MAP
objects and how the memory is allocated. Obviously this can be done with less code and less strdup
s, but I think this shows more precisely how to use these functions. You can use this code as your base or just use it as a basic idea.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct{
char *destination;
char *type_present;
int no_available_presents;
char *direction;
} MAP;
MAP *create_map(const char *dest, const char *type, int present, const char *dir);
void free_map(MAP *map);
void print_map(MAP *map);
MAP *create_map(const char *dest, const char *type, int present, const char *dir)
{
MAP *map = calloc(1, sizeof *map);
if(map == NULL)
return NULL;
int errors = 0;
if(!(map->destination = strdup(dest)))
errors++;
if(!(map->type_present = strdup(type)))
errors++;
if(!(map->direction = strdup(dir)))
errors++;
map->no_available_presents = present;
if(!errors)
return map;
free_map(map);
return NULL;
}
void free_map(MAP *map)
{
if(map == NULL)
return;
free(map->destination);
free(map->type_present);
free(map->direction);
free(map);
}
void print_map(MAP *map)
{
if(map == NULL)
{
puts("(null)");
return;
}
printf("destination: %s\n", map->destination);
printf("type: %s\n", map->type_present);
printf("present: %d\n", map->no_available_presents);
printf("direction: %s\n", map->direction);
}
int main(char argc, char **argv)
{
FILE *fp;
if(argc != 1 && argc != 2)
{
fprintf(stderr, "usage: %s [database]\n", argv[0]);
return 1;
}
if(argc == 1)
fp = stdin;
else
fp = fopen(argv[1], "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open '%s': %s\n", argv[1], strerror(errno));
return 1;
}
MAP **maps = NULL;
size_t map_len = 0;
char line[1024];
const char *delim = " \r\n";
while(fgets(line, sizeof line, fp))
{
int pres;
char *dest = NULL, *type = NULL, *dir = NULL, *token;
token = strtok(line, delim);
dest = strdup(token);
token = strtok(NULL, delim);
type = strdup(token);
token = strtok(NULL, delim);
pres = atoi(token);
token = strtok(NULL, delim);
dir = strdup(token);
if(dest == NULL || type == NULL || dir == NULL)
{
// ignore line
free(dest);free(type);free(dir);
continue;
}
MAP *new_map = create_map(dest, type, pres, dir);
if(new_map == NULL)
{
// ignore line
free(dest);free(type);free(dir);
continue;
}
MAP **tmp_map = realloc(maps, (map_len + 1) * sizeof *tmp_map);
if(tmp_map == NULL)
{
// ignore line
free_map(new_map);
free(dest);free(type);free(dir);
continue;
}
maps = tmp_map;
maps[map_len++] = new_map;
free(dest);free(type);free(dir);
}
for(int i = 0; i < map_len; ++i)
{
print_map(maps[i]);
puts("---");
free_map(maps[i]);
}
free(maps);
if(fp != stdin)
fclose(fp);
return 0;
}
The output:
destination: BERLIN
type: CAR
present: 1
direction: U
---
destination: BERLIN
type: CAR
present: 1
direction: R
---
destination: BUCHAREST
type: JACKET
present: 2
direction: D
---
destination: NEW_YORK
type: DOLL
present: 7
direction: U
---
destination: BERLIN
type: ROBOT
present: 5
direction: L
---
destination: BUCHAREST
type: BALL
present: 4
direction: L
---