I'm trying to load some highscores of a game to this kind of struct:
typedef struct{
char date_time[20];
int record_minutes;
int record_seconds;
int plays;
} Highscore;
The highscores are stored in a txt file like so: "nrplays minutes seconds date_and_time"
e.g. 15 2 10 31/12/2017-23:00:20
The first bit of the code I am using to read the file (which has only 3 lines, that's why I didn't create a loop) is the following
void loadHighscores(){
FILE *f;
if (check_ifEmptyFile()==-3)
return;
f=fopen("highscores.txt", "r");
char linha[30];
char *token;
High1 = (Highscore *)malloc(sizeof(Highscore));
fgets(linha, 30, f);
printf("linha: %s", linha);
token = strtok(linha, " \n");
High1->plays=atoi(token);
printf("%d\n", High1->plays);
token = strtok(NULL, linha);
High1->record_minutes=atoi(token);
printf("%d\n", High1->record_minutes);
token = strtok(NULL, linha);
High1->record_seconds=atoi(token);
printf("%d\n", High1->record_seconds);
token = strtok(NULL, linha);
snprintf(High1->date_time, 20*sizeof(char), "%s",token);
printf("%s",High1->date_time);
}
The output was this
linha: 15 2 10 31/12/2017-23:00:20
15
2
0
/
which means strtok isn't doing what I intended it to do. Any tips?
Note that High1 was defined previously, the malloc isn't wrong and also that High1->date_time should be the whole 31/12/2017-23:00:20 string.
In strtok() the second parameter should be the delimeter.
So, in your case, should be the character space: ' '.
token = strtok(linha, " ");
and for successive calls:
token = strtok(NULL, " ");
where you parsing every line in linha.
Related
This question already has an answer here:
Unexpected strtok() behaviour
(1 answer)
Closed 4 years ago.
The end goal is to output a text file where repeating words are encoded as single digits instead. The current problem I'm having is reading words and storing them into an array.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_CODE 120
void main() {
FILE *inputfile = fopen("input.txt","rw");
char buffer[128];
char *token;
char *words[MAX_CODE];
int i = 0;
while(fgets(buffer, 128, inputfile)){
token = strtok(buffer," ");
printf("Token %d was %s",i,token);
while(token != NULL) {
words[i] = malloc(strlen(token)+1);
strcpy(words[i], token);
i++;
token = strtok(buffer," ");
}
}
for(int i = 0; i<3; i++) printf("%d\n%s\n",i,words[i]);
printf("End");
}
What I get is segmentation fault errors, or nothing. What I want is for words to be an array of strings. I'm allocating memory for each string, so where am I going wrong?
Your second call to strtok should pass NULL for the first argument. Otherwise, strtok will parse the first token over and over again.
token = strtok(buffer," ");
printf("Token %d was %s\n",i,token);
while(i < MAX_CODE && token != NULL) {
words[i] = malloc(strlen(token)+1);
strcpy(words[i], token);
i++;
token = strtok(NULL," ");
}
The check against MAX_CODE is for the safety's sake, in case you ever increase the size of your buffer or reduce the value of MAX_CODE. In your current code, the maximum number of space delimited tokens you can hold in a 128 byte buffer is 64.
From cppreference:
If str != NULL, the call is treated as the first call to strtok for this particular string. ...
If str == NULL, the call is treated as a subsequent calls to strtok: the function continues from where it left in previous invocation. ...
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
I was trying to take out individual digits from input string like 1 2 3 4,5 6 7 8,9 10 11 12 in c program by splitting using strtok() function. For this i wrote below programming but it was reading till first comma , delimiter( Note : input size can vary. like in given example comma is after 4 digits but it can be after k(5,6,7, etc) digits based on give testcases ).
fgets(str,80,stdin);
/* read str with comma(,)delimiter */
token = strtok(str, ",");
/* walk through other tokens */
while( token != NULL )
{
// read token string with space delimiter
token2 = strtok(token, " ");
while( token2 != NULL )
{
printf("%s \n", token2);
token2 = strtok(NULL, " ");
}
token = strtok(NULL, ",");
}
strtok is not reentrant -- you can only tokenize one string at a time. If you want to simultaneously tokenize multiple strings at a time, use strtok_r instead. Better yet, ALWAYS use strtok_r in preference to strtok, as it is never less capable:
char *inner, *outer;
fgets(str,80,stdin);
/* read str with comma(,)delimiter */
token = strtok_r(str, ",", &outer);
/* walk through other tokens */
while( token != NULL )
{
// read token string with space delimiter
token2 = strtok_r(token, " ", &inner);
while( token2 != NULL )
{
printf("%s \n", token2);
token2 = strtok_r(NULL, " ", &inner);
}
token = strtok_r(NULL, ",", &outer);
}
You might also want to investigate strsep as well.
The implementation of strtok works with the last string that was passed to it that was not NULL.
Hence, the line:
token = strtok(NULL, ",");
does not work.
If you know the exact number of tokens, you can use sscanf.
/* read str with comma(,)delimiter */
token = strtok(str, ",");
/* walk through other tokens */
while( token != NULL )
{
int num1;
int num2;
int num3;
int num4;
if ( sscanf(token, "%d %d %d %d", &num1, &num2, &num3, &num4) != 4 )
{
// Problem.
}
else
{
// Use the numbers
}
token = strtok(NULL, ",");
}
I'm using strtok to split up a string, it works as expected for the first 4 iterations, but starts messing up after that. The program is supposed to take a line such as "david 1 2 3 4 5" and print out the name plus the sum of the numbers "david 15"... However I am having a problem with strtok.
EDIT: I make number a pointer for later uses of the code (this is only a snippet)
This is my C script:
#include <stdio.h>
#include <string.h>
char str1[50];
char *token;
char *end;
long int *number;
int loop = 1;
while(loop){
fgets(str1,50,stdin);
token = strtok(str1," ");
printf("%s ",token);
*number = 0;
while(token != NULL){
token = strtok(NULL," ");
if(token != NULL){
*number = *number + strtol(token,&end,0);
}
}
printf("%li\n",*number);
}
With this input:
David 10 10 10 10 10
I get this output:
David 40
The expected output is:
David 50
Suspecting strtok, I put these test print statements:
char str1[50];
char *token;
char *end;
long int *number;
int loop = 1;
while(loop){
fgets(str1,50,stdin);
token = strtok(str1," ");
printf("%s\n",token);
*number = 0;
while(token != NULL){
printf("before new token: %s\n",token); // <---HERE
token = strtok(NULL," ");
printf("after new token: %s\n\n",token); // <---HERE
if(token != NULL){
*number = *number + strtol(token,&end,0);
}
}
printf("%li\n",*number);
}
And with the same input of:
David 10 20 30 40 50
I get:
David
before new token: David
after new token: 10
before new token: 10
after new token: 20
before new token: 20
after new token: 30
before new token: 30
after new token: 4<
before new token: 4#
after new token: (null)
64
As you an see it works fine during the first few iterations, but after that things start going bad. If anyone has any idea what is happening, I would greatly appreciate the advice :) thanks!
The variable number is a pointer (why?) but you never make it point anywhere, therefore when you dereference it you will have undefined behavior.
The simple solution? Don't make it a pointer!
The reason you get 40 instead of 50 is that you drop the first token (i.e. the one that you get from strtok when you pass str1, not NULL). You need to add it to the sum before entering the loop, or re-organize the loop to add first and call strtok next:
number = 0; // There is no point in making "number" a pointer
token = strtok(str1," ");
while(token != NULL){
printf("%s ",token);
number += strtol(token,&end,0);
token = strtok(NULL," ");
}
Demo.
I am using vc2010 and I am trying to read contents of a file into a struct as follows and it gives me run time error.
char buf[100];
char *token = NULL;
while( fgets (buf , 100 , rd) != NULL )
{
token = strtok( buf,", ");
test_st.fp.chunk_offset = atol(token);
printf("\n %llu ", test_st.fp.chunk_offset);
//OPTION 1: if i do this there will be no runtime error but the same
// value as the first token will be assigned to chunk_length
token = strtok(buf, ",");
//OPTION 2: this line gives error in the second while loop iteration
token=strtok(NULL,",");
test_st.fp.chunk_length = atol(token);
printf("%llu ", test_st.fp.chunk_length);
token = strtok(NULL, " ");
....
}
my other problem is how can i use strtok() or any- if there is one- to assign a very long character string(like the one after the second coma in the following file content) into a structure data member(in this case into fp.fing_print)?
Here is the first part of the file i am trying to read
0,4096,2ed692b40e335f7c20b71c5ed0486634
4096,3028,da40bf20c8ff189087b8bd7e8580118a
7124,2177,e6dfaee81e96095d302c82f9fd73dc55
9301,1128,76201eadff3c89a381a314ed311f75ff
the structure definition i am trying to read this into is:
typedef struct fpinfo
{
unsigned long chunk_offset;
unsigned long chunk_length;
unsigned char fing_print[32];
}fpinfo;
typedef struct Hash_Entry {
struct Hash_Entry *next; /* Link entries within same bucket. */
unsigned namehash; /* hash value of key */
struct fpinfo fp;
} Hash_Entry;
EDIT:
Yes you are right I have to use the second option.
I HAVE FOUND THE PROBLEM WITH THIS ONE. The file have empty lines between every line and it gives error message when it gets to these empty lines.
BUT I AM STUCK in the other problem where I have to read the last part of each line into the array member(fp.fing_print) of the structure.
Thank you everybody for your help!!!
EDIT:
the fing_print[32] array is supposed to hold 32 characters which are results of an md5 hash function. I am not sure if i have to make it a null terminated string or not. if you guys could give me a tip about it I will be more than grateful.
As stated by paulsm4 you need to check strtok() return value. The following code works and includes the creation of the string:
while( fgets (buf , 100 , rd) != NULL )
{
token = strtok(buf,", \n");
if (0 != token)
{
test_st.fp.chunk_offset = atol(token);
printf("\tchunk_offset=%lu\n", test_st.fp.chunk_offset);
token = strtok(0, ", \n");
}
if (0 != token)
{
test_st.fp.chunk_length = atol(token);
printf("\tchunk_length=%lu\n", test_st.fp.chunk_length);
token = strtok(0, ", \n");
}
if (0 != token)
{
/* EDIT: fing_print datatype changed. */
memset(test_st.fp.fing_print, 0, sizeof(test_st.fp.fing_print));
strncpy(test_st.fp.fing_print,
token,
sizeof(test_st.fp.fing_print) - 1);
/* test_st.fp.fing_print = _strdup(token); */
printf("\tfing_print=[%s]\n", test_st.fp.fing_print);
}
printf("\n");
}
Delimiter set is ", \n" as fgets() will read the newline character into buf.
You need to check for NULL return:
if ((token = strtok(buf, ",")) {
// must have found a comma
}
if (token && (token = strtok(NULL,"'")) {
// Two in a row: I found a comma and then I found an apostrophe
}
...