我有一个基本上是重写strtok_r
的函数,因为该函数让我感到悲伤。
char *betterStrtok(char *str, char *delim, char **loc)
{
int iter = 0;
char *tmp;
if(str)
{
char mod[strlen(str) + 2];
char *out = malloc(strlen(str) + 2);
char curr = str[0];
strcpy(mod, str);
while(curr)
{
tmp = strchr(delim, curr);
if(tmp)
{
mod[iter] = 0;
strcpy(out, mod);
*loc = &mod[iter + 1];
//printf("Inside function: \"%s\"\n", *loc);
return out;
}
if(curr)
{
curr = mod[++iter];
}
else
{
*loc = &mod[0];
strcpy(out, mod);
return out;
}
}
return NULL;
}
else
{
char mod[strlen(*loc) + 2];
strcpy(mod, *loc);
char *tloc = malloc(sizeof loc + 2);
char *out = malloc(strlen(*loc) + 2);
char curr = mod[0];
while(curr)
{
tmp = strchr(delim, curr);
if(tmp)
{
mod[iter] = 0;
strcpy(out, mod);
tloc = &mod[iter + 1];
strcpy(*loc, tloc);
return out;
}
if(curr)
{
curr = mod[++iter];
}
else
{
*loc = &mod[0];
strcpy(out, mod);
return out;
}
}
return NULL;
}
}
所以我的问题是*loc
在第一次传递后有适当的东西,当我检查函数外面的内容时,除了最后一个字符外,它主要在那里一些奇怪的东西。让我们说这是设置:
char *addr = malloc(60);
char **supaddr = &addr;
char *strtotok = "Hello, world!";
char *thetok;
thetok = betterStrtok(strtotok, ",", supaddr);
printf("Outside function: \"%s\"\n", addr);
在返回之前和调用函数之后立即添加print语句显示如下:
Inside function: " world!"
Outside function: " w"
问题是:如何防止字符串改变或如何做其他事情以便我可以保存"休息"没有返回它的原始字符串?
答案 0 :(得分:1)
如果您开始使用自己的实现替换标准库(或POSIX)函数,请首先仔细查看如何使用该工具。例如,比较fgets()
和getline()
。
如果我是你,我可能会使用
size_t extract_token(const char *src_ptr, const size_t src_len,
char **token_ptr, size_t *token_size, size_t *token_len);
从src_len
的{{1}} - 字节缓冲区中提取令牌。 (与基于字符串的方法不同,它可以处理嵌入的nul字节。)
返回值是src_ptr
消耗的字符数。令牌被复制(扩展?)到动态分配的src_ptr
。分配的长度为token_ptr
,令牌的长度为token_size
。
如果token_len
只遇到空格但没有令牌,则返回消耗的空白字符数,零指定给extract_token()
。为简单起见,我们假设函数始终设置token_len
;如果成功则为零,如果发生错误则为非零错误代码。
标记从标准输入读取的行的简单循环将是
errno
请注意,在阅读具有清晰记录和字段格式的文件(如CSV文件)时,我更喜欢使用类似char *line_ptr = NULL;
size_t line_size = 0;
ssize_t line_len;
long line_num = 0;
char *token_ptr = NULL;
size_t token_size = 0;
size_t token_len;
char *cur, *end;
size_t n;
while (1) {
line_len = getline(&line_ptr, &line_size, stdin);
line_num++;
if (line_len < 1) {
if (ferror(stdin) || !feof(stdin)) {
fprintf(stderr, "Standard input: Line %ld: Read error.\n", line_num);
return EXIT_FAILURE;
}
break;
}
cur = line_ptr;
end = line_ptr + line_len;
while (1) {
if (cur >= end) {
errno = 0;
cur = end;
break;
}
n = extract_token(cur, (size_t)(end - cur),
&token_ptr, &token_size, &token_len);
if (errno) {
/* cur + n is the offending character in input */
fprintf(stderr, "Standard input: Line %ld: Cannot tokenize line.\n", line_num);
exit(EXIT_FAILURE);
}
/* Do something with token;
token_ptr points to the token,
token_len is the length of the token
token_size is the size allocated for the token
*/
}
}
/* Since the line and token buffers are no longer needed,
free them. I like to clear the variables too, just in
case.
*/
free(line_ptr);
line_ptr = NULL;
line_size = 0;
free(token_ptr);
token_ptr = NULL;
token_size = 0;
的界面直接从文件中读取令牌,
getline()
或
int next_field(char **ptr, size_t *size, size_t *len, FILE *in);
int next_record(FILE *in);
其中int next_wfield(wchar_t **ptr, size_t *size, size_t *len, FILE *in);
int next_wrecord(FILE *in);
(或广泛输入的next_field()
)获取当前记录中的下一个字段,最好处理取消引用和解除转义,next_wfield()
跳过任何剩余字段当前记录,并移至下一记录的开头。
使用next_wrecord()
或fgetc()
实现上述代码非常简单(即使实施了CSV引用规则),尽管使用更高级的方法不会尽可能快。由于CSV和其他此类文件格式无论如何都不是最佳的,因此速度的轻微损失通常可以忽略不计/不可察觉。最重要的是,如果您尝试一下,您会发现使用fgetwc()
/ next_field()
的代码非常强大,并且易于长期阅读,编写和维护。
答案 1 :(得分:0)
答案在评论中。事实证明,如果我将mod
更改为指针,它可以完美运行。