我是 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/