【问题标题】:Return an array of strings from a function从函数返回一个字符串数组
【发布时间】:2011-09-04 13:41:24
【问题描述】:

我需要返回一个char**,但是当我尝试这样做时,编译器告诉我我想返回一个局部变量的地址。我怎样才能做到这一点?我知道我应该为这个变量分配空间但是如何?这是我的代码,但第二个 printf 没有出现,函数什么也不返回:

char** parse_cmd(const char* cmdline) {
char** arguments = (char**)malloc(100);
int i;
int j=0, k=0;
printf("%s\n", cmdline);

for(i=0; i<100; i++) {
    arguments[i] = malloc(100);
}

for(i = 0; i < strlen(cmdline); i ++) {
    if(cmdline[i] != ' ') {
        arguments[j][k] = cmdline[i];
        k++;
    } else {
        arguments[j][k] = '\0';
        j++;
        k = 0;
    }
}

printf("%s\n", arguments[1]);

return arguments;
}

【问题讨论】:

  • 你在哪里调用函数?
  • 我在主类中调用函数
  • 在 C 中转换 malloc 的返回值被许多人(比如我)认为是不好的做法,原因有很多。
  • 不要每次循环调用strlen();它变得昂贵。然而,这不是这里的主要问题......
  • 如果连续获得 3 个空格会怎样?你如何标记返回的参数列表的结尾?我没有看到空指针,也没有计数。

标签: c string dynamic-allocation


【解决方案1】:

您需要进行多次分配。第一个用于char**,然后用于每个char*。例如。像

  char **args = (char**)malloc(100);
  int i;
  for (i=0; i<100; i++) 
    args[i] = malloc(100);

  // Rest of program

  return args;

【讨论】:

  • 现在可以了,但如果我的 cmdline/ test /' arguments[0]` 是 /*** * 是奇怪的符号。
  • @n_yanev - 这是因为您没有终止每个参数的字符串。在 else 子句中,您需要在迭代 j 之前在末尾添加一个 '\0'。像 arguments[j][k] = '\0'
  • 您可以在我的第一篇文章中看到我编辑的代码。但我有同样的错误。
【解决方案2】:

这是我组装和测试的代码。它为argv 参数列表和每个参数在组装时使用动态内存分配。函数release_cmd() 释放分配的空间。函数cleanup() 是内部函数,在失败时释放分配的空间,然后返回空双指针。这简化了错误处理。 prompt() 函数和 main() 中有一个最小的测试工具。我没有在valgrind 下运行过,但malloc() 的MacOS X 实现经常会发现问题,所以我有信心没有严重的内存滥用——但可能存在一次次泄漏。我没有通过伪造分配失败来测试cleanup() 代码。

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

void release_cmd(char **argv)
{
    for (size_t i = 0; argv[i] != 0; i++)
        free(argv[i]);
    free(argv);
}

static char **cleanup(size_t argc, char **argv)
{
    argv[argc] = 0;
    release_cmd(argv);
    return 0;
}

char **parse_cmd(const char* cmdline)
{
    size_t argc = 2;
    char **argv = malloc(argc * sizeof(char *));

    if (argv == 0)
        return 0;

    size_t j = 0;  // Index into argv
    size_t len = strlen(cmdline);

    for (size_t i = 0; i < len; i++)
    {
        while (isspace(cmdline[i]))
            i++;
        if (cmdline[i] == '\0')
            break;
        if (j > argc - 2)
        {
            size_t newc = (argc * 2);
            char **newv = realloc(argv, newc * sizeof(char *));
            if (newv == 0)
                return cleanup(argc, argv);
            argv = newv;
            argc = newc;
        }
        size_t argl = 2;    // Length of argument string
        argv[j] = malloc(argl);
        size_t k = 0;       // Index into argv[j]
        while (cmdline[i] != '\0' && !isspace(cmdline[i]))
        {
            if (k > argl - 2)
            {
                size_t newl = argl * 2;
                char  *news = realloc(argv[j], newl);
                if (news == 0)
                    return cleanup(argc, argv);
                argv[j] = news;
                argl    = newl;
            }
            argv[j][k++] = cmdline[i++];
        }
        argv[j][k] = '\0';
        argv[j] = realloc(argv[j], k+1);    // Shrink to fit!
        j++;
    }
    argv[j] = 0;
    argv = realloc(argv, (j+1)*sizeof(*argv));  // Shrink to fit!

    return argv;
}

static int prompt(const char *prompt, char *buffer, size_t bufsiz)
{
    printf("%s", prompt);
    return (fgets(buffer, bufsiz, stdin) != 0);
}

int main(void)
{
    char line[1024];

    while (prompt("cmd? ", line, sizeof(line)) != 0)
    {
        char **argv = parse_cmd(line);
        char **args = argv;
        while (*args)
            puts(*args++);
        release_cmd(argv);
    }
    putchar('\n');
    return 0;
}

【讨论】:

  • 我不太满意的是外部for 循环,因为内部代码会篡改外部循环索引i,将这两个@ 打包可能会更干净987654332@ 分块成单独的函数。循环可以只替换为while (1)(您必须声明i,并且不再需要len)。我现在检查了valgrind 并修复了代码中的argv = realloc(argv, (j+1)*sizeof(*argv));
  • (仅作记录,错误代码是argv = realloc(argv, j+1);,是通过粗心类比类似realloc() 用于超长字符串而创建的。“缩小以适应”realloc() 操作可能如果加倍算法分配了 128 个字节,例如当字符串长于 64 个字节时,则可以节省空间。
猜你喜欢
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 2012-03-30
  • 2014-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多