除非事先打印,否则字符数组不会用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;
}
您需要为要从函数返回的对象分配内存。这会将对象放在堆栈的堆(永久内存)上(由