基于TCP的应用层协议有:POP3、SMTP(简单邮件传输协议)、TELNET(远程登陆协议)、HTTP(超文本传输协议)、HTTPS(超文本传输安全协议)、FTP(文件传输协议)
基于UDP的应用层协议:TFTP(简单文件传输协议)、RIP(路由信息协议)、DHCP(动态主机设置协议)、BOOTP(引导程序协议,DHCP的前身)、IGMP(Internet组管理协议)
基于TCP和UDP协议:DNS(域名系统)、ECHO(回绕协议)
int(*n)[10]; 是数组指针 sizeof(n)=4
int* n[10]; 是指针数组 sizeof(n)=40
注:看n和什么结合。
指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针
数组指针:a pointer to an array,即指向数组的指针
还要注意的是他们用法的区别,下面举例说明。
int* a[4] 指针数组
表示:数组a中的元素都为int型指针
元素表示:a[i] *(a[i])是一样的,因为[]优先级高于
int (*a)[4] 数组指针
表示:指向数组a的指针
元素表示:(*a)[i]
new/delete、new[]/delete[] 要配套使用
malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作
二维数组:如果是定义就必须知道维度,如果不写维度,可以不写第一个维度,但是不能省略第二个维度,但必须初始化。
1 | struct Date |
在64位系统上,如果Data的地址是x,那么data[1][5].c的地址是(X+365)
1、结构体的内存大小应该是结构中成员类型最大的整数倍,此处最大的类型是int_64t,占8个字节。。即最后所占字节的总数应该是8的倍数,不足的补足;
b.数据对齐原则-内存按结构体成员的先后顺序排列,当排到该成员变量时,其前面所有成员已经占用的空间大小必须是该成员类型大小的整数倍,如果不够,则前面的成员占用的空间要补齐,使之成为当前成员类型的整数倍。假设是地址是从0开始,结构体中第一个成员类型char型占一个字节,则内存地址0-1,第二个成员从2开始,int型所占内存4个字节,根据原则b,第一个成员所占内存补齐4的倍数,故第一个成员所占内存:1 + 3 = 4; 第二个成员占5-8. 第三个成员占8个字节,满足原则b,不需要补齐,占9-16. 第四个成员占一个字节,占17. 故总内存为1 + 3 + 4 + 8 + 1 = 17个字节,但根据原则a,总字节数需是8的倍数,需将17补齐到24. 故此结构体总字节数为:24字节
2、计算
data [1] [5],意思是前面有15个元素。则第15个元素的起始地址为: 24 * 15 = 360, 即 X + 360
则data[1] [5].c的地址为: 360 + 1 + 3 + 4 = 368,即 X + 368
除了类属关系运算符”.”、成员指针运算符”.*“、作用域运算符”::”、sizeof运算符和三目运算符”?:”以外,C++中的所有运算符都可以重载
但是=、()、[]、->这四个不能重载为类的友元函数。 即:=(赋值),[],(),->(指向并访问)只能通过成员函数来重载(4个);
若int 占 2 个字节, char 占 1 个字节, float 占 4 个字节, sizeof(xc) 大小是:
1 | struct stu |
结构体中每一个成员的起始地址要是 该成员大小的整数倍。 所以,这题不是8+8+4 ,而是( ((5+1)+ 8) + 2) + 4
union 中有两个数据类型char和int, int 占两个字节,较大,因此union对齐应该是2的倍数,而union内部中char有5个元素,因此占用5个字节,要对齐为此占用6个字节;接下来是char元素8个,占用8个字节,加上前面的6个字节共14个字节;接下来float存储的时候,float占4个字节为此需要以4个字节对齐,现在的位置是14,不满足4的倍数,为此float从16开始,然后占用4个字节,共20个字节
sizeof是操作符,在编译阶段就获得结果,strlen是函数调用,在运行阶段才获得值。
sizeof(float)返回值是一个整型,在编译阶段就被整型替代了,所以这是一个整型表达式。
switch后面的“表达式”,可以是int、char和枚举型中的一种,不能是float型变量
1 | &a+i = a + i*sizeof(a); |
1.mutable定义可变成员对象(即使在带有const的成员函数中也可改变成员对象的值)
2.c++中类的成员函数都有隐含的this指针,普通的非const成员函数中,this是一个指向类类型的const指针,可改变this所指向的值,但不可以改变this所保存的地址;在const成员函数中,不可改变this所指向的值,也不可改变this保存的地址。
1 | char *p1 = ”123”, *p2 = ”ABC”, str[50] = “xyz”; |
原代码有错:p1和p2都指向常量字符串,在常量区,所以不能对其进行操作;改为数组即可,但是用字符串初始化数组时要记得将数组长度加1,因为字符串默认的末尾有一个‘\0’;第二点要注意的是,strcat函数的p1要有足够的空间来容纳p1和p2连接后的串长。
修改为以下代码将可以:
1 | char p1[7] = "123"; |
结果:xy123ABC
数组名为char * const,不能对地址赋值,可以对该地址指向的数据赋值(数组名是个固定地址,不能直接赋值)
数组名str1为 char *const类型的右值类型,根本不能赋值。 再者,即使想对数组的第一个元素赋值,也要使用 *str1 = ‘a’;
strlen不统计’\0’所占用的1个字节
断言可以有两种形式
1.assert Expression1
2.assert Expression1:Expression2
其中Expression1应该总是一个布尔值,Expression2是断言失败时输出的失败消息的字符串。
1 | char *GetMemory(void) |
char p[]=”hello world”;相当于char p[12],strcpy(p,” hello world” ).p是一个数组名,属于局部变量,存储在栈中, “ hello world” 存储在文字存储区,数组p中存储的是 “ hello world” 的一个副本,当函数结束,p被回收,副本也消失了(确切的说p指向的栈存储区被取消标记,可能随时被系统修改),而函数返回的p指向的内容也变得不确定,文字存储区的 “ hello world” 未改变。可以这样修改: ①char* p= “ hello world” ; return p; 这里p直接指向文字存储区的 “ hello world” ,函数按值返回p存储的地址,所以有效。 ②static char p[]= “ hello world” ; return p; static指出数组p为静态数组,函数结束也不会释放,所以有效。
float保留小数点后6位,double保留小数点后14位
1 | #ifndef __INCvxWorksh |
为什么标准头文件都有类似以下的结构?
头文件中的编译宏的作用是防止被重复引用。
1 | #ifndef __INCvxWorksh |
作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在symbol库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo(int x, int y);
该函数被C编译器编译后在symbol库中的名字为foo,而C++编译器则会产生像_foo_int_int之类的名字。_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern “C”来解决名字匹配问题,函数声明前加上extern “C”后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。