C99:为什么我的字符串会改变?

时间:2017-03-24 00:21:12

标签: c c99

我有一个基本上是重写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"

问题是:如何防止字符串改变或如何做其他事情以便我可以保存"休息"没有返回它的原始字符串?

2 个答案:

答案 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更改为指针,它可以完美运行。