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

标签 c arrays variable-assignment

我是 C 语言的新手,希望能够很好地理解来自 Java 背景的字符数组赋值。我使用 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;
}

最佳答案

您已经为这些值分配了存储空间。主要错误是您使用赋值时认为它会复制您的字符串。相反,它覆盖了指向 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])never 任何其他的(它们只是指向该 block 的指针) .

关于c - c char** 数组赋值的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43990003/

相关文章:

java - 如何使用 java 8 迭代 JsonArray

erlang - 理解 spawn 的返回值

c - C 指针的疑问

连接两个字符串 : C

c - C : how this function works? 中的按位运算符

arrays - MongoDB - 如何访问数组中的对象

arrays - 从 bash 到 ash shell : how to handle arrays defined by input? 的翻译

c++ - 为什么 std::unique_ptr 重置与赋值不同?

php - 从 100 到 0 的倒计时,在 PHP 中没有分配

c - Main.c :3:9: error: expected ‘=’ , ‘,’ 、 ‘;’ 、 ‘asm’ 或 ‘__attribute__’ 位于 ‘{’ token 之前