Разбейте строку на слова и поместите их в массив символов с помощью strtok - PullRequest
2 голосов
/ 22 января 2020

У меня есть этот простой анализатор строк в функции токенов ... Но что-то мне не хватает.

int parse_line(char *line,char **words){

   int wordc=0;

   /* get the first token */
   char *word = strtok(line, " ");
   words[wordc]=(char*)malloc(256*sizeof(char));
   strcpy(words[wordc++],word );

   /* walk through other tokens */
    while( word != NULL ) {
        word = strtok(NULL, " ");
        words[wordc]=(char*)malloc(256*sizeof(char));
        strcpy(words[wordc++],word );
    }

    return wordc;
}

Когда я запускаю его, я получаю ошибку сегментации! В качестве первого аргумента я даю строку char [256] и в качестве второго, конечно, слова char **, но у меня есть первая память mallo c для этого. вот так

  char **words = (char **)malloc(256 * sizeof(char *));
main:
.
.
.
char buffer[256];
char **words = (char **)malloc(256 * sizeof(char *));
.
.
.
n = read(stdin, buffer, 255);
if (n < 0){
   perror("ERROR");
   break;
}

parse_line(buffer,words);

Когда программа выполняет parse_line, она завершается с ошибкой сегментации

Находит, где происходит ошибка сегмента. И это здесь:

strcpy(words[wordc++],word );

И, в частности, на первом strcpy. Еще до того, как оно достигнет l oop

Ответы [ 3 ]

3 голосов
/ 22 января 2020
while( word != NULL ) {
    word = strtok(NULL, " ");
    words[wordc]=(char*)malloc(256*sizeof(char));
    strcpy(words[wordc++],word );
}

В конце строки, word всегда будет установлен на NULL (как и ожидалось), поэтому strcpy(words[wordc++],word ) будет неопределенным поведением (вероятно, cra * sh).

Вам необходимо реорганизовать l oop, чтобы никогда не пытаться скопировать строку NULL.

@ jxh предлагает это решение, которое устраняет проблему word, являющуюся NULL в любом из ваших strcpy s.

/* get the first token */
char *word = strtok(line, " ");

while( word != NULL ) {
    words[wordc]=(char*)malloc(256*sizeof(char));
    strcpy(words[wordc++],word );
    word = strtok(NULL, " ");
}

Я бы сделал это (использует меньше памяти)

/* get the first token */
char *word = strtok(line, " ");

while( word != NULL ) {
    words[wordc++] = strdup(word);
    word = strtok(NULL, " ");
}
1 голос
/ 22 января 2020

следующий предложенный код:

  1. безупречная компиляция
  2. выполняет желаемую функциональность
  3. правильно проверяет ошибки
  4. отображает результаты в пользователь
  5. не может передать всю выделенную память free(), поэтому имеет много утечек памяти

и теперь предложенный код:

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

// avoid 'magic' numbers in code
#define MAX_WORDS 256
#define MAX_LINE_LEN 256


int parse_line( char *line, char **words )
{
    int wordc=0;

    /* get the first token */
    char *token = strtok(line, " ");
    while( wordc < MAX_WORDS && token ) 
    {   
        words[wordc] = strdup( token );
        if( ! words[wordc] )
        {
            perror( "strdup failed" );
            exit( EXIT_FAILURE );
        }

        // implied else, strdup successful

        wordc++;

        // get next token
        token = strtok(NULL, " ");
    }

    return wordc;
}



int main( void )
{
    char buffer[ MAX_LINE LENGTH ];

    // fix another problem with OPs code
    char **words = calloc( MAX_WORDS, sizeof( char* ) );
    if( ! words )
    {
        perror( "calloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, calloc successful

    // note: would be much better to use 'fgets()' rather than 'read()'
    ssize_t n = read( 0, buffer, sizeof( buffer ) );
    if (n <= 0)
    {
       perror("read failed");
       exit( EXIT_FAILURE );
    }

    // implied else, read successful

    // note: 'read()' does not NUL terminate the data
    buffer[ n ] = '\0';   

    int count = parse_line( buffer, words );

    for( int i = 0; i < count; i++ )
    {   
        printf( "%s\n", words[i] );
    } 
}

здесь Типичный запуск программы:

hello old friend  <-- user entered line
hello
old
friend
0 голосов
/ 22 января 2020

Ваши ответы верны! НО у меня был segF снова из-за чтения !!!!! я не заметил, что когда я запускаю программу, она не останавливается для чтения с входа при чтении! Вместо этого это передавало это. То, что я сделал, я изменил читать на fgets, и это сработало !!! С вашими изменениями! Может кто-нибудь объяснить мне это ???? Почему это не останавливается на функции чтения ??

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...