zoukankan      html  css  js  c++  java
  • C语言学习趣事_经典面试题系列_2

          最近老感觉自己的身体一天不如一天,老是丢三落四的, 哎,岁月啊..................

          在此给还在被中国教育的童鞋们一个建议.............在学校的时候还是小玩玩游戏,小谈谈一些海阔天空的事,当你工作后,你会发现你

    不但没有时间这个本钱了, 同时连身体这个本钱也没有了..........

           上次说了一些有意思的面试题, 今天我们结着看看一些关于指针和sizeof的面试题:

    下面是我看到的一些面试题

    5、简述
            char * const p;
            char const *p;
            const  char *p;
       之间的区别。

        首先讨论:
                   char  * const p;   这里可以知道const修饰是指针变量p; 因此指针p的指向不能改变,这样的变量
              定义必须首先初始化,否则将不能编译通过。但是p指向的变量的存储内容可以改变。
                   Exp:
                          char chTest1;
                          char chTest2;
                          char  * const p=&chTest1;
                          // p=&chTest2;   这个地方是错误的,不能这样赋值
                          *p=‘c’;
                          chTest1=‘b’;
        接下来讨论:
                   char const *p;     这里可以知道const修饰的是*p; 因此可以知道不能通过*p指向来改变变量的值; 但是
        指针p的指向可以改变,而且可以通过原变量进行改变值。
                  Exp:
                         char chTest1;
                         char chTest2;
                         char const *p=&chTest1;
                         p=&chTest2;
                         chTest=‘a’;
                 这里可以知道: 1)p的指向可以改变
                               2)不能通过*p= 某个值进行赋值
                               3)指针指向的变量的值自己可以改变。
       
        最后讨论:
                 const char  *p=&chTest1;  这里可以知道const修饰的是*p; 因此这个与char const *p;具有相同的效果。
               Exp:      
                   char chTest1;
                   char chTest2;
                   const char  *p=&chTest1;
                   p=&chTest2;
                   chTest1='a';
                   // *p='a';  这个地方错误, 不能这样修改值。

       总结:
              修饰符仅对其修饰的对象起作用,对别的变量不起作用。

    6、以下代码中的两个sizeof用法有问题吗?
                   void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
               {   
                    for( size_t i=0; i <sizeof(str)/sizeof(str[0]); ++i )      
                       if( 'a' <=str[i] && str[i] <='z' )           
                                 str[i] -= ('a'-'A' );
                 }
                char str[] = "aBcDe";
                cout < < "str字符长度为: " < < sizeof(str)/sizeof(str[0]) < < endl;
                UpperCase( str );
                cout < < str < < endl;
       Exp:
          这个问题的考察点是sizeof的用法。那么我们应该如何看待这个问题呢?
        1、这里首先我们需要知道的是sizeof 是个运算符, 它具有运算的优先级别, 那么sizeof运算的优先级在什么地方呢?
           可以查看运算符优先级的定义: sizeof 的优先级和 *p(P为指针)、&p(变量,取地址)的优先级一样, 排在优先级的第二位。
        2、其次要明白sizeof关键字的作用
              sizeof 关键字返回的是操作数在内存中占用的字节数。
           这里要看sizeof操作符的操作对象:
           1) 类型关键字
               sizeof(int):  这个取决系统的定义, 当在32位机器上时; sizeof int == 4
                                而在16位机器上时, sizeof int == 2
           2) 变量
               int iTest;
               sizeof iTest;  这样返回的是这种变量类型在内存中所占用的空间。
               即:
                    sizeof iTest == sizeof int;
           3) 字符串字面值
               sizeof "abcd";
               那么返回的是:字符串在内存空进中占用的字节数。 这里我们知道"abcd"在内存中占用的是5个字节,那么很显然有
               sizeof "abcd"==5;
           4) 数组
             这里有点难度
             char chTest[5];
             sizeof(chTest)==5; //这里可以知道chTest数组有5个元素,并且每个元素占用一个字节,因此sizeof(chTest)==5;

             那么如果我们这样定义呢?
             int iTest[5];
             sizeof(iTest)= ?  // 答案是10 , 因为有5个元素,每个元素占两个字节,所以占用10个字节的空间。
         
             二维数组呢?
             char chTest[10][20];
             sizeof(chTest)= ?  //200
             既然sizeof(chTest)==200; 那么sizeof(chTest[10])= ?  答案是 20 .
           
             又如:
             int iTest[10][20];
             sizeof(iTest)= ?  // 400
             同样 sizeof(iTest[10])= ?  答案是 20

            通过这里我们得出结论:
            对于sizeof操作数组的时候要分两种情况:
            a、 一维数组
               sizeof(数组名) 返回的是 数组元素个数 * 每个元素占用的字节数
               sizeof(数组名[n]) 返回的是: 数组类型定义的单个变量所占用的字节数
              即:
                  int iTest[4];
              则
                  sizeof(iTest)=8;
                  sizeof[iTest[1]]=2;  //这里假设 sizeof[int]=2
                
           b、 多维数组
               sizeof(数组名)     返回的是:一维的长度*二维的长度*....* 每个元素占用的字节数
               sizeof(数组名[n])  返回的是:其后面各位长度的乘积* 每个元素占用的字节数,
                                   这样必须保证sizeof的操作数没有取到最后一维。
               即: int iTest[2][3][4];
                    sizeof(iTest[2][3])= 4*sizeof[int]=8;  //这里假设用的是16位系统
           c) 多维数组
              sizeof(数组变量定义式);
              即:
              int iTest[2][3][4][5];
              sizeof(iTest[2][3][4][5])= ? 
              这里返回的是 数组的维数 就是 4 。
           
           5、传递的是指针的时候
              如果操作的是指针那么情形又如何呢?
              这里也分两种情形:
              1)当操作数是指针本身的时候
              Exp:
                 int *iTest;
              那么
                 sizeof(iTest) = ? //这里有一个规则,当sizeof操作变量的时候,返回的是变量本身的存储长度, 因此
                                      //如果在16位的系统中, 这里返回2; 而在32位系统中返回的是4;
                         
              2)当操作数有* 取值间接运算符号时
              Exp:
                 int *iTest;
              那么
                 sizeof(*iTest) = ? // 这里返回的是 2, 其实返回的是sizeof(int)的长度; 即返回的是其指向的
                                      //变量类型的 所占用的空间
             可以用:
                 float *fTest;
                sizeof(*fTest)= ?  // 这里返回的值是 4
                sizeof(fTest)= ?     //  取决于系统  16位的系统返回 2, 32位系统返回 4, 64位系统返回8 即地址总线的宽度。

           现在回到我们的问题:
            void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
               {   
                    for( size_t i=0; i <sizeof(str)/sizeof(str[0]); ++i )      
                       if( 'a' <=str[i] && str[i] <='z' )           
                                 str[i] -= ('a'-'A' );
                 }
                char str[] = "aBcDe";
                cout < < "str字符长度为: " < < sizeof(str)/sizeof(str[0]) < < endl;
                UpperCase( str );
                cout < < str < < endl;  
          1、首先确定sizeof的语法问题:
                for( size_t i=0; i <sizeof(str)/sizeof(str[0]); ++i )    //语法没有问题        
               
                sizeof(str)/sizeof(str[0])    //语法也没有问题
          2、接着确定逻辑有没有问题
                我们先看: sizeof(str[0])分析可知str[0]是个char的变量 , 因此占用一个字节;
                再看:
                     sizeof(str); 这里str是一维数组同时是数组名, 因此返回的是数组的长度,
                貌似可以实现. 但是我们忽略了一个问题:
                数组当做实参传递的时候,最后一个 ‘\0’是不会传递的。
           3、 既然不能传递那么我们运行的时候是否可以得到正确结果呢

                答案是肯定的。


               这个可以在VC6.0中用下列代码测试:
             Exp:
    /*
     * test the sizeof key word
     *
     */

    #include <stdio.h>
    #include <conio.h>

     void UpperCase( char str[] ) 
    {   int i;
        printf("%d,%d",sizeof(str),sizeof(str[0]));
        for(i=0; i< sizeof(str)/sizeof(str[0]) ;++i )
            if( 'a' <=str[i] && str[i] <='z' )
                   str[i] -= ('a'-'A' );
    }
    int main(int argc,char *argv[])
    {
        char  chTest[]="abcd";
        printf("%d\n",sizeof(chTest));
        UpperCase(chTest);

        puts(chTest); // 因为我们知道chTest[4]='\0'. 所以虽然没有传递,但是还是可以实现转换的功能
        getch();
    }

       通过这个例子可以看出来, 有些时候确实不是我们想的那样,

  • 相关阅读:
    SpringMVC:拦截器拦截时机和原理
    SpringBoot:MessageConverter自动配置原理
    SpringMVC:返回值处理器原理和MessageConverter原理
    SpringMVC:自定义Converter
    XML-RPC协议学习
    ContentControl 与 ViewModel (一)
    C# 获取相对路径(绝对路径转相对路径)
    WPF 最简单的TextBox水印
    WPF/Silverlight开发的15个最佳实践(转发)
    WPF 打印崩溃问题( 异常:Illegal characters in path/路径中有非法字符)
  • 原文地址:https://www.cnblogs.com/volcanol/p/2087728.html
Copyright © 2011-2022 走看看