关于C语言函数strtok引发的思考

  欢迎参与讨论,转载请注明出处。

前言

  近期遇到个C语言的课题作业,要求完成parse功能(以空格、回车、TAB为分割符分割字符串,输出结果且返回数组。)该功能涉及到strtok函数的一些问题,特此开贴记录。

详解

  以下为程序源码:

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

struct ListNode {
    char * value;
    struct ListNode * next;
};

char ** parse(char * line) {
    if (line == NULL) {
        return NULL;
    }

    static char delim[] = " \t\n"; /* SPACE or TAB or NL */
    int count = 0;
    char * token;
    char ** newArgv;
    char str[strlen(line)];

    strcpy(str, line);
    token = strtok(str, delim);

    if (token == NULL) {
        return NULL;
    }

    struct ListNode * head = (struct ListNode *)malloc(sizeof(struct ListNode));
    struct ListNode * cur = head;
    cur->value = token;
    count ++;

    while (1) {
        token = strtok(NULL, delim);

        if (token == NULL) {
            break;
        }

        cur->next = (struct ListNode *)malloc(sizeof(struct ListNode));
        cur = cur->next;
        cur->value = token;
        count ++;
    }

    newArgv = (char **)malloc((count + 1) * sizeof(char *));
    cur = head;

    for (int i = 0; i < count; i++) {
        newArgv[i] = (char *)malloc(strlen(cur->value) * sizeof(char));
        strcpy(newArgv[i], cur->value);
        printf("[%d] : %s\n", i, cur->value);
        free(cur);
        cur = cur->next;
    }

    newArgv[count] = NULL; //tail

    return newArgv;
}

int main() {
    char ** argv = parse("system program");

    return 0;
}

第一个问题

  首先第一个问题便是这里:

    char str[strlen(line)];

    strcpy(str, line);
    token = strtok(str, delim);

  最初尝试直接把parse函数的参数line直接作为strtok函数的第一参数填入,结果不行。查阅文档后发现strtok的声明为:

    //param: str -- 要被分解成一组小字符串的字符串。
    //param: delim -- 包含分隔符的 C 字符串。
    //return: 该函数返回被分解的最后一个子字符串,如果没有可检索的字符串,则返回一个空指针。
    char *strtok(char * str, const char * delim);

  可以发现,第一参数char * str要求的并非const,而我在调用时填入的参数为‘system program’,这种字符串数据是作为‘const char[]’保存在字符串常量区的,故不符合参数需求。需要重新申请一片栈空间复制line的内容再作为参数填入。

第二个问题

  由此衍生的第二个问题便是:为何要为newArgv[i]申请新的空间,而非newArgv[i] = cur->value;

    newArgv[i] = (char *)malloc(strlen(cur->value) * sizeof(char));
    strcpy(newArgv[i], cur->value);

  这一点的原因主要是 strtok返回的字符串其实并非新的副本,而是从str上截取的一部分而已。 而cur->value便是来自于str,且str是拥有生命周期的栈数据,而如果将这样的部分保存在newArgv后返回到外部,便会因为生命周期问题,导致数据被回收。这将会产生很可怕的后果。所以必须申请新的空间,形成复制。

后记

  没有垃圾回收的C/C++,编程时必须对内存的分配和流向必须要有十分清晰的认识,不然就很容易发生内存泄漏和野指针现象。慎之、慎之。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值