C++知识点整理

1:函数中参数缺省问题
函数声明部分:

void mytest(std::string &hash, float &Deviation, std::vector<std::string> reference=std::vector<std::string> ());

注意在定义部分是没有给缺省值!
函数定义部分:

mytest(std::string &hash, float &Deviation, std::vector<std::string> reference)
{

}

注意:
vector的初始化方式有以下几种,所以初始化的右值可以多种方式:

vector<string> svec(10);    // 10个元素,每个都是空string对象 
/vector<string> svec(10, "hi!");

在函数缺省参数的使用时候上述两种是可用的,而下述两种是不可用的(但是这两种也是vector的初始化方法)。

ector<string> articles = {"a", "an", "the"}; 
vector<string> v1{"a", "an", "the"}; // 列表初始化

2:类中成员不能是该类的对象作为成员
从对象构造函数的角度来说:
因为如果类包含自身类的对象,存在无限初始化的问题。
构造一个类的对象是,先构造成员变量,然后再调用自身的构造函数,如果类包含自身的的对象,那么在调用构造函数之前,需要先构造自身类的对象。而构造自身类的对象时,又得先构造自身的对象,然后调用其构造函数。。。。这样便会无限循环。
从实例化对象分配空间来说:
当用实例化一个类的对象时,编译器会根据类的定义来分配相应的存储空间。也就是说,在创建对象前,一定要有完整的类定义,这样编译器才能正确的计算所需空间。
如果是下面的代码:

class Screen{
    Screen sc;    //error, 'sc' uses undefined class 'Screen'
    //etc...
};

上述代码中,由于Screen还没有定义结束,在内部定义一个Screen类型的对象时,编译器无法知道应该为sc分配多少空间,因此会报注释中的错误。
但是可以,在类定义时,指向自身类型的指针或引用作为数据成员则没有问题。这是因为指针和引用所占存储空间大小与类型无关,所以编译器可以计算分配空间。

class Screen{
    Screen *sc1;   //ok
    Screen &sc2;   //ok
};

3:多维数组的访问和赋值问题

    char b[2][3][3]={'1','2','a','b','c','d','e','f','g','h','i','k','L','M','N'};
    char (*p)[3][3] = b;
    char (*r)[3] = b[0];
    char *t = b[0][0];
    char u = b[0][2][2];
    // printf("%x\n",p);
    std::cout<<*p<<"\t"<<p<<"\t"<<b<<std::endl;//都是数组名
    std::cout<<*r<<"\t"<<*t<<std::endl;
    std::cout<<u<<"\t"<<&u<<std::endl;

4:检测系统中浮点数0.0的位模式是否与整型数0的位模式相同

printf("sizeof double is:%d\n",sizeof(double));
    printf("sizeof int    is:%d\n",sizeof( int ));

    double d0=0.0;
    int    i0[2]={0,0};

    if(*(double*)i0==d0){
        puts("is the same!");
    }
    else {
        puts("not the same!");
    }

从结果看出,是相同的。
5:数组参数的地址和数组参数的第一个元素的地址不同

void fun1(char ca[])
{
    printf("char ca:\n");
    printf("%x\n", &ca);
    printf("%x\n", &(ca[0]));
    printf("%x\n", &(ca[1]));
}

void fun2(char* pa)
{
    printf("char* pa:\n");
    printf("%x\n", &pa);//printf("%#x\n", &pa);打印的方式不同而已,多一个0X
    printf("%x\n", &(pa[0]));
    printf("%x\n", &(pa[1]));
    printf("%x\n", ++pa);
}
void main()
{
    char test[] = "helloworld";
    fun1(test);
    fun2(test);
    printf("test:\n");
    printf("%x\n", &test);
    printf("%x\n", &(test[0]));
    printf("%x\n", &(test[1]));
}

这里写图片描述
从上述的运行结果,发现数组参数的地址和数组参数的第一个元素的地址不一样,这是为什么呢?
这是因为在fun1()的第二行,打印的内容为”&ca“,而&ca的实际意义为ca的地址,即指向ca的指针。在函数内部,ca本身就是一个指向数组第一个元素的指针,无需取ca的地址,直接打印ca的值即可,取得ca的地址,实际上是该指针的地址。将第二行的语句替换为:printf(“%x\n”, ca)即可。

6:数组指针和指针数组的区别
1)数组指针(也称行指针)
定义 int (*p)[n];
括号()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
如要将二维数组赋给一指针,应这样赋值:

    int a[3][4]={1,2,3,4,5,6,7,8,9,10,11};
    int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
    p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
    std::cout<<*p<<"\t"<<&a<<"\t"<<p[0][2]<<std::endl;
    p++;//该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
    std::cout<<*p<<"\t"<<&a<<"\t"<<p[0][2]<<std::endl;

这里写图片描述
所以数组指针也称指向一维数组的指针,亦称行指针。

2)指针数组
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:

int *p[3];
int a[3][4];
for(i=0;i<3;i++)
    p[i]=a[i];

这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:

*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

例如:

std::cout<<*(p[0]+2)<<"\t"<<*(*(p+0)+2)<<"\t"<<(*(p+0))[2]<<"\t"<<p[0][2]<<std::endl;

都是输出数字7,都是表示p[0][2]
这里写图片描述
ps:
优先级:()>[]>*

7:

8:

【待补充】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值