【问题标题】:Seg fault occurs when copying char pointer into array of char pointers将 char 指针复制到 char 指针数组时发生 Seg 错误
【发布时间】:2017-04-07 08:32:41
【问题描述】:

我正在从文件中读取一行文本,并尝试使用strtok() 将其拆分为空格,然后在名为tokenize 的函数中使用strcpy() 将每个标记存储在一个字符指针数组中。

代码:

/**
** Tokenizes contents of buffer into words
** Delimiter is a space character
*/
void tokenize(char *buffer, char *tokens[]){
    char *token = NULL;
    int i = 0;
    token = strtok(buffer, " ");
    while(token != NULL){
        strcpy(tokens[i], token);//seg fault line
        token = strtok(NULL, " ");
        i++;
    }
}

我假设,根据 K&R 中的函数描述,我的调用会起作用,因为我传递了一个 char 指针,这是 tokens[i] 应该取消引用的,以及另一个包含字符串内存地址的 char 指针复制,这就是token 应该是什么。但是,当我尝试strcpy 时,我遇到了段错误。

在通过调用fgets() 检索到一行后立即在main 中调用此函数。 buffer 被声明为 char buffer[MAXLINE_LEN - 1],它的大小为 100。tokens 被声明为 char *tokens[MAXLINE_LEN - 1]

main 中致电tokenize

while(fgets(buffer, MAXLINE_LEN, inputFile)){
    int choice;
    printf("%s", buffer);
    tokenize(buffer, tokens);
    /**
    ....
    */
}

我正在使用:gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

编辑: tokens 的声明(这发生在上面显示的 while 循环之前,在 main 中):

char *tokens[MAXLINE_LEN - 1];//MAXLINE_LEN - 1 = 100

int a;
for(a = 0; a < MAXLINE_LEN - 1; a++)
    tokens[a] = NULL;

【问题讨论】:

  • 您的问题与您没有向我们展示的 tokens 的声明/初始化有关。
  • tokens[i] = malloc(strlen(token)+1);strcpy(tokens[i], token); 之前
  • @BLUEPIXY 我必须为tokens 中的每个字符指针分配堆内存?我第一次在 main 中声明 tokens 时没有分配内存吗?
  • 请否决投票者澄清一下吗?
  • 指针在数组中分配。但不是指针指向的区域。

标签: c pointers strcpy


【解决方案1】:

我能想到四种可能

  1. tokensNULL 或未初始化
  2. tokens 已初始化,但您没有分配足够的空间。如果您为四个令牌分配空间但strtok() 解析五个令牌怎么办?
  3. tokens 的各个元素是 nNULL 或未初始化
  4. 您没有在每个 elemant 中分配足够的空间来复制令牌字符串。

其中一项或多项几乎肯定适用于您的代码。解决它的一种方法是在函数内部完全分配 tokens 并在指针中返回它(以计数作为返回值)。

enum
{
    CHUNK_SIZE = 16; // A trick to get an int constant in C that works everywhere a #define works
};

size_t tokenize(char *buffer, char **tokenRet[])
{
    size_t capacity = 0;
    char** tokens = NULL;
    size_t count = 0;
    char *token = NULL;
    token = strtok(buffer, " ");
    while(token != NULL)
    {
        count++;
        if (count > capacity)
        {
            capacity += CHUNK_SIZE;
            tokens = realloc(tokens, capacity * sizeof *tokens);
        }
        tokens[count - 1] = strdup(token);//strdup mallocs space and copies the string into it
        token = strtok(NULL, " ");
    }
    *tokenRet = tokens;
    return count;
}

这样称呼

char** myTokens = NULL;
size_t tokenCount = tokenize(buffer, &myTokens);

然后整理到最后,free()myTokens的第一个tokenCount元素,然后释放myTokens

【讨论】:

  • `**tokenRet[] 是 char 指针的三维数组吗?为什么我需要这个?我是 C 新手,尤其是指针对我的大脑产生了影响。凌晨 5 点
  • tokenRet 是指向 char 的指针数组的指针。在这种情况下,您可以将其视为指向字符串数组的指针。它需要额外间接的原因是,tokenize 可以返回到它的调用者,并将在那里声明的字符串数组更改为它从缓冲区构建的数组。
  • char* myTokens[] = NULL; --> char** myTokens = NULL;
【解决方案2】:

“char *tokens[]”的大小是多少? “char *buffer”中的令牌可能比令牌[] 可以容纳的更多。 另外,您是否为指针数组分配了内存?

【讨论】:

  • 正如我在问题中提到的,tokens 被声明为大小为 100。buffer 不能容纳超过 100 个令牌,因为它包含 100 个字符。那么,buffer 中最多可以有 50 个标记,如果每个标记是单个字符,每个标记之间有一个空格。
  • 在传递给 tokenize() 之前,您是否为每个 tokens[] 指针分配了内存?
  • 不,我没有。我假设当我声明数组时它们会被分配内存,从表面上看,它们有 8 个字节,这对于我的机器来说是正确的指针大小。如果我在将它们传递给标记化之前确实使用了 malloc 调用,我将不知道为每个指针分配多少。另外,我将为/分配什么内存?
猜你喜欢
  • 2021-01-26
  • 2023-03-08
  • 1970-01-01
  • 2013-05-15
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
相关资源
最近更新 更多