1

I am trying to enhance the string splitter by splits on : char. Original version can be found at string splitter - how is it working

I do not want to use MAX_TOKEN_SIZE, I want the buffer to be just enough to hold each token. I added malloc and realloc as follows but I am getting free(): double free detected in tcache 2 error which I do not understand. How am I double freeing ? Thanks for all your help.

PS: Based on Gerhardh's comments, I modified the code as follows, but now I am getting segfault.

PS: Based on user3121023's comments, I added parenthesis around *token in 2 places and it works now.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

# define GROWBY 32

const char* splitter(const char *str, char delimiter, char **token) {

    size_t i = 0;
    size_t buflen = 32;
    while (*str) {
       if ( i ==  buflen) {
           buflen += GROWBY;
           printf("gowing buffer\n");
           char *new_token = realloc(*token, buflen * sizeof **token);
           if (new_token == NULL){
               fprintf(stderr, "Out of Memory");
               abort();
           }
           *token = new_token; //set the new pointer to old pointer
       }
       char c = *(str++);

       if (c == delimiter)
           break;

       (*token)[i++] = c; //user3121023
   }

   (*token)[i] = '\0';  /* set the null terminator, user3121023 */

   return str;
} 

int main(){
    
    const char *env = 
  "/bin/svsgerertegdfyufdujhdcjxbcn:/sbin:::/usr/bin/46526vw67vxshgshnxxcxhcgbxhcbxn";

   while (*env){
       char *token = malloc(GROWBY * sizeof(char));
       env = splitter(env, ':', &token);  
       if (token[0] == '\0') {
           strcpy(token, "./");            
       }
       printf("%s\n", token)  ;
       free(token);
   }

   return 0;
}
Yoshiro
  • 53
  • 1
  • 3
  • You use `realloc` in your function. This can cause the pointer to be freed if a new allocation at some other location is done. If you do `free(token)` in main afterwards, that same address is freed again. Remember: In C parameters are passed by value. You put in a copy of `token` into `splitter` and if you assign something inside that function (`token = new_token;`) that will not be visible outside of that function. – Gerhardh Sep 10 '22 at 14:57
  • Does this answer your question? [Changing address contained by pointer using function](https://stackoverflow.com/questions/13431108/changing-address-contained-by-pointer-using-function) – Gerhardh Sep 10 '22 at 14:59
  • Out of curiosity, why not use `strtok`? – aulven Sep 10 '22 at 15:02
  • Hi aulven, I do not want to use strtok as it modifies the original string, replaces the delimiters. Plus it does not handle consecutive delimiters that I have in my test string above. This code is part of a larger codebase. Thanks – Yoshiro Sep 10 '22 at 15:12
  • Thank you, user3121023, it absolutely works now. I forgot about those precedence rules I guess. Thanks. – Yoshiro Sep 10 '22 at 15:37
  • Heh, [maybe my solution will help you with yours](https://stackoverflow.com/a/69512860/2706707). – Dúthomhas Sep 10 '22 at 15:52

1 Answers1

0

Try using strcspn to advance to the next delimiter.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* splitter(const char *str, char *delimiter, char **token) {
    size_t buflen = 0;
    size_t extra = 0;

    buflen = strcspn ( str, delimiter); // characters to next delimiter
    extra = 1;
    if ( ! buflen) {
        extra = 3; // need space for "./" copy in main
    }
    char *new_token = realloc(*token, ( buflen + extra) * sizeof **token);
    if (new_token == NULL){
        fprintf(stderr, "Out of Memory");
        abort();
    }
    *token = new_token; //set the new pointer to old pointer
    strncpy ( *token, str, buflen);

    (*token)[buflen] = 0;

    str += buflen;
    if ( *str) {
        str += 1;
    }
    return str;
}

int main(void){

    const char *env =
  "/bin/svsgerertegdfyufdujhdcjxbcn:/sbin:::/usr/bin/46526vw67vxshgshnxxcxhcgbxhcbxn";

   while (*env){
       char *token = NULL;
       env = splitter(env, ":", &token); // note " instead of '
       if (token[0] == '\0') {
           strcpy(token, "./");
       }
       printf("%s\n", token)  ;
       free(token);
   }
   return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16