除非先前打印过,否则char数组不会在C中打印

时间:2014-02-03 16:21:13

标签: c

所以这很奇怪 - 下面是我创建tokenizer对象的代码和主要方法:

struct TokenizerT_ {
    char * sep;
    char * toks;
};

TokenizerT *TKCreate(char *separators, char *ts) {

    if (ts==NULL) {
        return NULL;
    }

    int lin = (int) strlen(separators);
    char yr[lin];
    yr[0] = *separators;
    int lim = 1;
    int h = 1; 

    for(h=1; h<strlen(separators); h++){
        char tmp = *(separators+h);
        int z=0;

        for (z=0; z<lim; z++) {
            if (tmp==yr[z]) {
                z=-1;
                break;
            }
        }
        if(z>-1){
            yr[h] = tmp;
            lim++;
        }

    }
    TokenizerT inu = {yr, ts};
    printf("%s\n", inu.sep);
    return &inu;
}

int main(int argc, char **argv) {

    char * arr = argv[1];
    char * y = argv[2];
    TokenizerT jer = *TKCreate(arr, y);

    printf("%s\n", jer.sep);
    printf("%s\n", jer.toks);
    return 0;
}

如果我使用参数“tes”和“testing”运行程序,我会得到以下结果: TES TES 测试

但是,如果我用TKCreate中的printf语句运行程序注释掉,我得到:

测试。

printf(“%s \ n”,jer.sep)停止工作,除了在TKCreate中注释掉printf语句之外,我没有对代码做任何事情。为什么会这样?

3 个答案:

答案 0 :(得分:3)

这里有很多问题:

  1. inu是一个局部变量。你返回它的地址。当您尝试从main中的该地址读取时,您正在访问不再在范围内的变量。这是未定义的行为。
  2. sep的{​​{1}}字段已分配inu。现在,yr是一个局部变量,一个字符数组,它衰减到一个指针。同样,一旦函数返回就访问它意味着访问其范围已结束的变量。再次,未定义的行为。
  3. 您正在使用可变长度数组,即VLA。我怀疑这不是故意的。一般而言,VLA是高级功能,只有在您明确其含义时才能使用。
  4. 我建议进行以下更改:

    • 使用yr动态分配字符数组。
    • 按值返回结构。

    最重要的是,我怀疑你还有其他问题。在我看来,malloc不是以空值终止的,并且某些元素可能根本不会被初始化。这是故意的吗?也许你真的打算在写yr时初始化yr等于separators。请注意,您的代码只分配一个字符。要动态分配yr[0] = *separators,并将其初始化为等于yr,您可以写:

    separators

    为什么多次拨打yr := malloc(strlen(separators)+1); strcpy(yr, separators); ?您似乎将其称为strlen(separators)次。你应该只调用一次。

答案 1 :(得分:2)

在C中,您永远不能返回指向本地函数变量的指针。嗯,你可以,但它不会起作用。即使似乎工作,它只是在等待一个不工作的好机会。

所以你绝对不能这样做:

TokenizerT inu = {yr, ts};
return &inu;

您需要做的是传递指向要构建的对象的指针,或使用malloc分配新的对象。如果您使用malloc,则需要稍后记住free该对象。而且由于Windows及其多个C运行时,free函数内部的对象是一个非常好的主意。因为如果您要在库中使用代码,并在调试运行时使用malloc并在发布运行时使用free,那么就会发生错误。

因此对于malloc示例:

struct box* create_box(int x, int y) {
    struct box* b = malloc(sizeof(*b));
    if(!b) abort();
    b->x = x;
    b->y = y;
    return b;
}

void destroy_box(struct box* x) {
    free(x);
}

用于传递对象:

void init_box(struct box* b, int x, int y) {
    b->x = x;
    b->y = y;
}

void f() {
    struct box b;
    init_box(&b, 10, 20);
}

答案 2 :(得分:0)

您需要为要从函数返回的对象分配内存。这会将对象放在堆栈(永久内存)副本上堆栈(当前函数结束后由程序回收的内存)。

您可以通过在TKCreate函数中进行这些更改来实现此目的:

TokenizerT *TKCreate(char *separators, char *ts) {
    ...
    # change 'char yr[lin];' to:
    char* yr = (char*)malloc(lin * sizeof(char));

    ....
    TokenizerT* inu = (TokenizerT*)malloc(sizeof(TokenizerT));
    inu->sep = yr;
    int->yoks = ts;
    printf("%s\n", inu->sep);
    return inu;
}

您还可以通过仅共享对象的一个​​副本来清理main()函数。完成后,您可以在任何分配内存上调用free():

int main(int argc, char **argv) {
    char * arr = argv[1];
    char * y = argv[2];
    TokenizerT jer* = TKCreate(arr, y);

    printf("%s\n", jer->sep);
    printf("%s\n", jer->toks);
    free(jer);
    return 0;
}