Troubles with strtok() and char**

Hello guys, i tried to use strtok but without success..

I have a simple file with 2 lines:

1) hello, world
2) loving, programming

I would like to save all words in a different position of a 2D array, like this

arr[0] = hello, arr[1] = world, arr[2] = loving, etc...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void print_char_array(char **a, int size);

int main(int argc, char const *argv[])
{
    int size = 4;
    int _char_index = 0;
    
    char **_char_arr = (char **)malloc(size * sizeof(char *));
    
    char *pch; //token for strtok
    
    FILE *_file = fopen("/Users/vitto/Desktop/Untitled.txt", "r");

    char *line = (char *)malloc(100 * sizeof(char)); //each file's line will be saved here

    while (fscanf(_file, "%[^\n]", line) != EOF)
    {
        getc(_file);
        printf("Line: %s\n", line);
        pch = strtok(line, ",");
        while (pch != NULL)
        {
            _char_arr[_char_index] = pch;
            _char_index++;
            pch = strtok(NULL, ",");
            
        }
    }
    
    print_char_array(_char_arr, size);
    
    free(_char_arr);
    
    return 0;
}


void print_char_array(char **a, int size)
{
    int i;
    printf("ARR: ");
    for (i = 0; i < size; i++)
        printf("%s ", *(a + i));
    printf("\n");
}


But the output is always the same:

Line: hello, world
Line: loving, programming
ARR: loving loving programming
Program ended with exit code: 0

//////////////////////////////////

It has a weird behavior.. it prints 2 "loving" and 1 time "programming"...??

Did i miss something with STRTOK or im doing wrong with 2D pointers?.. im lost.
Thank you all for the help.
Last edited on
The main issue is with the memory management. Space is needed for each word extracted. Consider as C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_char_array(char** a, int size);

int main(int argc, char const* argv[])
{
	const int size = 4;
	char** _char_arr = (char**)calloc(size, sizeof(char*));

	FILE* _file = fopen("Untitled.txt", "r");

	if (_file == NULL) {
		puts("Cannot open file\n");
		return 1;
	}

	char* line = (char*)calloc(100, sizeof(char)); //each file's line will be saved here

	for (int _char_index = 0; _char_index < size && fscanf(_file, "%[^\n]", line) != EOF; getc(_file))
		for (char* pch = strtok(line, ","); pch; pch = strtok(NULL, ","))
			_char_arr[_char_index++] = strcpy((char*)calloc(strlen(pch) + 1, sizeof(char)), pch);

	print_char_array(_char_arr, size);

	for (int i = 0; i < size && _char_arr[i]; ++i)
		free(_char_arr[i]);

	free(_char_arr);
	free(line);
	return 0;
}

void print_char_array(char** a, int size)
{
	printf("ARR: ");

	for (int i = 0; i < size && a[i]; ++i)
		printf("%s ", a[i]);

	puts("");
}



ARR: hello  world loving  programming


You may also need to trim the words to remove extra spaces.

Oh for C++!
Last edited on
Thank you
seeplus


But I have a doubt at this point..

If i have an array of char pointers (_char_arr).. and STRTOK returns a pointer. the question is: Why should i allocate memory?

I mean: the strtok returns me a pointer to the char array and i just attach it like

_char_arr[_char_index] = pch;

I dont need to allocate memory if i already have a pointer (?)
Why should i allocate memory and then copy the content to the allocated memory?

I give you an example:
1
2
3
char* x = "hello";
char *ptr;
ptr = x;


In this code you dont allocate memory but just attach the memory to the pointer. This is my idea right now.

I'm just asking because i'm a bit confusing right now..

I hope i was clear to explain my idea.
Last edited on
strtok returns a pointer into the char array provided. It doesn't allocate any new memory. Variable line is defined only once and re-used for each line read. pch is a pointer into line. line is re-used each time a line is read from the file. Thus after a line has been read, the saved pch pointers are not valid as line has been overwritten. For this to work, you would need to allocate new memory for each line read from the file. Then pch would point into the appropriate line.

In my code above, I only allocate enough space to hold each word - not to hold each line - which would be a waste of memory.

Either way, memory has to be allocated somewhere to hold the extracted words.
Ok i understand, thank you for the help!
also note that arrays are fine too.
char stringarray[30][100]; //30 strings, 100 letters each.
you can avoid all the memory allocation and release if you have a good idea of how big to make the storage. Today, if its a modern computer, even making it an absurd 1000x1000 is only one MB, which is roughly using 1/64000 memory on a 64GB machine.

depending on what you need to do, it is often possible to completely avoid the memory mess. If you have to do something like read a file of any size all into memory, then you will need to allocate some but if its line by line and you have a general idea of the max size of a line, you can avoid it, if that helps you decide
Topic archived. No new replies allowed.