c char **数组赋值的奇怪行为

时间:2017-05-15 22:54:55

标签: c arrays variable-assignment

我是C语言的新手,希望能够很好地理解来自Java背景的char数组赋值。我使用stringTok()将本地sentence[]数组拆分为单个数组字,并希望将该字分配给传入的char ** tokens。我收到以下输出:

value of i:4   
len:1 ,  
len:1 ,  
len:6 ,8?k  
len:0 ,  

有些人有价值(指定的值是胡言乱语)而有些人没有。我最初认为我必须为字符数组中的每个字符分配内存。但是,这似乎也没有用。所以,我想我一定做错了。我也尝试使用tokens[4][10]代替char ** tokens,但也没有任何区别。所以,我被困在这里已有一段时间了。

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

void  stringTok(char** tokens)
{
    int i = 0;
    char sentence[] = "jake is really cool.";
    char *word = strtok(sentence, " .");

    while (word != NULL)
    {
        //printf("%s\n", word);
        tokens[i++] = word;
        word = strtok(NULL, " .");
    }
    printf("value of i:%d\n", i);
    tokens[i] = NULL;
}

int main()
{ 
    char **cmdArr = calloc(5, sizeof(char*));

    for (int i = 0; i < 5; i++)
        cmdArr[i] = (char*)calloc(10, sizeof(char));
    stringTok(cmdArr);
    for(int i = 0; i < 4; i++)
    {
        printf("len:%ld ,", strlen(cmdArr[i]));
        printf("%s\n", cmdArr[i]);
    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

您已为这些值分配了存储空间。主要的错误是你使用赋值思维它会复制你的字符串。相反,它覆盖了指向strtok返回的临时指针。

快速解决方法是:

while (word != NULL) {
    strcpy(tokens[i++], word);
    word = strtok(NULL, " .");
}

你应该小心点。您的字符串仅支持10个字符(包括空终止符)。通常,您会使用strncpy,如果源字符串对于您可用的存储量太长,它将停止。这有助于避免诸如缓冲区溢出之类的不良内容,这些内容会产生未定义的行为并产生通常在网络攻击中利用的漏洞。

更安全的方法可能是让您的标记生成器执行分配。

int tokenize( const char *sentence, char** tokens, int max_tokens )
{
    const char * delim = " .";
    int count = 0;

    // Make copy of sentence for strtok
    int len = strlen(sentence);
    char *copy = malloc(len+1);
    if( !copy ) return 0;
    strncpy( copy, len, sentence );
    copy[len] = '\0';

    // Allocate and copy tokens
    for( char *word = strtok(copy, delim);
         word && count < max_tokens;
         word = strtok(NULL, delim) )
    {
        int len = strlen(word);
        tokens[count] = malloc(len+1);
        if( !tokens[count] ) break;
        strncpy( tokens[count], len, word );
        tokens[count][len] = '\0';
        count++;
    }

    return count;
}

现在,这有点傻。由于您已经复制了原始文件并且strtok将要插入终结符,因此无需分配和复制所有内容。您可以将copy存储在tokens[0]中,然后将word存储在每个后续指针中。调用者只需要知道清理内存它只需要free(tokens[0])永远其他任何一个(只是指向该块的指针)。