从函数C返回填充的字符串数组

时间:2012-03-19 05:16:55

标签: c arrays pointers c-strings

这是第一次发帖,所以我为任何困惑道歉:

我正在写一个这样的函数:

int myFunc(char* inputStr, int *argCTemp, char** argVTemp[]);

我的函数的目的是获取输入字符串的副本(基本上是任何用户输入),然后使用strtok将其转换为标记并通过数组指针填充数组(argV )。当myFunc完成时,希望我有inputStr字符串中的参数count和字符串数组。

以下是我如何称呼它的示例:

int main(int argc, char** argv[])
{
    int argCTemp = -1;
    char** argVTemp; 

    // 1 Do Stuff
    // 2 Get input string from user 
    // 3 then call myfunc like this:

    myFunc(inputStr, &argCTemp, &argVTemp);

    // 4: I get garbage whenever I try to use "argVTemp[i]" 
}

我的问题:我应该如何以安全和一致的方式做到最好。专业人士如何做到这一点?


  1. 我不使用malloc因为:

    • 我不知道参数的数量或每个输入的长度(动态分配空间)。我想这就是我使用指针的原因
    • 因为我在main函数中声明它,我认为argCTempargVTemp使用的指针/内存很好/保留在范围内,即使它们在堆栈中也是如此。
  2. 我知道当myFunc退出时它会使它创建的任何堆栈引用无效,所以这就是我从调用函数发送指针的原因。我应该使用指针和malloc等等或什么?

  3. 最后一件事:在myfunc退出之前,我会查看argCTempargVTemp的值,并且它们包含有效内容。我正在设置argCtempargVtemp,如下所示:

    (*argCTemp) = argCount;
    (*argVTemp)[0] = "foo";
    
  4. 并且在函数退出之前似乎工作得很好。由于我在内存中的其他位置设置指针,我很困惑为什么引用失败。我在设置指针时尝试使用malloc INSIDE myFunc,当myFunc结束并且被调用函数读取时它仍然变为垃圾。

    如果其中任何一个令人困惑,我很抱歉,并提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

由于“不知道我的输入的参数数量或每个参数的长度”,您也可以使用malloc。当你的缓冲区满员时,你应该realloc你的缓冲区。 更好的方法:您不需要存储整个输入。一条线,一个标记或一个块更好。只需设置一个静态数组来存储它们。如果你的输入超过100 mb,也许散列更好。

对不起我的英语很差。

答案 1 :(得分:0)

一般来说,由于您不知道结果中将包含多少令牌,因此您需要使用malloc()realloc()和/或某些等效项动态分配数组。或者,您可以让调用者在数组中传递数组的大小,如果数组不够大,则返回错误指示(对于动态分配不合适的嵌入式系统上的简单命令解析器,我这样做。)

这是一个以小增量分配返回数组的示例:

static
char** myFunc_realloc( char** arr, size_t* elements)
{
    enum {
        allocation_chunk = 16
    };

    *elements += allocation_chunk;
    char** tmp = (char**) realloc( arr, (*elements) * sizeof(char*));

    if (!tmp) {
        abort();  // or whatever error handling
    }

    return tmp;
}

void myFunc_free( char** argv)
{
    free(argv);
}

int myFunc(char* inputStr, int *argCTemp, char** argVTemp[])
{
    size_t argv_elements = 0;
    size_t argv_used = 0;
    char** argv_arr = NULL;


    char* token = strtok( inputStr, " ");

    while (token) {
        if ((argv_used+1) >= argv_elements) {
            // we need to realloc - the +1 is because we want an extra 
            //  element for the NULL sentinel
            argv_arr = myFunc_realloc( argv_arr, &argv_elements);
        }

        argv_arr[argv_used] = token;
        ++argv_used;

        token = strtok( NULL, " ");
    }

    if ((argv_used+1) >= argv_elements) {
        argv_arr = myFunc_realloc( argv_arr, &argv_elements);
    }
    argv_arr[argv_used] = NULL;

    *argCTemp = argv_used;
    *argVTemp = argv_arr;

    return argv_used;
}

一些注意事项:

  • 如果分配失败,程序将终止。您可能需要不同的错误处理。
  • 传入的输入字符串'已损坏'。这可能不适合您的函数(通常,我更喜欢这样的函数不会破坏输入数据)。
  • 函数的用户应该调用myFunc_free()来释放返回的数组。目前这是free()的简单包装器,但是这使您可以灵活地执行更复杂的操作(例如为令牌分配内存,这样您就不必销毁输入字符串)。