-1

I'm struggling with this split function based on C. After returning the struct by reference from the strSplit() function the token handle seems wrong. The variable sd->tokens is the right address, but I cannot get the tokens. But they are correct because inside the function I can get it. How can I resolve this and what is the reason for this behavior. All remaining variables in the struct are ok.

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

struct splitResult {
    char *source;
    long lSource;
    int  result;
    char **tokens;
};

typedef struct splitResult splitResultStruct;

splitResultStruct * strSplit(char *source, char *delimiter);

int main(int argc, const char * argv[]) {

    char *source = "part1.part2.part3";
    splitResultStruct *sd;
    
    sd = strSplit(source, ".");
    
    printf("%d tokens found\n", sd->result);
    
    for(int i=0; i<sd->result; i++) {
        printf("%s\n", sd->tokens[i]);
    }

    return 0;
}


splitResultStruct * strSplit(char *source, char *delimiter) {
    
    // Defines the result struct
    splitResultStruct sData, *sDataPtr;
    
    sDataPtr = &sData;
    
    sData.source = source;
    // Gets the length of source string
    sData.lSource = strlen(source);
    // Don't split if empty string is given
    if(sData.lSource == 0) {
        sData.result = -1;
        return sDataPtr;
    }
    // Allocate memory according teh size of source string
    char data[sData.lSource];
    // Copy the source into the allocated memory
    strcpy(data,source);
    // Just count the tokens
    char *token = strtok(data, delimiter);
    int tc = 0;
    while (token != NULL)
    {
        token = strtok(NULL, delimiter);
        tc++;
    }
    if(tc == 0) {
        sData.result = -1;
        return sDataPtr;
    }
    // Defines an array of char pointer with the dimension of the number of tokens
    sData.result = tc;
    char *tokens[tc];
    // Resets the token engine
    strcpy(data,source);
    // Strip out the first token found
    token = strtok(data, delimiter);
    tokens[0] = token;
    tc = 0;
    while (token != NULL)
    {
        // Strip out one token and store them into the token array
        token = strtok(NULL, delimiter);
        tc++;
        tokens[tc] = token;
    }
      
    sData.tokens = tokens;

    for(int i=0; i<sData.result; i++) {
        printf("%s\n", sData.tokens[i]);
    }

    return sDataPtr;
}
  • 1
    `sDataPtr = &sData; ... return sDataPtr;` You are not allowed to return the address of a local variable. – Gerhardh Oct 27 '22 at 13:17
  • 1
    `sDataPtr = &sData;` you return a pointer to a local variable, which ceases to exist once the `strSplit` has finished. Don't return a _pointer_ to `splitResultStruct` simple return a `splitResultStruct`. – Jabberwocky Oct 27 '22 at 13:17
  • Does this answer your question? [error: function returns address of local variable](https://stackoverflow.com/questions/12380758/error-function-returns-address-of-local-variable) – Gerhardh Oct 27 '22 at 13:18
  • "All remaining variables in the struct are ok." All other fields of the struct are also invalid as the whole struct where your returned pointer points to is not valid any longer. Its lifetime has ended – Gerhardh Oct 27 '22 at 13:19
  • A good compiler will warn you about the error. See https://godbolt.org/z/xzMeqbfne – Bodo Oct 27 '22 at 13:33

2 Answers2

0

Remember, never return a pointer to local variable. Local variables are destoryed when the function returns.

Try:

sDataPtr = malloc(sizeof(splitResultStruct));

Or:

static splitResultStruct sData;
splitResultStruct* sDataPtr;
Le Young
  • 37
  • 4
0

Ok, guys, got it regarding the struct memory. Changed the code to this version, so the struct will be declared in main and a pointer is passed. The functions returns nothing but changes the struct itself. But the tokens remains empty. Not a clue...

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

struct splitResult {
    char *source;
    long lSource;
    int  result;
    long tSize;
    char **tokens;
};

typedef struct splitResult splitResultStruct;

void strSplit(splitResultStruct *, char *source, char *delimiter);

int main(int argc, const char * argv[]) {

    char *source = "part1.part2.part3";
    splitResultStruct sd;
    
    strSplit(&sd, source, ".");
    
    printf("%d tokens found\n", sd.result);
    
    for(int i=0; i<sd.result; i++) {
        printf("%s\n", sd.tokens[i]);
    }

    return 0;
}


void strSplit(splitResultStruct *sData, char *source, char *delimiter) {
    
    sData->source = source;
    // Gets the length of source string
    sData->lSource = strlen(source);
    // Don't split if empty string is given
    if(sData->lSource == 0) {
        sData->result = -1;
    }
    // Allocate memory according teh size of source string
    char data[sData->lSource];
    // Copy the source into the allocated memory
    strcpy(data,source);
    // Just count the tokens
    char *token = strtok(data, delimiter);
    int tc = 0;
    while (token != NULL)
    {
        token = strtok(NULL, delimiter);
        tc++;
    }
    if(tc == 0) {
        sData->result = -1;
    }
    // Defines an array of char pointer with the dimension of the number of tokens
    sData->result = tc;
    char *tokens[tc];
    // Resets the token engine
    strcpy(data,source);
    // Strip out the first token found
    token = strtok(data, delimiter);
    tokens[0] = token;
    tc = 0;
    while (token != NULL)
    {
        // Strip out one token and store them into the token array
        token = strtok(NULL, delimiter);
        tc++;
        tokens[tc] = token;
    }
    
    sData->tokens = tokens;
    
    for(int i=0; i<sData->result; i++) {
        printf("%s\n", sData->tokens[i]);
    }
}

Result:

Part1
Part2
Part3
3 tokens found
(null)
(null)
(null)
Program ended with exit code: 0