char** splitInput = malloc(255 * sizeof(char*));
...
while(token != NULL)
{
splitInput[i] = token;
token = strtok(NULL, " ");
i++;
}
I don't know why this code works. In my previous version,
while(token != NULL)
{
*splitInput = token;
token = strtok(NULL, " ");
*splitInput++;
}
But It did't store anything. Why? What the difference between these two code?
That how I print the content of splitInput:
for(; *splitInput != NULL; *splitInput++){
printf("%s\n", *splitInput);
}
I can print the content of splitInput in my first code but fail in the second. Why?
If you have not got it sorted out yet, the difference is due to the difference in using array indexing versus pointer arithmetic. When you use array indexes, the address pointed to by splitInput
never changes.
However, when using the post increment operator you are changing the address of splitInput
each time you call *splitInput++
. It is the same as calling *splitInput = token; splitInput += 1;
So when you are done tokenizing your input, splitInput
points to the next pointer address after your last assigned token
.
Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be accessed and then freed when it is no longer needed. You violate rule (1) which prevents ever being able to access the beginning of the block you allocated (and creates a permanent memory leak)
How can you handle this? Either keep a count of the number of tokens assigned and then reset (back up) to the beginning of your block by that number of pointers, or better, simply use a separate pointer with the post-increment operator, thereby preserving the original address for the memory block in splitInput
.
A short example will illustrate:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 4096
int main (void) {
/* allocate & initialize */
char **splitInput = calloc (255, sizeof *splitInput),
**sp = splitInput, /* create pointer to splitInput */
buf[MAX] = "", *delim = " \n";
int n = 0;
if (!splitInput) { /* validate all allocations */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
while (fgets (buf, MAX, stdin)) {
for (char *p = strtok (buf, delim); p; p = strtok (NULL, delim)) {
*sp++ = p;
if (++n == MAX) /* always protect against writing beyond bounds */
goto full;
}
}
full:
for (int i = 0; i < n; i++)
printf ("splitInput[%3d] : %s\n", i, splitInput[i]);
free (splitInput); /* you allocate it --> you free it */
return 0;
}
Example Input
$ cat dat/fleas
my dog has fleas
Example Use/Output
$ ./bin/ptrinc < dat/fleas
splitInput[ 0] : my
splitInput[ 1] : dog
splitInput[ 2] : has
splitInput[ 3] : fleas
Of course, using array indexes, you can drop sp
completely and simply use:
while (fgets (buf, MAX, stdin)) {
for (char *p = strtok (buf, delim); p; p = strtok (NULL, delim)) {
splitInput[n++] = p;
if (n == MAX)
goto full;
}
}
Look things over and let me know if you have any further questions.