除非事先打印,否则字符数组不会用C打印

除非事先打印,否则字符数组不会用C打印,c,C,这很奇怪-下面是我创建标记器对象的代码和主要方法: 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

这很奇怪-下面是我创建标记器对象的代码和主要方法:

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;
}
struct-TokenizerT\u{
char*sep;
char*toks;
};
TokenizerT*TKCreate(字符*分隔符,字符*ts){
如果(ts==NULL){
返回NULL;
}
int lin=(int)strlen(分隔符);
查尔[林];
yr[0]=*分离器;
int lim=1;
int h=1;

对于(h=1;h,这里有许多问题:

  • inu
    是一个局部变量。您返回它的地址。当您试图在
    main
    中读取该地址时,您正在访问一个不再在范围内的变量。这是未定义的行为
  • inu
    sep
    字段被赋值为
    yr
    。现在,
    yr
    是一个局部变量,一个字符数组,衰减为指针。同样,函数返回后访问该字段意味着访问一个范围已结束的变量。同样,未定义的行为
  • 您使用的是可变长度数组,VLA。我怀疑这不是故意的。一般来说,VLA是高级功能,只有在您清楚其含义时才应该使用
  • 我建议作出以下修改:

    • 使用
      malloc
      动态分配字符数组
    • 按值返回结构
    除此之外,我怀疑您还有其他问题。在我看来,
    yr
    不是以null结尾的,有些元素可能根本没有初始化。这是故意的吗?也许您在编写
    yr[0]时实际上是想将
    yr
    初始化为等于
    分隔符=*分隔符
    。请注意,您的代码只分配一个字符。要动态分配
    yr
    ,并将其初始化为等于
    分隔符
    ,您可以编写:

    yr := malloc(strlen(separators)+1);
    strcpy(yr, separators);
    

    为什么要多次调用
    strlen(分隔符)
    ?您似乎多次调用它
    1+strlen(分隔符)
    。您应该只调用一次。

    这里有许多问题:

  • inu
    是一个局部变量。您返回它的地址。当您试图在
    main
    中读取该地址时,您正在访问一个不再在范围内的变量。这是未定义的行为
  • inu
    sep
    字段被赋值为
    yr
    。现在,
    yr
    是一个局部变量,一个字符数组,衰减为指针。同样,函数返回后访问该字段意味着访问一个范围已结束的变量。同样,未定义的行为
  • 您使用的是可变长度数组,VLA。我怀疑这不是故意的。一般来说,VLA是高级功能,只有在您清楚其含义时才应该使用
  • 我建议作出以下修改:

    • 使用
      malloc
      动态分配字符数组
    • 按值返回结构
    除此之外,我怀疑您还有其他问题。在我看来,
    yr
    不是以null结尾的,有些元素可能根本没有初始化。这是故意的吗?也许您在编写
    yr[0]时实际上是想将
    yr
    初始化为等于
    分隔符=*分隔符
    。请注意,您的代码只分配一个字符。要动态分配
    yr
    ,并将其初始化为等于
    分隔符
    ,您可以编写:

    yr := malloc(strlen(separators)+1);
    strcpy(yr, separators);
    

    为什么多次调用
    strlen(分隔符)
    ?您似乎将其称为
    1+strlen(分隔符)
    次。您应该只调用一次。

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

    所以你绝对不能这样做:

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

    你需要做的是传递一个指向你想要构建的对象的指针,或者使用
    malloc
    分配一个新的指针。如果你使用
    malloc
    ,你以后需要记得
    free
    对象。由于Windows及其多个C运行时,在一个fu中
    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);
    }
    

    在C语言中,你永远不能返回一个指向局部函数变量的指针。当然,你可以,但它不会工作。即使它看起来有效,它也只是在等待一个不起作用的好机会

    所以你绝对不能这样做:

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

    你需要做的是传递一个指向你想要构建的对象的指针,或者使用
    malloc
    分配一个新的指针。如果你使用
    malloc
    ,你以后需要记得
    free
    对象。由于Windows及其多个C运行时,在一个fu中
    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);
    }
    
    您需要为要从函数返回的对象分配内存。这会将对象放在堆栈的堆(永久内存)上(当前函数结束后程序会立即回收的内存)

    您可以在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;
    }
    
    您需要为要从函数返回的对象分配内存。这会将对象放在堆栈的堆(永久内存)上(由