• C语言学习趣事_经典面试题系列_3


             有日子没有学习C语言了, 前些天在看windows程序设计时, 按照win的体系结构,在VC 6里面找到

    下面一段代码,发现自己的C语言功底实在是差之又差。代码为我看到的C代码,至目前为止,还只能理解个大概;

    估计要慢慢体会了。

    View Code
    DECLARE_HANDLE(HDC);


    #define DECLARE_HANDLE(name)
    struct name##__
    {
    int unused;
    };
    typedef
    struct name##__ *name

          上面的代码等我理解后再和大家分享吧, 下面说说这一次的C语言面试题。

     8、找错题
     找出下面几个函数的错误:
    试题1:
      void test1()
           {
          char string[10];
          char* str1 = "0123456789";
          strcpy( string, str1 );
           }

    /*
       这个题目咋一看,没有任何错误, 给strcpy()函数传递的两个实参参数类型均能满足要求。
       但是细心一看我们会发现这个函数存在越界问题,"0123456789"这个字符串
       的长度为 strlen("0123456789") + 1 = 11 , 而很显然string[10],不可能存储这么大的空间
       通常在使用strcpy函数时一定要考虑源串、和目的串的大小问题。

    */
       函数改成下面的形式可能会健壮一些:
        int StrCpy(const char *source; char dest[])
         {
             if( NULL==source || NULL == dest || ( strlen(dest) < strlen(source) ) )
                  return 1;   // 返回值=1 表示复制失败
             else
                 strcpy(dest,source);           
             return 0;   //返回值=0 表示复制成功
         }
     

    试题2::
    void test2()
    {
       char string[10], str1[10];
       int i;
       for(i=0; i<10; i++)
         {
            str1 = 'a';
          }
     strcpy( string, str1 );
    }
    /*
    这个题目考查了两个问题: 
        1、 数组的首地址是常量,不可以作为左值, 即str1是一个常量,
            它代表整个数组的首地址。
        2、 第二数组的引用需要用下标,除了初始化时可以int iArray[10]={1,2}
            这样赋值外,在其他地方不可以批量给数组元素赋值。
        3、 同时strcpy复制函数是针对具有'\0'的字符类型变量,因此这个函数赋
            值同样存在赋值越界的情况。
    */
    改成下面的方式估计会健壮一些:
    void  test2( )
    {
       char string[10],
             str1[10] ;
       for(int i=0; i<10; i++)
          str1[i] = 'a';
           str[9]='\0';
       strcpy(string , str1);
    }

    试题3:
    void test3(char* str1)
      {
        char string[10];
        if( strlen( str1 ) <= 10 )
          {
            strcpy( string, str1 );
           }
       }
     //试题3同样存在越界的可能性。如果strlen(str1)=10, 则实际上str1占用的空间是11个。
     //strlen函数返回的长度没有计算末尾'\0'字符。 因此需要注意。
    改为下面的方式可能会更健壮:
    void  test3(char* str1)
      {
        char string[10];
        if( strlen( str1 ) < 10 && NULL != str1 )
            strcpy( string, str1 );
       }


    试题4:
     void GetMemory( char *p )
       {
         p = (char *) malloc( 100 );
       }

     void Test( void )
      {
       char *str = NULL;
       GetMemory( str );
       strcpy( str, "hello world" );
       printf( str );
      }
    /*
    首先这个题目存在内存泄露的问题和指针指向空地址问题
    说说这个题目的存在的几个问题:
     1、 在GetMemory函数里面, 没有对malloc函数返回值进行测试
         if(NULL==p)
     2、 在函数里面没有对指针p进行释放
         free(p);
     3、这里会有一个问题,在C语言中默认时按值传递的, 不是按照地址传递的。
        在程序里面不能改变str的指向。
          GetMemory(str);不能改变str的指向。 
        函数原型为:
           void GetMemory(char *p); 定义的就是一个指针类型的参数。
      4、在函数内部不能改变传值参数的值
    */

    /*****************
    malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,
    它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求
    的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果
    有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多
    的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,
    malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大
    的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内存块时,一定要
    进行返回值的判断。
    **************/

    改成下面形式可能更健壮一些:
      Void GetMemory(char **p)
       {     
             char *temp;
             if(NULL != (temp=(char *)malloc(1000)))
                   *p=temp;
             free(temp);
       }
                            

    试题5:
    char *GetMemory( void )
    {
     char p[] = "hello world";
     return p;
    }

    void Test( void )
    {
     char *str = NULL;
     str = GetMemory();
     printf( str );
    }

    /* 其实怎么说呢这个题目的理解比上面一个题目来对简单, 但是通过这个题目和上面
    的题目需要知道一个事实:
        那就是函数内部声明的局部变量(static类型的除外,当然还有register的除外),这里指的
        是auto类型的变量, 其内存空间是在系统为应用程序开辟的栈里面申请。
        而malloc函数申请的空间则是从系统为应用程序开辟的堆里面申请。堆里面申请的不会自动释放,
        而栈里面申请的会随着函数声明周期的结束而自动释放。 
    这个题目的错误之处在于没有理解局部变量的生命周期。
    */
    改成下面的形式可能会更健壮:
    char *getmemory(void)
    {
        char *p=NULL;
        if(NULL !=(p=(char *)malloc(strlen("hello word")+1))
           return p;
    }

    /*

     但是这样返回的的指针是游离的, 没有任何意义

    */
     

    试题6:

    void GetMemory( char **p, int num )
    {
     *p = (char *) malloc( num );
    }

    void Test( void )
    {
     char *str = NULL;
     GetMemory( &str, 100 );
     strcpy( str, "hello" );
     printf( str );
    }
    /*
       这个题目在第四个题目已经实现和论述,不再论述
     指的一提的是:
         传递&str值,并不能改变str的指向。
    */

    试题7:

    void Test( void )
    {
     char *str = (char *) malloc( 100 );
     strcpy( str, "hello" );
     free( str );
     ... //省略的其它语句
    }
    /*
       这个题目比上面的更加简单, 它的问题就是没有对malloc函数的返回情况进行
       检测,
       如果 NULL=(char *)malloc(NUM) 那么strcpy函数将不会成功执行,
      
    */

  • 相关阅读:
    [导入]起点
    docker 07 多容器应用程序
    Docker WARNING: Ignoring https://dlcdn.alpinelinux.org/alpine/v3.15/main: temporary error (try again later)
    Docker 06 持久化到主机本地系统。也就是常说的挂载
    小程序开发,不支持打开非业务域名,请重新配置。
    Docker 01 安装DockerEngine和Docker Cli
    Docker 02 Docker基本概念
    Docker 04 构建并运行基础镜像
    win10使用scp命令通过密钥rsa进行传输的bad Permissions的解决方案:WARNING: UNPROTECTED PRIVATE KEY FILE!
    Docker 05 构建镜像发送到中央仓库
  • 原文地址:https://www.cnblogs.com/volcanol/p/2109982.html
Copyright © 2020-2023  润新知