C++之引用、运算符、随机发生器(四)

关于逻辑运算符 && ,|| 的巧用方式

逻辑与 &&

  • && 会先判断左边的值是否为真。
  • 如果为假,那么整个表达式毫无疑问也为假。
  • 如果为真,那就还需要判断右值,才能知道整个式子的值。
    这个时候判断右值的过程就起了一个if的作用,可以利用这个过程判断右边表达式是否为真。
    下面代码:

    /*不用任何循环语句,不用if,来实现1+2+3+...+10的值*/
    #include <iostream>
    using namespace std;
    
    int add(int c)
    {
        int a=0;
        c&&(a=add(c-1));//递归循环,直到传入c的值为0则结束循环
        cout<<c+a<<endl;
        return c+a;
    }
    int main()
    { 
        add(10);
        return 0;
    }
    

逻辑或 ||

其实与上面的逻辑与 && 大同小异。
– 先判断左边是否为真,再来考虑右边。
– 因为逻辑与 || 只需要左边为真,那么整个表达式就有值,就不会再去算右边的值了。
– 我们加个 ! 让 c 值为假时,!c 才为真,这样的话逻辑与 || 还需要判断右边的表达式才能计算出整个表达式的值。

srand函数是随机数发生器的初始化函数。

原型: void srand(unsigned seed);
用法:它需要提供一个种子,这个种子会对应一个随机数,如果使用相同的种子后面的rand()函数会出现一样的随机数。如: srand(1); 直接使用 1 来初始化种子。不过为了防止随机数每次重复,常常使用系统时间来初始化,即使用 time 函数来获得系统时间,它的返回值为从 00:00:00 GMT, January 1, 1970 到现在所持续的秒数,然后将 time_t 型数据转化为(unsigned)型再传给 srand 函数,即: srand((unsigned) time(&t)); 还有一个经常用法,不需要定义time_t型t变量,即: srand((unsigned) time(NULL)); 直接传入一个空指针,因为你的程序中往往并不需要经过参数获得的t数据。

#include <stdlib.h>
#include <stdio.h>
#include <time.h> /*用到了time函数,所以要有这个头文件*/
#define MAX 10

int main( void)
{
    int number[MAX] = {0};
    int i;
    srand((unsigned) time(NULL)); /*播种子*/
    for(i = 0; i < MAX; i++)
    {
        number[i] = rand() % 100; /*产生100以内的随机整数*/
        printf("%d ", number[i]);
    }
    printf("\n");
    return 0;
}

sizeof 和strlen区别

char str[20]="0123456789";
int a=strlen(str);         // a=10; >>>> strlen 计算**字符串的长度**,以结束符 0x00 为字符串结束。
int b=sizeof(str);         // 而 b=20; >>>> sizeof 计算的则是分配的数组 str[20] 所占的**内存空间的大小**,不受里面存储的内容改变。  

上面是对静态数组处理的结果,如果是对指针,结果就不一样了。

char* ss = "0123456789";
sizeof(ss) 结果 4 ===》ss 是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是长整型的,所以是 4。
sizeof(*ss) 结果 1 ===》*ss 是第一个字符 其实就是获得了字符串的第一位 '0' 所占的内存空间,是 char 类型的,占了 1 位
strlen(ss)= 10      ===》 如果要获得这个字符串的长度,则一定要使用 strlen。

strlen 用来求字符串的长度;而 sizeof 是用来求指定变量或者变量类型等所占内存大小。

把指针运算符 * 应用到 var 数组上是完全可以的,但修改 var 数组的值是非法的。这是因为 var数组 是一个指向数组开头的常量,不能作为左值。
由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。

#include <iostream>
using namespace std;

int main ()
{
    int var[3] = {10,100,200};
    int *p=var;
    for (int i = 0; i < 3; i++)
    {
        cout << *(var++) << endl;    //编译错误,因为var是数组名(也是数组首元素地址),不是一个变量,不可修改其值
        cout << *(var+i) << endl; //编译正确,因为没有对var进行赋值,只是通过与i相加访问变量地址
        cout<<  *(p++)<<endl;        ///编译正确,p为指针变量可赋值
    }
    return 0;
}

C++引用

  • 以引用返回函数值,定义函数时需要在函数名前加 &
  • 用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
  • 引用作为返回值,必须遵守以下规则:
  • 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁(局部变量保存在栈),因此被返回的引用就成为了”无所指”的引用,程序会进入未知状态。
  • 不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
  • 可以返回类成员的引用,但最好是const。引用回改变原始数据,主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
  • 使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

C++为什么要增加引用类型

C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能。
C++ 函数传参:
– (1)将变量名作为实参和形参。这时传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。// 同 c
– (2) 传递变量的指针。形参是指针变量,实参是一个变量的地址,调用函数时,形参(指针变量)指向实参变量单元。这种通过形参指针可以改变实参的值。// 同 c
– (3) C++提供了 传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。
形参、实参
1. 比如你定义一个函数void add(int a, int b),这里的a和b就是形参。
2. 当你进行函数调用的时候,add(1, 2),这里的1和2就是实参。

C++ 之const char*

how to justify what the const points to is constant?

the syntax isn’t as complicated as it may seen,there is a rule ,if the word appears to the left of the * , what’s pointed to is constant,if the word appears to the right of the *,the pointer itself is constant;if const appears to both sides ,both are constant.

C++之enum、typedef

enum 枚举

下面的代码定义了一个颜色枚举,变量 c 的类型为 color。最后,c 被赋值为 “blue”。

enum color{red,black,green,blue} c;
c=blue

默认情况下,枚举类型开始第一个名称值为0,后面依次加1;上面代码c为 3 。
下面枚举中赋值green为 5

enum color{red,black,green=5,blue} c;
c=blue

那么,blue的值为 6。

Continue reading “C++之enum、typedef”