(C编程)制作像argv一样的char **数组

时间:2015-07-02 21:51:58

标签: c arrays struct

在我写的程序中,我创建了一个Tokenize结构,上面写着:

TokenizerT *Tokenize(TokenizerT *str) {

    TokenizerT *tok;
    *tok->array = malloc(sizeof(TokenizerT));
    char * arr = malloc(sizeof(50));
    const char *s = str->input_strng;
    int i = 0;

    char *ds = malloc(strlen(s) + 1);
    strcpy(ds, s);

    *tok->array[i] = strtok(ds, " ");

    while(*tok->array[i]) {
        *tok->array[++i] = strtok(NULL, " ");
    }
    free(ds);
    return tok;
}

其中TokenizeT定义为:

struct TokenizerT_ {
    char * input_strng;
    int count;
    char **array[];
};

所以我要做的就是从我已创建的大型令牌中创建更小的令牌。我有问题返回一个数组,所以我做了TokenizerT结构的数组部分,所以我可以通过dok->数组访问它。我构建程序时没有错误,但是当我尝试打印令牌时,我遇到了问题。

TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);

TKCreate有效,因为我用它来打印argv但是当我尝试打印ab时它不起作用。我认为它就像argv一样工作。如果有人可以帮助我,我将非常感激。谢谢。

1 个答案:

答案 0 :(得分:3)

创建Tokenizer

我要走出困境,并猜测其意图:

TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));

是动态分配单个TokenizerT,其容量包含49个字符串和一个NULL结束标记。代码中的任何位置都不使用arrtok永远不会给出值;如果每个值都被移动一个语句并且更正了,那么似乎更有意义:

// Note: I use 'sizeof *tok' instead of naming the type because that's
//       my style; it allows me to easily change the type of the variable
//       being assigned to. I leave out the parentheses because
//       that makes sure that I don't provide a type.
//       Not everyone likes this convention, but it has worked pretty
//       well for me over the years. If you prefer, you could just as
//       well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);

tok->array不是一个好名字。我会使用tok->argv因为您显然正在尝试制作 arg ument v ector ,那是一个传统的名字。在这种情况下,tok->count可能是tok->argc,但我不知道你对该成员的意图是什么,因为你从来没有使用过它)。

填写参数向量

strtok将覆盖给定字符串中的(某些)字节,因此创建副本(此处为ds)完全正确,并且您执行此操作的代码是正确的。但请注意,strtok返回的所有指针都是指向副本中的字符的指针。因此,当您致电free(ds)时,您可以释放所有这些令牌所占用的存储空间,这意味着您即将返回到毫无戒心的来电者的新创建的TokenizerT已满晃来晃去的指针。所以永远不会这样做;你需要避免释放这些字符串,直到不再需要参数向量。

但这会导致另一个问题:如何释放字符串?您不能保存ds的值,strtok返回的第一个令牌可能不会在ds的开头处开始。 (如果字符串中的第一个字符是空格字符,则会发生这种情况。)如果您没有指向已分配存储的非常开始的指针,则无法释放存储空间。

TokenizerT结构

char是一个字符(通常是一个字节)。 char*是指向字符的指针,该字符通常(但不一定)是指向NUL终止字符串开头的指针。 char**是指向字符指针的指针,它通常(但不一定)是字符指针数组中的第一个字符指针。

那么char** array[]是什么? (注意尾随[])。 "显然",它是一个未指定长度char**的数组。因为未指定数组的长度,所以它是一个"不完整的类型"。现代C允许使用不完整的数组类型作为struct中的最后一个元素,但它需要您知道自己在做什么。如果您使用sizeof(TokenizerT),那么您最终会得到结构的大小,而不是不完整的类型;也就是说,好像数组的大小为0(虽然这在技术上是非法的)。

无论如何,那不是你想要的。你想要的是一个简单的char**,它是一个参数向量的类型。 (它的char*[]相同,但这两个指针都可以用整数i索引,以返回i th 向量中的字符串,所以它可能已经足够好了。)

这个代码不是所有,但它是修复它的良好开端。祝你好运。