关于C语言函数strtok引发的思考
2017-10-13 17:18
274 查看
欢迎参与讨论,转载请注明出处。
最初尝试直接把parse函数的参数line直接作为strtok函数的第一参数填入,结果不行。查阅文档后发现strtok的声明为:
可以发现,第一参数char * str要求的并非const,而我在调用时填入的参数为‘system program’,这种字符串数据是作为‘const char[]’保存在字符串常量区的,故不符合参数需求。需要重新申请一片栈空间复制line的内容再作为参数填入。
这一点的原因主要是 strtok返回的字符串其实并非新的副本,而是从str上截取的一部分而已。 而cur->value便是来自于str,且str是拥有生命周期的栈数据,而如果将这样的部分保存在newArgv后返回到外部,便会因为生命周期问题,导致数据被回收。这将会产生很可怕的后果。所以必须申请新的空间,形成复制。
前言
近期遇到个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" 4000 , 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++,编程时必须对内存的分配和流向必须要有十分清晰的认识,不然就很容易发生内存泄漏和野指针现象。慎之、慎之。相关文章推荐
- 关于考试作弊引发的关于诚信的思考
- 一个窗帘引发的——关于测试及测试活动的思考(一)
- 由一道关于位运算的程序设计题引发的思考
- 由OUI-10035和OUI-10033错误引发的关于oraInventory目录位置的思考
- 一次代码review引发的关于单例模式的思考
- 由linux下的多进程编程引发的关于进程间隔离的思考
- 各种关于ViewGroup中touch事件传递引发的思考
- 一骑绝尘引发的思考–关于hive程序员是否需要学习mapreduce
- 关于DML命令与DDL命令引发的对事物特性的思考
- 关于考试作弊引发的关于诚信的思考
- C语言中关于strcry 引发的思考
- 关于一个小学算数引发的思考
- 一次关于使用status作为变量引发的bug及思考
- The sound of silence引发的关于互联网以及教育的利弊思考
- [赏析]stack overflow引发的关于获取知识的思考
- 关于数组去重问题引发的一系列思考
- 一骑绝尘引发的思考–关于hive程序员是否需要学习mapreduce
- 四极管:一个需求引发的关于平板电脑的思考
- 由一个问题引发的思考——关于数据库的外键约束
- 关于员工离职引发的思考