从C函数中返回一个字符串指针数组

huangapple go评论105阅读模式
英文:

Returning a string pointer array from a function in C

问题

我正在尝试使用一个函数来将字符串分割成单独的单词。该函数创建了一个数组,我可以看到该数组在函数中正常工作。我的问题是,当我尝试将数组作为另一个char数组返回给main函数时出现问题。

以下是你的代码(已翻译为中文):

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>

char *commands(char *command) {
    char *commands[30];
    int i = 0;
    char *st = strtok(command, " ");
    while (st != NULL) {
        commands[i] = strsep(&st, " ");
        st = strtok(NULL, " ");
        i++;
    }
    for (int p = 0; p < i; p++) {
        printf("在函数内部: i-> %d, command: %s\n", p, commands

); } return *commands; } int main(int MainArgc, char *MainArgv[]) { size_t size = 10; char *user_input; char *user_commands; int flag = 0; user_input = (char *)malloc(size); while (flag != EOF) { printf("witsshell> "); flag = getline(&user_input, &size, stdin); user_commands = commands(user_input); puts(&user_commands[1]); } return (0); }

请注意,我只翻译了代码部分,不包括注释和输出语句。

英文:

I am trying to use a function to split a string in its separate words. The function creates an array, and I can see that the array is working in the function. My problem is when I try to return the array back to the main function as another char array.

Here is my code:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;string.h&gt;
#include &lt;assert.h&gt;
#include &lt;fcntl.h&gt;

char *commands(char *command) {
	char *commands[30];
	int i =0;
	char *st = strtok(command, &quot; &quot;);
	while (st != NULL) {
		commands[i] = strsep(&amp;st, &quot; &quot;);
		st = strtok(NULL, &quot; &quot;);
		i++;
	}
	for (int p = 0; p &lt; i; p++) {
		printf(&quot;inside the function still: i-&gt; %d, command: %s\n&quot;, p, commands

); } return *commands; } int main(int MainArgc, char *MainArgv[]) { size_t size = 10; char *user_input; char *user_commands; int flag = 0; user_input = (char *)malloc(size); while (flag != EOF) { printf(&quot;witsshell&gt; &quot;); flag = getline(&amp;user_input, &amp;size, stdin); user_commands = commands(user_input); puts(&amp;user_commands[1]); } return (0); }

答案1

得分: 2

你的代码存在多个问题:

  • 函数commands修改了它的参数字符串。这可能会导致问题,特别是不能使用字符串字面值调用此函数。
  • 你只在空格上分割字符串,应该考虑制表符和换行符作为单词分隔符。
  • 你将单词指针存储在一个本地数组中,没有检查溢出,如果参数字符串包含超过30个单词,就会发生溢出。
  • 你应该在数组末尾存储一个空指针,以便调用者可以检测到数组的结束。
  • 你返回的是*commands,也就是第一个单词,而不是字符串数组。
  • 你不能返回一个本地数组,因为一旦函数返回,它就会变为无效。

下面是使用标准字符串函数的替代方法,可以避免上述许多问题:

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

char **commands(const char *command) {
    char **array;
    int count, pos, len;
    for (pos = 0, count = 0;; count++) {
        // 跳过空白字符
        pos += strspn(command + pos, " \t\r\n");
        if (command[pos] == '\0')
            break;
        // 获取单词长度
        len = strcspn(command + pos, " \t\r\n");
        // 跳过单词
        pos += len;
    }
    // 为数组分配内存:
    array = malloc(sizeof(*array) * (count + 1));
    if (array == NULL)
        return NULL;
    for (pos = 0, i = 0;; i++) {
        // 跳过空白字符
        pos += strspn(command + pos, " \t\r\n");
        if (command[pos] == '\0')
            break;
        // 获取单词长度
        len = strcspn(command + pos, " \t\r\n");
        // 复制单词
        array[i] = strndup(command + pos, len);
        if (array[i] == NULL) {
            while (i-- > 0)
                free(array[i]);
            free(array);
            return NULL;
        }
        // 跳过单词
        pos += len;
    }
    array[i] = NULL;
    return array;
}

int main(int argc, char *argv[]) {
    size_t size = 0;
    char *user_input = NULL;
    char **user_commands;

    for (;;) {
        printf("witsshell> ");
        if (getline(&user_input, &size, stdin) < 0)
            break;
        char **user_commands = commands(user_input);
        if (user_commands) {
            for (int i = 0; user_commands[i]; i++) {
                printf("%d: %s\n", i, user_commands[i]);
                free(user_commands[i]);
            }
            free(user_commands);
        }
    }
    free(user_input);
    return 0;
}
英文:

There are multiple problems in your code:

  • the function commands modifies its argument string. This may pose problems, in particular, you cannot call this function with a string literal.
  • you split the string on spaces only, you should also consider TABs and newlines as word separators.
  • you store the word pointers into a local array without checking for overflow, which will occur if the argument string contains more than 30 words.
  • you should store a null pointer at the end of the array for the caller to detect the end of the array.
  • you return *commands, which is the first word, not the array of strings
  • you cannot return a local array at it becomes invalid as soon as the function returns.

Here is an alternative approach using standard string functions that avoid many of the above shortcomings:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
char **commands(const char *command) {
char **array;
int count, pos, len;
for (pos = 0, count = 0;; count++) {
// skip whitespace
pos += strspn(command + pos, &quot; \t\r\n&quot;);
if (command[pos] == &#39;\0&#39;)
break;
// get the word length
len = strcspn(command + pos, &quot; \t\r\n&quot;);
// skip the word
pos += len;
}
// allocate memory for the array:
array = malloc(sizeof(*array) * (count + 1));
if (array == NULL)
return NULL;
for (pos = 0, i = 0;; i++) {
// skip whitespace
pos += strspn(command + pos, &quot; \t\r\n&quot;);
if (command[pos] == &#39;\0&#39;)
break;
// get the word length
len = strcspn(command + pos, &quot; \t\r\n&quot;);
// make a copy of the word
array[i] = strndup(command + pos, len);
if (array[i] == NULL) {
while (i-- &gt; 0)
free(array[i]);
free(array);
return NULL;
}
// skip the word
pos += len;
}
array[i] = NULL;
return array;
}
int main(int argc, char *argv[]) {
size_t size = 0;
char *user_input = NULL;
char **user_commands;
for (;;) {
printf(&quot;witsshell&gt; &quot;);
if (getline(&amp;user_input, &amp;size, stdin) &lt; 0)
break;
char **user_commands = commands(user_input);
if (user_commands) {
for (int i = 0; user_commands[i]; i++) {
printf(&quot;%d: %s\n&quot;, i, user_commands[i]);
free(user_commands[i]);
}
free(user_commands);
}
}
free(user_input);
return 0;
}

答案2

得分: -3

在代码片段中,你正在使用一个名为commands的函数根据空格字符来分割一个字符串。然而,由于该函数的作用域有限,将数组返回给主函数会导致问题。因此,在处理commands函数中的单词时,你可能需要在主函数之外创建一个新的数组来克服这个限制。

char** commands(char *command, int *numCommands){
    char **commands = (char**)malloc(sizeof(char*) * 30);
    int i = 0;
    char *st = strtok(command, " ");
    while(st != NULL){
        commands[i] = strdup(st);
        st = strtok(NULL, " ");
        i++;
    }
    *numCommands = i;
    return commands;
}
英文:

In the code snippet, you are using a function named commands to split a string based on space characters. However, due to the limited scope of this function, returning the array to the main function is causing issues. Therefore, while processing separate words with the commands function, you might need to create a new array outside of the main function to overcome this limitation.

char** commands(char *command, int *numCommands){
char **commands = (char**)malloc(sizeof(char*) * 30);
int i = 0;
char *st = strtok(command, &quot; &quot;);
while(st != NULL){
commands[i] = strdup(st);
st = strtok(NULL, &quot; &quot;);
i++;
}
*numCommands = i;
return commands;}

huangapple
  • 本文由 发表于 2023年8月9日 00:20:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76861460.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定