Работа с указателем на символ и написать функцию для разделения текстовых слов - PullRequest
0 голосов
/ 11 марта 2020

Я хотел бы написать функцию, которая будет принимать указатель на char и int (начальный индекс сканирования) в качестве входных данных и возвращать первое слово после него. В чем проблема с этим кодом? Нет слова возвращается. Проблема, откуда включить один из символов-разделителей, создана. Чтобы набросать символы.


char *setWord(char string[], int *n) {
    char word[20] = "\0";
    string += *n;
    while (*string == ','||*string == '\t' || *string == '\n'
    || *string == ' '|| *string == '.' || *string == '!' || *string == '?') {
        string++;
       (*n)++;
    }
    int i = 0;
    while (*string != ',' && *string != '\t'
                     && *string != '\n' && *string != ' ' &&
                     *string != '.' && *string != '!' &&
                     *string != '?') {
        word[i] = *string;
        string++;
        (*n)++;
        i++;
    }
    char *words = word;


    return words;
}

Ответы [ 2 ]

1 голос
/ 11 марта 2020

Вы хотите вернуть строку C ([указатель на] массив символов с нулевым символом в конце) из функции. Проблема в том, что массивы не являются объектами первого класса в C, поэтому вы можете только передавать и возвращать указатели. И любой автоматический c массив достигнет своего конца жизни в конце блока, в котором он объявлен. Поэтому, если вы красиво встроите свое слово в автоматический c массив и вернете на него указатель, то, что делает ваш текущий код, массив будет уничтожен, когда функция вернет только оставив висящий указатель.

Существует 2 возможных способа, каждый со своими плюсами и минусами:

  1. использование выделенной памяти (ответ @ ChrisMM).

    Может быть рекурсивным и поточно-ориентированным , Просто вы должны документально подтвердить, что вызывающая сторона будет отвечать за освобождение блока памяти и как это должно быть сделано: free, если вы использовали malloc, delete[], если вы использовали new[].

  2. использовать stati c память

    Быстрое исправление - написать:

    static char word[20];
    

    Массив stati c будет действовать до конца программы, так что вы можете безопасно используйте его в вызывающем абоненте, и никакой очистки не требуется. Но в многопоточной программе массив stati c будет общим для всех потоков, поэтому вы должны убедиться, что только один поток использует его одновременно и что другой поток не изменил его, когда вы хотите его использовать , Короче говоря: не используйте это, если ожидается, что функция будет использоваться в многопоточной программе.

1 голос
/ 11 марта 2020

Как уже упоминалось в комментарии, у вас есть UB, поскольку вы возвращаете указатель на локальную переменную (words). Первоначально у вас также было n++ в вашем l oop вместо (n*)++, который также является UB. Вам нужна проверка ошибок в вашем коде, но следующее работает, и все еще остается с char* (без проверки ошибок):

#include <string>
#include <iostream>

char *setWord( char string[], int *n ) {
    char word[20] = { 0 };
    string += *n;
    while ( *string == ',' || *string == '\t' || *string == '\n' || *string == ' ' || *string == '.' || *string == '!' || *string == '?' ) {
        string++;
        ( *n )++;
    }
    int i = 0;
    while ( *string != ',' && *string != '\t' && *string != '\n' && *string != ' ' && *string != '.' && *string != '!' && *string != '?' ) {
        word[i++] += *string;
        string++;
        ( *n )++;
    }

    std::cout << word;
    char *words = new char[i + 1];
    strncpy( words, word, I + 1 );

    return words;
}

int main() {
    char str[] = "hello world!";
    int n = 5;
    char *word = setWord( str, &n );

    delete[] word;

    return 0;
}

Используя std::string, вы можете сделать (без проверки ошибок):

std::string setWord( std::string string, int *n ) { // copy on purpose
    int start = *n;
    *n = string.length();
    size_t end = string.find_last_of( ",\t\n .!?" );
    string = string.substr( string.find_first_not_of( ",\t\n .!?", start ) );
    if ( end != std::string::npos ) {
        string = string.substr( 0, string.find_last_of( ",\t\n .!?" ) ); // because it's not end
        *n = (int)end;
    }
    std::cout << string;
    return string;
}
...