如何在没有随机符号的情况下正确标记 C 中的字符串?
How to properly tokenize strings in C without random symbols?
我目前正在学习 C 并尝试编写一个函数来标记由空格分隔的 paragraph/string 和包含所有标记的数组 return。我被卡住了,因为我无法弄清楚为什么某些令牌会携带原始字符串中没有的符号。有人可以帮我弄清楚我的代码有什么问题吗?另外,我不想在代码中添加额外的库或使用像 strtok() 这样的函数。
char **tokenizeParagraph(char *paragraph) {
char *ptr = paragraph;
char words[MAX_WORDS][MAX_WORDLENGTH];
int wordIndex = 0;
int wordLen = 0;
while (*ptr) {
wordLen = 0;
while (*ptr && *ptr != ' ') {
wordLen++;
ptr++;
}
if (wordLen > 0) {
strncpy(words[wordIndex], paragraph, wordLen);
printf("%s\n", words[wordIndex]);
wordIndex++;
}
ptr++;
paragraph = ptr;
}
return words;
}
这是一个演示结果:
tokenizeParagraph("I'm currently learning C and trying to write a function to tokenize a paragraph/string delimited by spaces and return an array with all the tokens.");
Error Demo
非常感谢!
已编辑:
@Sourav Kannantha B 和@Finxx 建议的动态内存方法非常有帮助。然而,由于我不想添加 库,我将数组声明移出函数并将其作为参数传入,因此数组不会在函数 [= 之后用堆栈内存擦除28=]s.
char words[MAX_WORDS][MAX_CHARS];
void tokenizeParagraph(char words[MAX_WORDS][MAX_CHARS], char *paragraph)
您正在堆栈上创建变量 words
并在堆栈上 return 指向它的指针。但是,当您从函数 return 时,堆栈不再局限于您的程序,这意味着您的指针指向的某些内容可能会发生变化,从而导致未定义的行为。为了防止这种情况,更改此代码:
char words[MAX_WORDS][MAX_WORDLENGTH];
有了这个:
char** words = calloc(MAX_WORDS * MAX_WORDLENGTH, sizeof(char));
这将在堆上而不是堆栈上分配内存,尽管您需要 stdlib.h
才能包括在内。
@Finxx 已经建议的已经足够好了。但如果 wordLen 变化很大,你仍然可以改进它。
char **tokenizeParagraph(char *paragraph) {
char *ptr = paragraph;
char** words = malloc(sizeof(char*) * MAX_WORDS);
int wordIndex = 0;
int wordLen;
while (*ptr) {
wordLen = 0;
while (*ptr && *ptr == ' ') {
ptr++;
}
paragraph = ptr;
while (*ptr && *ptr != ' ') {
wordLen++;
ptr++;
}
if (wordLen > 0) {
words[wordIndex] = malloc(sizeof(char) * wordLen+1);
strncpy(words[wordIndex], paragraph, wordLen);
words[wordIndex][wordLen] = '[=10=]';
printf("%s\n", words[wordIndex]);
wordIndex++;
}
}
for(;wordIndex < MAX_WORDS; wordIndex++) {
words[wordIndex] = NULL;
}
return words;
}
另外,请注意 strncpy 不添加终止 NUL 字符。这可能是输出中出现随机字符的原因。
此外,不要忘记 free
从调用函数分配的内存。:
int main() {
...
char** words = tokenizeParagraph(para);
...
for(int i = 0; i < MAX_WORDS; i++) {
free(words[i]);
}
free(words);
...
return 0;
}
我目前正在学习 C 并尝试编写一个函数来标记由空格分隔的 paragraph/string 和包含所有标记的数组 return。我被卡住了,因为我无法弄清楚为什么某些令牌会携带原始字符串中没有的符号。有人可以帮我弄清楚我的代码有什么问题吗?另外,我不想在代码中添加额外的库或使用像 strtok() 这样的函数。
char **tokenizeParagraph(char *paragraph) {
char *ptr = paragraph;
char words[MAX_WORDS][MAX_WORDLENGTH];
int wordIndex = 0;
int wordLen = 0;
while (*ptr) {
wordLen = 0;
while (*ptr && *ptr != ' ') {
wordLen++;
ptr++;
}
if (wordLen > 0) {
strncpy(words[wordIndex], paragraph, wordLen);
printf("%s\n", words[wordIndex]);
wordIndex++;
}
ptr++;
paragraph = ptr;
}
return words;
}
这是一个演示结果:
tokenizeParagraph("I'm currently learning C and trying to write a function to tokenize a paragraph/string delimited by spaces and return an array with all the tokens.");
Error Demo
非常感谢!
已编辑:
@Sourav Kannantha B 和@Finxx 建议的动态内存方法非常有帮助。然而,由于我不想添加
char words[MAX_WORDS][MAX_CHARS];
void tokenizeParagraph(char words[MAX_WORDS][MAX_CHARS], char *paragraph)
您正在堆栈上创建变量 words
并在堆栈上 return 指向它的指针。但是,当您从函数 return 时,堆栈不再局限于您的程序,这意味着您的指针指向的某些内容可能会发生变化,从而导致未定义的行为。为了防止这种情况,更改此代码:
char words[MAX_WORDS][MAX_WORDLENGTH];
有了这个:
char** words = calloc(MAX_WORDS * MAX_WORDLENGTH, sizeof(char));
这将在堆上而不是堆栈上分配内存,尽管您需要 stdlib.h
才能包括在内。
@Finxx 已经建议的已经足够好了。但如果 wordLen 变化很大,你仍然可以改进它。
char **tokenizeParagraph(char *paragraph) {
char *ptr = paragraph;
char** words = malloc(sizeof(char*) * MAX_WORDS);
int wordIndex = 0;
int wordLen;
while (*ptr) {
wordLen = 0;
while (*ptr && *ptr == ' ') {
ptr++;
}
paragraph = ptr;
while (*ptr && *ptr != ' ') {
wordLen++;
ptr++;
}
if (wordLen > 0) {
words[wordIndex] = malloc(sizeof(char) * wordLen+1);
strncpy(words[wordIndex], paragraph, wordLen);
words[wordIndex][wordLen] = '[=10=]';
printf("%s\n", words[wordIndex]);
wordIndex++;
}
}
for(;wordIndex < MAX_WORDS; wordIndex++) {
words[wordIndex] = NULL;
}
return words;
}
另外,请注意 strncpy 不添加终止 NUL 字符。这可能是输出中出现随机字符的原因。
此外,不要忘记 free
从调用函数分配的内存。:
int main() {
...
char** words = tokenizeParagraph(para);
...
for(int i = 0; i < MAX_WORDS; i++) {
free(words[i]);
}
free(words);
...
return 0;
}