函数中的本地字符数组保留其先前调用的值

时间:2015-11-20 08:31:45

标签: c arrays pointers

printf函数中对number()的第一次调用会打印出来的字符串 token[]在最后一次通话结束时。任何人都可以解释这背后的原因吗?

我删除了大部分与字符串无关的函数命令。如果我需要提供更多代码,请告诉我。

PS:如果我用char *替换令牌数组并动态存储和释放地址我没有这样的问题

void number(FILE *fp, FILE *fo, char ch)
{
       char token[100],*tmp; //characters read are saved here
       State currentState = S0;
       State prevState;
       int i,counter = 0;

       printf("THE PREVIOUS TOKEN = %s\n\n",token);


       while(1)
       {


            switch (currentState)
            {
                    case S0 :
                    {
                            ...
                    }
                    case S1 :
                    {
                            ...
                    }
                    case S2 :
                    {     
                            ...
                    }
                    case S3 :
                    {
                            ...
                    }
                    case S4 :
                    {
                            ...
                    }
                    case S5 :
                    {
                           ...
                    }
                    case INTEGER :
                    {
                           ...
                    }
                    case FLOAT :
                    {
                            ...
                    }
                    case BAD :
                    {
                            dbg("  BAD\n");
                            prevState=BAD;
                            fprintf(fo,"+Error! Invalid syntax for an integer or float\n");
                            tmp=avoidchars(fp,ch);
                            if(tmp)
                            {
                                printf("Unknown token : %s\n\n",strcat(token,tmp));
                                free(tmp);
                            }
                            break;
                    }

               }



                if ( ( currentState==GOOD ) || ( currentState==BAD ) && ( prevState == BAD ) )
                      break;

                if( currentState != INTEGER  &&  currentState != FLOAT && currentState != BAD)
                {
                        token[counter] = ch;
                        ch=fgetc(fp);
                }     

                counter++;
    }
}

2 个答案:

答案 0 :(得分:2)

未初始化的非静态局部变量具有 indeterminate 值,使用这样的变量做任何事情,除了初始化它,导致未定义的行为。你根本就不应该这样做。

但是为了解释这里的行为,想想编译器没有为你初始化这些变量,它们毕竟是未初始化的。但是,如果您之后多次调用函数,则此非初始化策略仅表示内存在调用之间保持不变。如果调用具有自己的局部变量的函数,它们在函数调用之间修改,那么对函数的第二次调用将使局部变量包含上一次调用另一函数的值。

试试例子

ContentObserver   observer = new MyObserver(Android.Net.Uri.Parse("content://com.Test/databases/Data.db"));
        // TODO Auto-generated method stub
        var a = Android.Net.Uri.Parse  ("content://com.Test/databases/Data.db");
        ContentResolver.RegisterContentObserver(a, false, observer);

现在,如果您在第二次调用中打印出number(...); printf("%s %s %s %s %s\n", "foo", "bar", "flux", "blam", "foblax"); number(...) 数组(技术上未定义的行为),则内容将与上一次token调用留下的内容完全不同。

答案 1 :(得分:2)

打印未初始化的变量是未定义的行为,因此您基本上要求"未定义的未定义行为"。

无法保证在打印未初始化数据时会发生什么:您可能会遇到垃圾,您可能会得到一些看似合理的内容,您可能会遇到程序崩溃。你可能会得到一些今天有意义的东西,明天会让程序崩溃。该程序可能在您的计算机上正常工作,但在客户的计算机上崩溃。 没有保证也没有可预测的行为。

在特定系统的幕后,阵列很可能存储在堆栈中。如果你是 lucky ,那么在函数调用之间不会修改堆栈的那个区域,为什么它可能会像保留内存一样。设计一个依赖运气的程序是一个坏主意。如果您确实需要保留数组,则需要将其声明为static,这也会强制初始化为可预测的值。