Home > front end >  char array variables are destroyed after exiting from function
char array variables are destroyed after exiting from function

Time:04-10

I use strtok() to tokenize my string in a function. After copying the values to a global char array, I print the values to ensure the functionality. Everything is OK, but when I want to access them they are destroyed.

this is the code:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

int client, count = 0;

volatile char *token_temp[30];
volatile int toknum = 0;

int text_test()
{
    char my_tokenised_string_buffer[255] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";
    const char delimiters[3] = "\n";

    char *token = strtok(my_tokenised_string_buffer, delimiters);
    token_temp[0]= token;
    printf("first tokenised value = %s\n", token);

    while (token != NULL) {
          toknum;
        token = strtok(NULL, delimiters);
        token_temp[toknum]= token;
        printf("toknum : %d\t", toknum);
        printf("token id from inside tokenise loop : %s -> [%u]\n", token_temp[toknum], toknum);
    }
    printf("\n\n\n");
    for (int i = 0; i < toknum; i  ) {
        printf("token [%d] value in function out of tokenise = %s\n", i, token_temp[i]);
    }
    return 0;
}

int main()
{
    text_test();
    printf("\n\n\n");

    for (int i = 0; i < toknum; i  ) {
        printf("token [%d] value in main = %s\n", i, (char *)token_temp[i]);
    }
    return 0;
}

this is output enter image description here

I want to assign the values to structures but they are missed.

CodePudding user response:

Within the function there is declared a local array with automatic storage duration

int text_test()
{
    char my_tokenised_string_buffer[255] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";
//...

that will not be alive after exiting the function.

So the array of pointers

volatile char *token_temp[30];

will contain invalid pointers and dereferencing these pointers will invoke undefined behavior.

What you need is for example to allocate dynamically a character array for each string extracted from the array my_tokenised_string_buffer.

Another approach is declare the array my_tokenised_string_buffer as having static storage duration specifying the keyword static

static char my_tokenised_string_buffer[255] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";

CodePudding user response:

The thing is that the strtok calls gives pointers to slices of your my_tokenised_string_buffer. But by exiting the function, my_tokenised_string_buffer gets out of scope, thus being overridden with new data you put in the stack. To avoid this, you have 2 solutions:

Or my_tokenised_string_buffer never goes out of scope, making the following program:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

int client, count =0;


volatile char *token_temp[30];
volatile int toknum = 0;
char my_tokenised_string_buffer[255] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK"; // Static, so won't go out of scope

int text_test()
{
    const char delimiters[3] = "\n";

    char *token = strtok(my_tokenised_string_buffer, delimiters);
    token_temp[0]= token;
    printf("first tokenised value = %s\n",token);

    while (token != NULL)
    {
          toknum ;
        token = strtok(NULL, delimiters);
        token_temp[toknum]= token;
        printf("toknum : %d\t",toknum);
        printf("token id from inside tokenise loop : %s -> [%u]\n", token_temp[toknum], toknum);
    }
    printf("\n\n\n");
    for(int i = 0; i < toknum;i  )
    {
        printf("token [%d] value in function out of tokenise = %s\n",i, token_temp[i]);
    }
    return 0;

}

int main()
{
    text_test();
    printf("\n\n\n");

    for(int i = 0; i < toknum;i  )
    {
        printf("token [%d] value in main = %s\n",i, token_temp[i]);
    }
    return 0;
}

or you copy your tokens each time you get a new one, with a malloc. However, you'll need to manage the last token differently:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

#include <stdlib.h>

int client, count = 0;


volatile char *token_temp[30];
volatile int toknum = 0;

int text_test()
{
    char my_tokenised_string_buffer[255] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";
    const char delimiters[3] = "\n";

    char *token = strtok(my_tokenised_string_buffer, delimiters);

    token_temp[0] = malloc((1   strlen(token)) * sizeof(char));
    strcpy((char*) token_temp[0], token);

    printf("first tokenised value = %s\n",token);

    while (token != NULL)
    {
          toknum ;
        token = strtok(NULL, delimiters);

        if (token != NULL) {
            token_temp[toknum] = malloc((1   strlen(token)) * sizeof(char));
            strcpy((char*) token_temp[toknum], token);
        } else {
            token_temp[toknum] = NULL;
        }

        printf("toknum : %d\t",toknum);
        printf("token id from inside tokenise loop : %s -> [%u]\n", token_temp[toknum], toknum);
    }
    printf("\n\n\n");
    for(int i = 0; i < toknum;i  )
    {
        printf("token [%d] value in function out of tokenise = %s\n", i, token_temp[i]);
    }
    return 0;

}

int main()
{
    text_test();
    printf("\n\n\n");

    for(int i = 0; i < toknum;i  )
    {
        printf("token [%d] value in main = %s\n",i, token_temp[i]);
    }
    return 0;
}

CodePudding user response:

You can use this code for solve your problem :

enter code here

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
//------------------------------------------------------------
int SpliteMessage(char* input , char sp , char token_temp[10][40])
{
    int len = strlen(input);
    int i,token_cnt=0,bcnt=0;
    for (i=0 ; i<len ; i  )
    {
        if (input[i] == sp)
        {
            token_temp[token_cnt][bcnt] = 0;
            token_cnt  ;
            bcnt=0;
        }
        else
        {
            token_temp[token_cnt][bcnt] = input[i];
            bcnt  ;
        }
    }
    return token_cnt;
}
//----------------------------------------------------------------
int main()
{
    char buffer[200] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";
    char t_temp[10][40];
    int token_counter =  SpliteMessage(buffer , '\n' , t_temp);
    printf("\n--------------\n(Token Counter -> %i)\n",token_counter);
    for (int i=0 ; i<token_counter ; i  )
        printf("token[%i] from main: (%s) \n",i,t_temp[i]);
    return 0;
}

CodePudding user response:

strtok() is a confusing and error prone function. The pointer it returns points to the string that gets tokenized (which is modified for this purpose). Storing these pointers to a global array, which by the way does not need to ne volatile qualified, results in undefined behavior after the function returns as the array my_tokenised_string_buffer is no longer valid.

You should allocate copies of the tokens and take the destination array as an argument.

Here is a modified version:

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

int text_test(char *token_temp[], int length) {
    char my_tokenised_string_buffer[] = "Response\n\nCompany\nModel\nRevision: N01234567890\n\nOK";
    const char delimiters[] = "\n";
    char *token;
    int toknum = 0;

    token = strtok(my_tokenised_string_buffer, delimiters);
    while (toknum   1 < length && token != NULL) {
        token_temp[toknum  ]= strdup(token);
        token = strtok(NULL, delimiters);
    }
    token_temp[toknum] = NULL; /* terminate the array with a null pointer */
    return toknum; /* return the number of tokens */
}

int main() {
    char *token_temp[30];
    int array_length = sizeof(token_temp) / sizeof(*token_temp);
    int toknum = 0;

    toknum = text_test(token_temp, array_length);

    /* print the tokens */
    for (int i = 0; i < toknum; i  ) {
        printf("token [%d] value in main = %s\n", i, token_temp[i]);
    }
    /* free the tokens */
    for (int i = 0; i < toknum; i  ) {
        free(token_temp[i]);
    }
    return 0;
}
  • Related