• sizeof与strlen()、递归优化题解


    一、sizeof

    sizeof是C/C++中的一个操作符(operator),确切的说是一个编译时运算符,参数可以是数组、指针、类型、对象、函数等。用于统计类型或者变量所占的内存字节数。由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。

    二、strlen()

    是C标准库中的字符串函数,要在运行时才能计算。参数必须是字符型指针(char*), 且必须是以''结尾的。它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符''。返回的长度大小不包括''。

    三、实例

    1、char *str = "hello";

       strlen(str); //它的值是5,因为hello这个字符串有5个字符

       sizeof(str); //它的值是4,因为char *是一个指针类型,它占4个字节。

      sizeof("hello"); //它的值是5,是因为hello有5个字符,每一个字符占1个字节。

    2、int a[2] = {0};

      sizeof(a); //它的值是8,因为a中有2个int型变量,每个int型占4个字节,所以8字节
      strlen(a) //a相当于一个指针,但是strlen只能接受char*类型,所以编译时出错

    3、char arr[10] = "Hello";

     int len_one = strlen(arr);
     int len_two = sizeof(arr); 
     cout << len_one << " and " << len_two << endl; 
        输出结果为:5 and 10
     strlen只关心存储的数据内容,不关心空间的大小和类型。    

      sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据(10x1)。    
       4、char * parr = new char[10];
                  int len_one = strlen(parr);
                  int len_two = sizeof(parr);
                  int len_three = sizeof(*parr);
                  cout << len_one << " and " << len_two << " and " << len_three << endl;
        输出结果:3 and 4 and 1
          第一个输出结果3实际上每次运行可能不一样,这取决于parr里面存了什么(从parr[0]开始直到遇到第一个''结束);
          第二个结果实际上本意是想计算parr所指向的动态内存空间的大小,但是事与愿违,sizeof认为parr是个字符指针,因此返回的是该指针所占的空间(指针的存储用的是长整型,所以为4)

         第三个结果,由于*parr所代表的是parr所指的地址空间存放的字符,所以长度为1。

     

    面试题:定义一个空的数据类型,里面没有任何成员变量和成员函数,对该类型求sizeof,得到的结果是多少?

    答案:是1,为什么不是0?空类型的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例时,它必须在内存中占有一定的空间,否则无法使用这些实例(也就不能求sizeof了),至于占用多少内存,由编译器决定,Visual Studio中每个空类型的实例占用1字节的空间。

    扩展1:如果在该类型中添加一个构造函数和析构函数,再求sizeof,得到的结果是多少?

    答案:还是1。调用构造函数和析构函数只需要知道函数的地址即可,而这些地址只与类型相关,而与类型的实例无关,编译器也不会因为这两个函数而在实例内添加任何额外的信息。

    注:不管添加的是构造函数还是析构函数还是其它任何类型的函数,都是这个结果。

     

    扩展2:那如果把析构函数标记为虚函数呢?

    答案:C++的编译器一旦发现一个类型中有虚函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针,在32位机器上,一个指针占4字节空间,因此求sizeof得到4;如果是64位则为8。

    测试用例:

    #include <stdio.h>
    
    struct nullType { };
    
    struct type1
    
    {
    
           type1() {}
    
           ~type1() {}
    
           int print() { printf("Alexia"); return 0; }
    
    };
    
    
    struct type2
    
    {
    
           type2() {}
    
           virtual ~type2() {}
    
    };
    
    
    int main()
    
    {
    
           printf("sizeof(nullType) = %d
    ", sizeof(nullType));
    
           printf("sizeof(type1) = %d
    ", sizeof(type1));
    
           printf("sizeof(type2) = %d
    ", sizeof(type2));
    
           return 0;
    
    }

    代码的优化,给出下一段代码,请做出最好的优化

    int f(int n) {
        if(n<=4)
            return n*n;
        else {
            return f(n-4)*f(n-1) -f(n-2)*f(n-2);
        }
    }

    解答

    无非是将递归转化为循环,防止重复计算中间值,跟斐波那契数列f(n)=f(n-1)+f(n-2)一样,解决方式也一样,就是利用几个临时变量保存中间值,然后每次循环都更新临时变量即可。过程没啥好说的,直接给出代码即可。

    int f2(int n) {
        int first = 1;
        int second = 4;
        int third = 9;
        int fourth = 16;
        if(n<=4)
            return n*n;
        for(int i = 5; i <= n; ++i) {
            int tmp = fourth * first - third * third;
            first = second;
            second = third;
            third = fourth;
            fourth = tmp;
        }
        return fourth;
    }
  • 相关阅读:
    Numpy随机数组的创建
    python map()
    LeetCode回溯系列(1)——第17题解法
    LeetCode回溯系列(0)——回溯算法讲解
    LeetCode位操作系列(1)——位操作在第190题中的运用
    LeetCode位操作系列(0)——位操作奇技淫巧之原理加实践
    python PIL 图像处理库简介
    plt.plot()的使用方法以及参数介绍
    关于.split()和os.sep的联合应用
    【mac清理】慎用CleanMyMac X
  • 原文地址:https://www.cnblogs.com/peterYong/p/6556734.html
Copyright © 2020-2023  润新知