在 C++03 中,如何在没有重复代码的情况下在堆栈上创建非常量 C 字符串数组?

How to create an array of non-const C strings on the stack without repetitive code in C++03?

我正在为一个模块编写单元测试,该模块采用 C++03 中的可变 C 字符串数组 getopt。函数参数是 char*const[]。我想在函数内部的堆栈上创建参数。我目前的解决方案是:

char args_stor[][1024] = {
    "parser",
    "-o",
    "SomeValue"
};
char* args[] = {
    args_stor[0],
    args_stor[1],
    args_stor[2]
};

如何避免重复的部分,如果可能的话,将其转化为一条语句?

函数声明为:

int getopt(int argc, char* const argv[], const char *optstring);

因此用例是:

getopt(3, args, ":o:");

这个怎么样?

// Example program
#include <iostream>
#include <string>

int main()
{
    char *what[] = {"asd", "asd", "asd"};
}

我会做类似的事情(我添加了一个 parse 函数来验证功能):

#include <stdio.h>

int parse(int argc, char* argv[], const char *optstring)
{
    printf("optstring = %s\n", optstring);
    printf("argv's:\n");
    for (int i = 0; i < argc; ++i)
        printf("\t%s\n", argv[i]);
    return 0;
}

int main(void)
{
    char args_arr[][1024] = {
            "Hello",
            "how",
            "are",
            "you?"
        };
    char *args[sizeof args_arr / sizeof *args_arr];
    for (size_t i = 0; i < sizeof args / sizeof *args; ++i)
        args[i] = args_arr[i];

    parse(sizeof args / sizeof *args, args, ":o:");
    return 0;
}

如果你想添加一些东西,你只需要将它添加到args_arr声明中。 args数组会相应改变

我认为你做不到。 getopt 需要 char * const[]。您可以做的唯一改进是为每个参数使用单独的 char[] 声明而不是二维数组。这样你只分配需要的 space:

char opt1[] = "parser";
char opt2[] = "-o";
char *args[] = { opt1, opt2 };

从问题的评论来看,将 char 数组分配在堆栈上并不重要,重要的是它被正确且自动清理 使用后,这样我们就可以像这样调用函数:

void f(char *const *args);

int main()
{
    const char *args[] = {
        "parser",
        "-o",
        "SomeValue"
    };
    f(transform(args)->p);
}

要实现transform(),我们可以return一个std::auto_ptr到合适的结构:

#include <cstring>
#include <memory>

template<std::size_t N>
struct arg_list
{
    char *s;        // string storage
    char *p[N+1];   // pointers into s

    arg_list(const char *const *args)
        : s(new char[total_len(args)]), p()
    {
        char *dest = s;
        for (std::size_t i = 0;  i < N;  ++i) {
            std::strcpy(p[i] = dest, args[i]);
            dest += std::strlen(args[i]) + 1;
        }
        p[N] = 0;
    }

    ~arg_list() { delete[] s; }

    static std::size_t total_len(const char *const *args) {
        std::size_t length = 0;
        for (std::size_t i = 0;  i < N;  ++i)
            length += std::strlen(args[i]) + 1;
        return length;
    }
};

template<std::size_t N>
std::auto_ptr< arg_list<N> > transform(const char *const (&args)[N])
{
    return std::auto_ptr< arg_list<N> >(new arg_list<N>(args));
}

arg_list对象将在main()中调用f()后销毁。我们可以使用这个例子 f():

来测试它
#include <iostream>
void f(char *const *args)
{
    while (*args)
        std::cout << *args++ << std::endl;
}

没有内存泄漏,也没有对无效内存进行访问:

valgrind --leak-check=full ./44908185 
==23361== Memcheck, a memory error detector
==23361== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23361== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23361== Command: ./44908185
==23361==  
parser
-o
SomeValue
==23361== 
==23361== HEAP SUMMARY:
==23361==     in use at exit: 0 bytes in 0 blocks
==23361==   total heap usage: 3 allocs, 3 frees, 72,764 bytes allocated

对于较新的 C++ 标准,有更简单的版本,但这似乎是 C++03 中最简单的版本。