C语言,C++练习笔记

函数调用:返回值存在寄存器中,没有地址,不能作为形参,但可以作为实参。
一个函数没有返回值时,是void型,此时的void关键字不能省略(不写);
一个函数省略(不写)返回值类型时,默认是int型;

int main() {
int a[3][3], *p, i;
p = &a[0][0];
for(i = 0; i < 9; i++) p[i] = i;
for(i = 0; i < 3; i++) printf("%d ", a[1][i]);
}
指针的步长与指针的类型相关,由于p为int型指针,故p+i表示跳过i个int长度;p指向二维数组的首元素地址

strlen 是函数,sizeof 是运算符。
strlen 测量的是字符的实际长度,以’\0’ 结束,也就是说不算最后的’\0’;
而sizeof 测量的是字符的分配大小,包括最后的’\0’;

C语言里i=5,j=7,请问i|j等于多少?
| 是位操作符 或 的意思
先把5和7转化为二进制 101 和 111
按位或就是 111 ,所以答案是7

抽象类的规定
(1)抽象类只能用作其他类的基类,不能建立抽象类对象。
(2)抽象类不能用作参数类型、函数返回类型或显式转换的类型。
(3)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。

常量的定义必须被初始化
静态局部变量相当于全局变量(只是只有在这个函数中能访问,但是生命周期是和全局变量差不多的),函数退出之后变量还在,而且只在第一次进入的时候做初始化,以后会跳过初始化语句,保留原来的值(也就是说,如果a是static的,那么只有在第一次进入这个函数的时候会执行a=2,以后都不会执行。)。

无符号号整数和有符号整数相加,有符号整数转化为无符号整数,signed int b 变成了一个很大的数。

结构体变量不管其包含有多少个成员,都应当看成是一个整体。在程序运行
期间,只要在变量的生存期内,所有成员一直驻留在内存中,不可能出现有的成员驻留内
存,有的成员不驻留内存的情况

斐波那契数列:
当n=6时,下列函数的返回值是()
1
2
3
4
5
int foo(int n){
if(n < 2)
return n;
return foo(n-1)+foo(n-2);
}

int *p[4]; //指针数组。 是个有4个元素的数组, 每个元素的是指向整型的指针 。(数组的每个元素都是指针)
int (*p)[4]; //数组指针。 它是一个指针,指向有4个整型元素的数组。 (一个指针指向有4个整型元素的数组)
int func(void); //指针函数。 无参函数, 返回整型指针。            (函数的返回值为int)
int (*func)(void); //表示函数指针,可以指向无参, 且返回值为整型指针的函数。 (函数的返回值为int)

引用是变量的别名,指针值变量的地址,通过改变所指向的地址的值来改变变量的值,属于间接操作。
引用是别名,不占内存空间,指针的变量的地址,存储指针要占一定的内存空间,所以引用更节省内存空间

常量的作用域可以是整个工程,而静态全局变量的作用域只能在其定义的源文件

char类型有符号,所以-1可以表示,uchar类型无符号(范围是0-255),-1是1000 0001,转换成补码是1111 1111,uchar无符号位,所以最高位的1也计算到值里,为1+2+4+…+128=255

MyClass c1,*c2;
MyClass *c3=new MyClass;
MyClass &c4=c1;
只有c1和c3会调用构造函数。
c2只是一个指针,用来动态描述对象的,不需要类的定义。
c4只是一个c1的别名,说白了c4就是c1 不占空间

(1)重载,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相 称之为重载函数或者方法。
(2)c++中不释放空间会造成内存泄漏,析构函数就是用来执行这一任务的
(3)析构函数没有返回值,也没有参数,没有函数类型,因此不能被重载
(4)因为子类的析构需求不一致,用统一的父类析构函数可能造成析构不完全,因此一般设置父类析构函数为虚函数,然后在子类中具体实现。在父类指针下,根据对象所属子类动态地加载子类析构函数
(5)虚函数可以进行重载

函数模板的实例化是由编译程序处理函数调用时自动完成的;类模板的实例化是由程序员在程序中显式的指定;函数模板针对参数类型不同和返回值类型不同的函数;类模板针对数据成员、成员函数和继承的基类类型不同的类。

静态数据成员则独立于该类的任何对象,在所有对象之外,单独开辟空间存储。在为对象所分配的空间中不包含静态成员所占的空间。

如果基类没有默认构造函数,派生类中的构造函数必须显式地调用基类的带参构造函数

析构函数不能够被继承,但是虚函数不仅能够被派生类继承,还能够被派生类改写

为什么自己实现拷贝构造函数和运算符重载?
当让系统默认生成时默认的是浅拷贝,当拷贝的变量中有指针时我们要实现深拷贝。因为浅拷贝是直接将指针指向原有的堆上,当程序执行完毕之后,需要将资源释放,这样会导致一个内存地址释放两次,出现错误,深拷贝则是给指针重新分配内存空间,在释放时就会各自释放各自的,不会出现错误。

this 指针:保存的是当前对象的地址,对应的对像的方法形参都会多一个相应类型的this指针,传参是将对象的地址传递给this。

为什么需要初始化列表?语义:定义并初始化 初始化列表的效率比在内部初始化效率高。
处理一些特殊的成员属性: 引用: 定义必须初始化。 const修饰的成员:定义必须初始化。 成员对象:(无默认构造函数)实例化对象时会自动调用构造函数(定义并初始化),继承中派生类初始化列表中初始化基类。

const修饰普通变量,C中是只读变量, C++是常量;
C++中const修饰成员函数是在最后加上 表示只可以访问不可以修改。想要修改成员变量时,要加mutable修饰成员;
const修饰的对象称之为常对象,只能调用它的const成员

类默认合成那些函数:默认构造函数,默认拷贝构造函数,默认析构函数,默认赋值运算符,取址运算符,取值运算符,默认移动构造函数,默认移动赋值运算符。

想知道类成员变量和函数的地址
int Test::*p = &Test::num;
int (Test::*p_func)() = &Test::func;
在后面的线程用到

运算符重载的作用:提高程序的可读性。(运算符比函数名更加有自注释性);
什么是重载,让相应的类型支持相应的运算符。

运算符重载实现:成员函数重载和友元函数重载
运算符重载规则:
运算符重载不允许发明新的运算符。
不能改变运算符操作对象的个数
运算符重载后,其优先级和结合性不会改变

不能重载的运算符 :: :? . .* sizeof 五个

成员函数重载和友元函数重载的选择:
一般情况下单目运算符最好用类的成员函数; 双目运算符则最好重载为类的友元函数。
以下一些双目运算符不能重载为类的友元函数: = () [] ->;
类型转换运算符只能以成员函数方式重载 static const
流运算符只能以友元的方式重载 << >>

Q1:必须要使用引用吗?
R1:不是必须使用

Q2:引用和值传递的使用场景区别?
R2:值传递的方式无法在链式编程的时候使用,因为值传递返回的不是本体,而引用返回的是本体,
最本质的一句话就是我们需要使用函数返回本体,先有需要,我们才使用引用,而不是现有引用,我们才有需求。
引用什么情况都可以使用,用了绝对不错,但是值传递却不行,总的来说引用的使用范围最大,建议使用引用。

Q3:那什么时候使用引用,什么时候简单的值传递返回就行
R3:这个取决于我们的运算符的使用场景。根据总结,只有加减乘除的时候两者均可,但是涉及到链式编程的时候只能使用引用返回。

代码复用的方法;组合和继承,组合缺点:如果组合多了,那么类就过于庞大,占用内存空间。

解决二义性,用作用域限定符,虚继承专门解决二义性

struct 的成员默认是公有的
class 的成员默认是私有的
class继承默认是私有继承
struct 的继承默认是公有的

友元函数有对象做参数时,可以在类内部定义函数体,没有对象做参数时,必须在类外定义函数体。

0x开头为16进制,0xf对应的二进制数为1111。
^为异或操作,若参加运算的两个二进制位值相同则为0,否则为1;
a与0xf做异或操作,可以实现低四位的翻转。
如果是| 按位或 ,则将低四位数全变成1.
如果是& 按位与,则结果不变。

其他的位运算符号:
& 按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
| 按位或 两个相应的二进制位中只要有一个为1,该位的结果值为1
^ 按位异或 若参加运算的两个二进制位值相同则为0,否则为1
~ 取反 ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0
<< 左移 用来将一个数的各二进制位全部左移N位,右补0

右移 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0

猜你喜欢

转载自blog.csdn.net/weixin_43296982/article/details/124115399