从C中的函数定义并返回二维字符串数组



我想使用一个二维字符串数组(new_sentence(,它是我在主函数(或任何其他函数(中名为parse((的函数中生成的。我写的代码如下。

strtok(( strcpy((strong>parse((函数中new_sentence数组的所有元素。但是,我无法将此数组传递到主函数中。

我可以理解parse((函数的返回值和主函数内部的定义存在问题。我对类似的问题做了一些研究,但没能搞清楚。你能帮我吗?

#include <string.h>
#include <stdio.h>
const char *parse(char *s);
int main () {

char str[1000] = "This-is-test-sentence";

char *n_sentence = parse(str);
for (int j = 0; j<4; j++)
{
printf("%sn", n_sentence[j]);
}
return 0;
}
const char *parse(char *s)
{
char *delim = "-";
char *token;
char new_sentence[4][15];
token = strtok(s, delim);
int numberOfWord = 0;
while( token != NULL ) {
strcpy(new_sentence[numberOfWord], token);
token = strtok(NULL, delim);
numberOfWord++;
}

return new_sentence;
}

这是解决问题的一种方法,基于您的代码和我自己的代码片段:

#include <string.h>
#include <stdio.h>
#define MAX_WORDS 1000
int parse(char *s, char *n_sentence[], int max_size);
int main () {
char str[] = "This-is-test-sentence";
char* n_sentence[MAX_WORDS];
int tot_words = parse(str, n_sentence, MAX_WORDS);
printf("Total number of words: %dn", tot_words);
for (int j = 0; j<tot_words; j++)
{
printf("%sn", n_sentence[j]);
}
return 0;
}
int parse(char *s, char* new_sentence[], int max_size)
{
char *delim = "-";
int numberOfWord = 0;
new_sentence[numberOfWord++]= strtok(s, delim);
while(((numberOfWord < max_size) && (new_sentence[numberOfWord] = strtok(NULL, delim)) != NULL)) {
++numberOfWord;
}
return numberOfWord;
}

代码在main中声明解析后的字符串数组,并将其作为参数(用单词填充(传递给parse。这避免了返回在parse中创建的本地数组(该数组在parse终止后不再存在(所导致的未定义行为。

n_sentence现在是一个合适的字符串数组——代码只指定它最多可以存储多少个字符串。但是单个字符串的长度可以是任何值。parse返回从解析中检索到的字符串数——这是一种方便的方法,可以更容易地使用该数组,正如您在打印部分看到的那样。

最后,parse本身被重新排列了——我使用了我以前解析行的方法,而不是strcpy方法。我建议您使用一本书/文档详细研究此代码。此外,永远不要忽略编译器警告,最好将其设置为尽可能高的级别。

编辑:根据@JonathanLefflerparse的建议,现在检查输入字符串数组的最大允许大小,并停止解析——如果达到该大小,则添加字符串。通过这种方式,代码可以避免潜在的写入超出数组边界。在这种情况下,最大大小为1000个单词。我对parse进行了单独的论证,而不是使用宏MAX_WORDS使其作为一个函数更加自治。while()由于短路而正常工作。

parse()函数是字符串分割函数的经典情况。如果在堆上分配结果,则可以处理任意数量的结果。我个人不会在这里使用strtok:它增加了一点不需要的复杂性,它修改了输入,而且它不是可重入的(你不能在多个线程中使用它,请查看strtok_r(。

char **split(const char *s, char delim, size_t *count)
{
*count = 0;
const char *p = s;
char **result = NULL;
for (; *p != ''; ++p) {
if (*p != delim)
continue;
char **new_result = realloc(result, (*count + 1) * sizeof(char *));
if (new_result == NULL)
goto error;
result = new_result;
result[*count] = calloc(p - s + 1, sizeof(char));
if (result[*count] == NULL)
goto error;
strncpy(result[*count], s, p - s);
++*count;
s = p + 1;
}
char **new_result = realloc(result, (*count + 1) * sizeof(char *));
if (new_result == NULL)
goto error;
result = new_result;
result[*count] = calloc(p - s + 1, sizeof(char));
if (result[*count] == NULL)
goto error;
strncpy(result[*count], s, p - s);
++*count;
return result;
error:
for (size_t i = 0; i < *count; ++i)
free(result[i]);
free(result);
*count = 0;
return NULL;
}

以下是拆分功能的测试驱动程序:

int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i) {
size_t count = 0;
char **result = split(argv[i], '-', &count);
printf("'%s'n", argv[i]);
for (size_t i = 0; i < count; ++i)
printf("t'%s'n", result[i]);
for (size_t i = 0; i < count; ++i)
free(result[i]);
free(result);
}
return EXIT_SUCCESS;
}

一些测试涵盖了一些边缘情况:

$ ./split -string-one string-two- string--three string-four
'-string-one'
''
'string'
'one'
'string-two-'
'string'
'two'
''
'string--three'
'string'
''
'three'
'string-four'
'string'
'four'

如果这是一项家庭作业,我强烈建议研究代码并尝试从头开始重新创建它。

最新更新