Переменные массива char уничтожаются после выхода из функции

Я использую strtok() для токенизации моей строки в функции. После копирования значений в глобальный массив char я печатаю значения, чтобы обеспечить функциональность. Все в порядке, но когда я хочу получить к ним доступ, они уничтожаются.

это код:

#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;
}

это вывод enter image description here

Я хочу присвоить значения структурам, но они отсутствуют.

volatile не делает того, что вы думаете. Просто удалите его.
aschepler 09.04.2022 13:46
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
2
1
57
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Внутри функции объявлен локальный массив с автоматическим временем хранения

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

который не будет живым после выхода из функции.

Итак, массив указателей

volatile char *token_temp[30];

будет содержать недопустимые указатели, и разыменование этих указателей приведет к неопределенному поведению.

Вам нужно, например, динамически выделить массив символов для каждой строки, извлеченной из массива my_tokenised_string_buffer.

Другой подход - объявить массив my_tokenised_string_buffer как имеющий статическую продолжительность хранения, указав ключевое слово static

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

Дело в том, что вызовы strtok дают указатели на кусочки вашего my_tokenised_string_buffer. Но при выходе из функции my_tokenised_string_buffer выходит за пределы области действия и, таким образом, переопределяется новыми данными, которые вы помещаете в стек. Чтобы избежать этого, у вас есть 2 решения:

Или my_tokenised_string_buffer никогда не выходит за рамки, составляя следующую программу:

#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;
}

или вы копируете свои токены каждый раз, когда получаете новый, с помощью malloc. Однако вам нужно будет управлять последним токеном по-другому:

#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;
}

Вы можете использовать strdup вместо malloc, а затем strcpy.

aschepler 09.04.2022 13:45

Большое спасибо . ваше руководство очень ясное и полезное. есть ли у вас какие-либо рекомендации, как использовать strdup()?

momo 09.04.2022 14:30

@momo Просто кажется token_temp[0] = strdup(token);, посмотрите справочные страницы, они документируют каждую функцию стандартной библиотеки. Спасибо @aschepler за эту функцию, я не знал

Naeio 09.04.2022 21:20

strtok() — запутанная и подверженная ошибкам функция. Указатель, который он возвращает, указывает на токенизированную строку (которая модифицируется для этой цели). Сохранение этих указателей в глобальном массиве, который, кстати, не требует квалификации ne volatile, приводит к неопределенному поведению после возврата функции, поскольку массив my_tokenised_string_buffer больше недействителен.

Вы должны выделить копии токенов и взять целевой массив в качестве аргумента.

Вот модифицированная версия:

#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;
}
Ответ принят как подходящий

Вы можете использовать этот код для решения вашей проблемы:

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;
}

касательно:

token_temp[toknum]= token;

Это просто копирует указатели, на самом деле необходимо скопировать данные.

Предложить:

token_temp[ toknum ] = strdup( token );

который создаст копию данных, а затем поместит указатель на эту копию в массив

Другие вопросы по теме