最近在写编译器,有这样一段代码
1 typedef struct{ 2 int symbolnum; 3 char *name; //id36 4 int i; //int37 5 float f; //float38 6 char *s; //string39 7 }To; 8 typedef To* Token;
1 Token ReadToken() //从fp文件中读取一行形如(36,sum)的行,返回值被压栈 2 { 3 char strLine[1024]; 4 char n1[10]; 5 char n2[20]; 6 int i=0,j=0; 7 int t1; 8 Token rt = (Token)malloc(sizeof(To)); 9 if(feof(fp)||(NULL == fgets(strLine,1024,fp))) 10 { 11 rt->symbolnum = 0; 12 return rt; 13 } 14 15 for(i=1;;i++) 16 { 17 if(strLine[i] == ‘,‘) 18 { 19 n1[i-1] = ‘\0‘; 20 t1 = atoi(n1); 21 break; 22 } 23 n1[i-1] = strLine[i]; 24 } 25 rt->symbolnum = yytranslate[t1]; 26 i++; 27 28 while(strLine[i] != ‘)‘) 29 { 30 n2[j] = strLine[i]; 31 j++; 32 i++; 33 } 34 n2[j] = ‘\0‘; 35 36 switch(t1) 37 { 38 case 36: //id 39 { 40 rt->name = n2; //我一定是脑子烧糊涂了才会这样写 41 break; 42 } 43 case 37: //int 44 { 45 rt->i = atoi(n2); 46 break; 47 } 48 case 38: //float 49 { 50 rt->f = atof(n2); 51 break; 52 } 53 case 39: //string 54 { 55 rt->s = n2; ///(ㄒoㄒ)/~~ 56 break; 57 } 58 } 59 return rt; 60 }
这段代码错在什么地方呢?
结构体To中的name和s的类型都是char*,即指针型的字符串。在函数ReadToken()中
40 rt->name = n2;
直接将n2字符数组的地址赋值给name,n2是个局部变量,在函数退出后就会被销毁,n2地址中的值也没了,但是rt返回给主函数被压栈,rt->name还是这个地址,这个地址现在存啥呢?不一定。将来存啥呢?不一定。
“
在c语言中,一种典型的错误就是将一个指向局部变量的指针作为函数的返回值。由于该数组是局部变量,因此在函数返回时其数组空间已经作废了,即指针应用一块无意义的地址空间,所以不会有返回值。
如果得到正常的值,只能是幸运的:退出函数的时候,系统只是修改了栈顶的指针,并没有清内存; 所以,是有可能正常访问到局部变量的内存的。
但因为栈是系统自动管理的,所以该内存可能会被分配给其他函数,这样,该内存的内容就会被覆盖;不再是原来的值了。
”
下一次执行ReadToken()又会为n2申请空间,这个和上一次被销毁的地址应该是一样的,所以这次执行ReadToken()时,一旦对n2的值改变,栈中原来那个token的name值也会被改变。
时间: 2024-10-13 06:20:58