C - 函数不在输入字符串末尾终止,导致分段错误

时间:2016-09-22 01:47:54

标签: c string segmentation-fault

免责声明:这是家庭作业的一部分,但不是整个作业。

我的任务是创建一个“tokenizer”对象,通过每次调用TKGetNextToken返回一次,检索由空格分隔的标记,并对返回的标记执行一系列操作。

但TKGetNextToken函数的行为并不应该如此。应该发生的是:

  1. 通过输入字符串前进,直到找到非空格字符。
  2. 继续前进输入字符串,直到遇到空格或NULL(表示字符串结尾),将字符添加到新的c字符串
  3. 如果遇到空格,则返回c字符串,字符串中的当前位置保存在TokenizerT结构中。
  4. 如果遇到NULL,则返回c字符串,并将NULL存储在TokenizerT结构中,以便对TKGetNextToken的所有后续调用都返回NULL。
  5. 但是,该函数不会在字符串的末尾停止,而是直接吹过它并打印出内存中的所有内容,直到程序崩溃。我无法弄清楚为什么会这样。

    这是代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    struct TokenizerT_ {
        char *currentToken;
    };
    
    typedef struct TokenizerT_ TokenizerT;
    
    
    char *TKGetNextToken(TokenizerT *tk) {
        char *cp = tk->currentToken;
    
        while (cp != NULL && isspace(*cp)) {
            cp++;
        }
    
        if (cp == NULL) {
            tk->currentToken = NULL;
            return NULL;
        }
    
        int size = 0;
        char *token = malloc(sizeof(char));
    
        while (cp != NULL && !isspace(*cp)) {
            size++;
            token = realloc(token, size * sizeof(char));
            token[size - 1] = *cp;
            cp++;
        }
    
        token = realloc(token, (size + 1) * sizeof(char));
        token[size] = NULL;
    
        tk->currentToken = cp;
        return token;
    }
    
    TokenizerT *TKCreate(char *ts) {
        TokenizerT *tokenizer = malloc(sizeof(TokenizerT));
        tokenizer->currentToken = ts;
    
        return tokenizer;
    }
    
    void TKDestroy(TokenizerT *tk) {
        free(tk);
    }
    
    int main(int argc, char **argv) {
    
        TokenizerT *tok = TKCreate(argv[1]);
        char *token = TKGetNextToken(tok);
    
        while (token) {
            printf("\'%s\'\n", token);
            token = TKGetNextToken(tok);
        }
    
        TKDestroy(tok);
        return 0;
    }
    

    以下是命令行参数“100 200 300 400”的示例输出。它显然是从输入字符串之外的内存中打印出来的。

    '100'
    '200'
    '300'
    '400'
    ''
    '╘jÉ'
    '╘hÉ'
    ''
    ''
    ''
    ''
    ''
    

    从gdb输出

    Program received signal SIGSEGV, Segmentation fault.
    0x00401476 in TKGetNextToken (tk=0x701720) at test.c:28
    28          while (cp != NULL && !isspace(*cp)) {
    (gdb) backtrace
    #0  0x00401476 in TKGetNextToken (tk=0x701720) at test.c:28
    #1  0x0040151e in main (argc=2, argv=0x700cf0) at test.c:60
    

1 个答案:

答案 0 :(得分:2)

在你的两个while循环中,条件应该包括对空字符的测试。 “没有遇到字符串末尾的空字符”的相应测试是*cp,因此使用:

while ( cp != NULL && *cp && !isspace( *cp ) )

我感觉cp != NULL测试是一个没有更多令牌的测试,在这种情况下,它们可能应该被排除在while循环之外。如果这是错误的并且它们是字符串结尾测试,那么它们应该被*cp测试替换。