【问题标题】:Split line into words and put them in char array using strtok将行拆分为单词并使用 strtok 将它们放入 char 数组中
【发布时间】:2020-05-08 01:03:15
【问题描述】:

我有这个简单的行解析器到标记函数中...... 但是我缺少一些东西。

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** 单词,但我有第一个 malloc 内存。像这样

  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 上。在它到达while循环之前

【问题讨论】:

  • char * 行是字符串是的!像一行字符
  • xing,你到底是什么意思?我还需要分配什么?
  • 请在您的问题中添加一个简单的main(),在其中定义示例行并调用parse_line() 函数
  • xing,如果我为第一个单词的 exac 大小分配内存,那么如果第二个更大,我会遇到问题。
  • 为什么从一开始就分配一个安全的大数字会出现问题??

标签: c segmentation-fault malloc strtok


【解决方案1】:
while( word != NULL ) {
    word = strtok(NULL, " ");
    words[wordc]=(char*)malloc(256*sizeof(char));
    strcpy(words[wordc++],word );
}

在行尾,word 将始终设置为 NULL(如预期的那样),因此 strcpy(words[wordc++],word ) 将是未定义的行为(可能会崩溃)。

您需要重新组织循环,以免尝试复制 NULL 字符串。

@jxh 建议使用此解决方案来解决 word 在您的任一 strcpys 中成为 NULL 的问题。

/* 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, " ");
}

【讨论】:

  • 这对我没有帮助。我在 while 内的第一个 strtok 之后放了另一个 if 来测试 id word==NULL。但什么都没有。我又得到了分段f
  • 使用调试器(或 printfs)精确定位问题所在。
  • 如果您展示代码应该是什么样子的示例,OP 将更有可能验证您的答案,并且您获得复选标记的可能性就越大。
  • 您的建议也适用于首次致电strtok
  • @jxh - 我特别避免为看似“家庭作业级别”的问题添加示例代码。必须再看一遍,但你的重构不是我会怎么做的 ;-) 编辑:你编辑的重构 IS 我会怎么做:-) :-)
【解决方案2】:

以下建议的代码:

  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

【讨论】:

    【解决方案3】:

    你的答案是对的!但我有 segF 再次因为阅读!!!!! 我没有注意到,当我运行程序时,它并没有停止读取 read 的输入! 相反,它正在通过它。我所做的是我将 read 更改为 fgets 并且它有效! 还有你的改变! 谁能给我解释一下????为什么它不会在读取功能处停止??

    【讨论】:

    • 'read()' 阻塞,直到输入某种终止符或读取最大字符数。您要输入额外的return 密钥吗?
    猜你喜欢
    • 2023-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多